Background
If you’ve ever gone poking around in your Linux system’s /sbin
directory the site of files like this might make you scratch your head.
1 2 3 4 5 6 7 8 |
lrwxrwxrwx 1 root root 3 Jun 7 2011 vgmerge -> lvm lrwxrwxrwx 1 root root 3 Jun 7 2011 vgmknodes -> lvm lrwxrwxrwx 1 root root 3 Jun 7 2011 vgreduce -> lvm lrwxrwxrwx 1 root root 3 Jun 7 2011 vgremove -> lvm lrwxrwxrwx 1 root root 3 Jun 7 2011 vgrename -> lvm lrwxrwxrwx 1 root root 3 Jun 7 2011 vgs -> lvm lrwxrwxrwx 1 root root 3 Jun 7 2011 vgscan -> lvm lrwxrwxrwx 1 root root 3 Jun 7 2011 vgsplit -> lvm |
We’ll read on and I’ll explain how all these seemingly regular tools are actually just one.
So What’s going on?
Many programs make use of this technique where there is a single executable that changes it’s behavior based on how it was executed.
There’s typically a structure inside the program called a case/switch statement that determines the name the executable was called with and then will call the appropriate functionality for that executable name. That name is usually the first argument the program receives. For example, in the C programming language when you write:
1 |
int main(char** argv, int argc) |
argv[0]
contains the name of the called executable. At least, this is the standard behavior for all shells, and all executables that use arguments should be aware of it.
Example in Perl
Here’s a contrived example I put together in Perl which shows the technique as well.
Here’s the actual script, call it mycmd.pl
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#!/usr/bin/perl use feature ':5.10'; (my $arg = $0) =~ s#./##; my $msg = "I was called as: "; given ($arg) { $msg .= $arg when 'ls'; $msg .= $arg when 'find'; $msg .= $arg when 'pwd'; default { $msg = "Error: I don't know who I am 8-)"; } } say $msg; exit 0; |
Here’s the file system setup:
1 2 3 4 5 6 |
$ ls -l total 4 lrwxrwxrwx 1 saml saml 8 May 24 20:49 find -> mycmd.pl lrwxrwxrwx 1 saml saml 8 May 24 20:34 ls -> mycmd.pl -rwxrwxr-x 1 saml saml 275 May 24 20:49 mycmd.pl lrwxrwxrwx 1 saml saml 8 May 24 20:49 pwd -> mycmd.pl |
Now when I run my commands:
1 2 3 4 5 6 7 8 9 10 11 |
$ ./find I was called as: find $ ./ls I was called as: ls $ ./pwd I was called as: pwd $ ./mycmd.pl Error: I don't know who I am 😎 |