Ubuntu – Error: object “ip” is unknown , try “ip help”

executablefilenameipscripts

I am trying to run trusted executables through a script.

I copied the binary executable /bin/ip to a directory called Tools.

I renamed the binary to eip.

I have navigated to the directory tools and tried to run the executable eip.

# ./eip addr list

It throws an error: object "ip" is unknown , try "ip help."

How to deal with this?

Best Answer

If you keep your local ip executable called ip, and not something longer, you can avoid this particular problem. If you rename it to some other one or two character long name, that will also work fine--the problem only happens if its name is three or more characters in length. This may seem strange... so read on for details...

When I run a copy of /bin/ip called eip, I get an error message with p (rather than ip) as the unknown object:

Object "p" is unknown, try "ip help".

I'm wondering if the same is happening to you? (Could there be a typo in your question?) Even if not, I strongly suspect the behavior on your machine is related to what I am seeing.

I found that when I renamed ip to anything longer than two characters, it gave me an "unknown object" error about the rest of the characters:

ek@Io:~$ cp /bin/ip abc
ek@Io:~$ ./abc
Object "c" is unknown, try "ip help".
ek@Io:~$ mv abc foobar
ek@Io:~$ ./foobar
Object "obar" is unknown, try "ip help".
ek@Io:~$ mv foobar 12345
ek@Io:~$ ./12345
Object "345" is unknown, try "ip help".

man ip didn't seem to explain this odd behavior, but I did notice that the first non-option argument to ip is technically called an object:

SYNOPSIS
       ip [ OPTIONS ] OBJECT { COMMAND | help }

       ip [ -force ] -batch filename

       OBJECT := { link | addr | addrlabel | route | rule | neigh | ntable |
               tunnel | tuntap | maddr | mroute | mrule | monitor | xfrm |
               netns | l2tp | tcp_metrics }

....

So I tried changing the characters, after the first two, to these object names:

ek@Io:~$ mv 12345 12addr
ek@Io:~$ ./12addr
1: lo:  mtu 65536 qdisc noqueue state UNKNOWN group default 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
....
ek@Io:~$ mv 12addr XXrule
ek@Io:~$ ./XXrule 
0:  from all lookup local 
32766:  from all lookup main 
32767:  from all lookup default
ek@Io:~$ mv XXrule ipl2tp
ek@Io:~$ ./ipl2tp 
Usage: ip l2tp add tunnel
          remote ADDR local ADDR
....

So it appears ip is designed to check the name with which it has been invoked, and if it contains more than two characters, to interpret the remaining characters as the name of the object on which to operate. Probably this is so that copies and symbolic links of ip with names like iplink, ipaddr, ipaddrlabel, and so forth, can act as if ip link, ip addr, ip addrlabel, and so on correspondingly were run.

To double check this, I took at look at the source code. The iproute2 package provides /bin/ip, so I searched for that and found it to be provided by the source package of the same name. (This is often but not always the case.) In the code tab, I selected a branch and browsed the code, entering the ip directory and examining ip.c.

I looked in the main function, since that's where most C programs start running. This is the function that begins:

int main(int argc, char **argv)
{

Like many programs' main functions, it consists largely of processing for command-line options. But below that, there's code to handle the various ways ip may be run, and one of them is for when its name is more than two characters long:

if (strlen(basename) > 2)
        return do_cmd(basename+2, argc, argv);

Cool! (Kinda weird--but cool.)


The simplest and best solution is probably just to keep your copy of ip called ip, or some other one- or two-character name. Giving it the same name as the copy of ip in /bin (and pointed to by the /sbin/ip symlink) should not be a problem--your script is already providing a path to the specific executable you wish to run.

However, you might want it to be possible for users to invoke your copy of ip with a command like eip--for example, so they can have a separate command to put in directories in their PATH. This is commonly achieved with a symbolic link, but that will fail here for the same reason calling the copy eip failed in the first place:

ek@Io:~$ ln -s /bin/ip eip
ek@Io:~$ ./eip
Object "p" is unknown, try "ip help".

(I made a symbolic link to my system's /bin/ip, but the same happens when you symlink to a separate copy.)

The solution is to write a wrapper script (named eip, or whatever you like) that invokes ip, passing its arguments along. The script file can look like this:

#!/bin/sh
/path/to/your/ip "$@"