This was a comment on Slashdot on the article Linux Foundation Promises LSB4 and its very informative. Btw I dont care about the news.

Env followed by the name of a binary, will exec the first binary with that name on the current path. It boils down to how you run a script on UNIX. There are two ways:

The first way is with a command like ’sh foo.sh’. sh will then read foo.sh and execute each command in it in order (if it’s not a shell script, it will hopefully read the magic number and run it).

The second way is to just exec() it. The loader then reads the first few bytes of the file. This tells it what type of file it is. For ELF files, they will be “.ELF”. For Mach-O binaries, they will be 0xFEEDFACE or 0xCAFEBABE, depending on the architecture. For scripts the first two bytes will be “#!”.

If the loader encounters “#!” then it will read the rest of the line execute the specified command (and arguments) and pass the file to it as the last argument. You can see this in operation with the following script:

$ cat foo
#!/bin/echo
This is a file?
$ chmod +x foo
$ ./foo
./foo

RDstore.com (Readers Digest)

If you have a shell script that needs to run with the standard POSIX shell, then there’s no problem. You just specify /bin/sh after the #! and it’s fine. But what happens if you want to use some bash-specific features? On GNU platforms, bash is the default shell and /bin/sh is a hard link to bash, so it’s in /bin. On other platforms it’s a third-party thing and so will be in /usr/local/bin or /opt/something. This is where env comes in.

When you specify “#!/usr/local/env bash” you can safely hard-code the path of env, because POSIX defines where it is. Env then looks up where bash is and execs it with whatever command line arguments it was given. You can see this in action again like this:

$ /usr/bin/env echo test
test

If you just run ‘env’ from a command line to inspect the environment variables, you are most likely just calling a shell built-in command, which lists the things passed in to the third argument to main() and any set since the shell started. Env, however, can be used when you are not launching from a shell. If your program wants to run a shell script, you can just vfork() and exec() it, and the loader will find the correct interpreter. You could always inspect the environment yourself, but having every app do that whenever it needs to run a script is quite silly (especially since it means that the app also has to know the difference between a binary and a script and so on).

Some people still have a habit of hard-coding /bin/bash, and this is probably the kind of crap LSB will encourage (’bash is always in /bin on Linux, and I don’t care about other platforms!’) but the correct thing to do is use env.

Share and Enjoy:
  • Digg
  • Reddit
  • Slashdot
  • del.icio.us
  • StumbleUpon
  • TwitThis
  • Fark
  • Facebook
  • Technorati
  • Sphinn
  • Furl
  • Google
  • Mixx