1

Sometimes, I have to specify a full path, because $PATH is seemingly not consulted:

####            I have `virtualenv` and it's on my path            ####

$ virtualenv --version      # `virtualenv` is on my path
1.7.1.2
$ which virtualenv          # further details
/usr/bin/virtualenv
$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games

####               However, I can't `stat virtualenv`:             ####

$ stat virtualenv
stat: cannot stat `virtualenv': No such file or directory

####              I have to use `stat `which $BINARY``               ####

$ stat `which virtualenv`
  File: `/usr/bin/virtualenv'
  Size: 54              Blocks: 8          IO Block: 4096   regular file
Device: ca01h/51713d    Inode: 22860       Links: 1
Access: (0755/-rwxr-xr-x)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2012-11-28 23:48:03.919400541 -0500
Modify: 2012-04-23 06:34:09.000000000 -0400
Change: 2012-11-28 17:24:31.335400569 -0500
 Birth: -
$ 

Why do I have to use which virtualenv if it's on my path?

1
  • 1
    I get the same results as you on my box. Unfortunately, I don't know the answer as to why this happens.
    – slafat01
    Nov 29, 2012 at 14:55

3 Answers 3

5

$PATH is only consulted when executing commands. When the shell has to search for a command to execute, it consults $PATH and walks down the list of directories in $PATH and picks the first executable file (with an appropriate execute bit set in the permissions) matching the supplied name, and executes it.

When you run stat virtualenv, you are passing virtualenv as an argument to the stat program. Assuming that stat is written in C, it then sees virtualenv as an argument in the program's main method:

int main(int argc, char** argv)

The argv contains two elements: index 0 is the command you used to invoke the program itself, so it's "stat". index 1 is the first command line argument, so it's "virtualenv".

This happens because the exec() series of system calls (look up the manpage if you're curious) allow you to pass an array of command line arguments when you replace the current process with a child process. The shell does call some variant of exec() and it parses your command line to determine which command line argument array to pass as argv.

Since stat doesn't know whether the file you supplied is a normal file, symlink, hardlink, executable or not, directory, etc., it doesn't search $PATH to find it. It treats the passed-in argument as specifying, specifically, ${PWD}/virtualenv where ${PWD} is expanded to the current working directory at the time that the stat program was invoked. This is called a relative path.

Almost all commands that accept relative paths for file names as an argument will not search $PATH, although a few commands might do so, such as bash or ssh if you tell them to execute a command in the child shell environment. There is nothing preventing any arbitrary command from looking through any particular environment variable for the file you supply, but it's application-specific behavior. It wouldn't make any sense at all to search $PATH for relative paths, because $PATH is only for executable files.

1
  • Awesome. Thank you for incorporating the C and system call execution narrative. Nov 29, 2012 at 17:16
3

The PATH is needed and consulted when you are trying to execute something.

Unlike Windows, on Unix you always need to specify executable files with a path. ./foo.bin or /usr/bin/foo.bin. However for simplicity there exists this thing called PATH. So it suffices to type foo.bin because /usr/bin happens to be in your path.

And if you ever wonder which file is resolved via foo.bin, which is there to tell you: /usr/bin/foo.bin.

Therefore every other UNIX tool accepting both executable and non-executable files as arguments, will probably not consult PATH.

1

The PATH is consulted by the shell when executing programs to find the program to execute. When it's a parameter (such as to the which or stat commands in your example), the shell just passes it to the program that it found as it, and the program decides what to do with it.

The which command is built into bash, and it takes the argument and consults the shell's path to figure out what the shell would do to execute it. Most other programs (including most other programs built into bash), such as stat in your example, just use the path and try to find it in the current directory in the filesystem.

So, executing commands (and things like which which are trying to figure out what commands to execute) are the only things that use the PATH.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .