Why does a shebang need a path?





#!/usr/bin/env ruby

The operating system should have the information regarding the path for a registered command, and why does it still expect it to be given?

5 Answers 5


Probably to keep the kernel simpler. I don't think the kernel ever searches your path to find an executable. That's handled by the C library. #! processing is done in the kernel, which doesn't use the standard C library.

Also, I don't think the kernel has a notion of what your path is. $PATH is an environment variable, and only processes have an environment. The kernel doesn't. I suppose it could access the environment of the process that did the exec, but I don't think anything currently in the kernel ever accesses environment variables like that.


You can get PATH-searching semantics using env, so:

#!/usr/bin/env ruby  

has the semantics you would like from


The reason that depending on PATH is not considered good practice is that the script can make no assumptions about the content of the PATH environment variable, breaking the "sequential dependency model" of binaries where

  1. /bin contains the executables needed at boot time;
  2. /usr/bin contains the other executables used by the OS installation;
  3. /usr/local/bin contains executables installed by the system administrator that are not part of the base OS.
  4. ~/bin contains the user's own executables.

Each level should not assume the existence of binaries later in the sequence, which are more "application" but may rely on binaries earlier, which are more "fundament". And the PATH variable tends to run from applicationy to fundamental, which is the opposite direction to the natural dependency above.

To illustrate the problem, ask yourself what happens if a script in ~/bin invokes an script in /usr/local/bin that invokes Ruby? Should that script depend on the OS installed version at /usr/bin/ruby, or on the personal copy the user happens to have at ~/bin/ruby? PATH searching gives the unpredictable semantics associated with the latter (maybe ~/bin/ruby is a broken symbolic link), while baking in the path to #! gives the former.

There isn't really any other platform-independent "operating system ... information regarding the path for a registered command", so the simplest thing is to insist on the path being provided in the #!.


I believe that's so you can specify an alternate interpreter if you need or want to. For example:


More often seen with shell scripts:

  • 4
    But why would that make it necessary? You can run ruby directly with ruby, but that doesn't stop you from specifying /home/user/myrubyinterpreter if you want Apr 24, 2011 at 3:00
  • Michael's point is exactly what I what I am asking.
    – sawa
    Apr 24, 2011 at 3:31

From Classic Shell Scripting book:

Shell scripts typically start with #! /bin/sh. Use the path to a POSIX-compliant shell if your /bin/sh isn't POSIX compliant. There are also some low-level "gotchas" to watch out for:

  • You have to know the full pathname to the interpreter to be run. This can prevent cross-vendor portability, since different vendors put things in different places (e.g., /bin/awk versus /usr/bin/awk).

There are other reasons, but from a security perspective I would never want a script to make assumptions about the correct path. What if it is wrong and it runs the wrong shell or interpreter? One that has been inserted by a malicious user? Or what if it relies on a particular shell and will crash out if the wrong shell is used?

Users may mess around with their path and break stuff - don't trust the user:-) I have conducted numerous attacks which rely on the user doing the wrong thing with their path - usually getting things in the wrong order - so I can subvert a normal script call.

Yes, I know if you've written the script yourself you can quite rightly claim that you have sorted out your own path, but an interpreter can't make those decisions.

  • This concern only applies if the script is running with elevated privileges. And that's uncommon, because shebang and setxid don't play well together, and there's a lot more to worry about than $PATH.. Without elevated privileges, what if LD_PRELOAD is used? P.S. Downvoted because giving a false warning about security is detrimental to security. Apr 24, 2011 at 15:21
  • Your point about setxid is valid, however it is a perfectly useful attack vector so definitely isn't a false warning
    – Rory Alsop
    Apr 24, 2011 at 16:16
  • 1
    Could you give an example of a case where PATH is an attack vector, and there aren't so many other attack vectors that the whole approach should be rethought? Apr 25, 2011 at 17:38
  • @Gilles - +1 you have a good point, definitely, as if this is broken there are probably other ways in that are just as valid, however in terms of broken things you can fix, this is an easy one.
    – Rory Alsop
    Apr 26, 2011 at 7:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.