When does the shell search PATH?

I am a bit confused about when PATH is searched. I had thought that PATH was only searched when a simple filename is given as the first token on a line, as in

$ date

A question I am solving however, seems to suggest that PATH is also searched when I very explicitly list a file with the ./ prefix:

$ ./date

Is this indeed the case? That is, if in my working directory I do not have an executable named date (say date was merely a script), the answer to this question seems to suggest that the shell will then go on to search PATH (and then find the standard date utility in some directory like bin).

I asked a somewhat analogous question here and the order for the shell search was nicely given in answer there. However, there I emphasized that I was simply giving the command as a simple filename. Here, I am very explicitly giving a ./ prefix. Why does the shell still search PATH, or am I missing something?


From Sobell’s A Practical Guide to Linux:

Explain the following unexpected result:

$ whereis date
date: /bin/date ...
$ echo $PATH 
.:/usr/local/bin:/usr/bin:/bin
$ cat > date
echo "This is my own version of date." 
$ ./date
Sun May 21 11:45:49 PDT 2017

One "expects" that the shell script ./date is run so that the output is "This is my own version of date."

Asked By: EE18

||

The POSIX-standard-conforming behavior with regard to PATH is not to use that variable if the input contains a slash anywhere. For instance if the command is foo, then the PATH is searched, but not if it is foo/bar or /foo/bar or ./foo/bar: anything with one or more slashes.

If a shell has to replicate PATH searching behavior in its own code base, rather than relying on functions like execvp, it should avoid searching when the input contains a slash.

I can reproduce your result easily, though.

Actual copy paste from my terminal:

$ cat > date
echo "this is my own version of date."
$ ./date
Mon 12 Feb 2024 06:38:20 PM PST
$

What I did was not type Ctrl-D after the echo ... line, so the $ ./date and the Mon 12 ... is all text typed into cat‘s standard input.

Answered By: Kaz

Looking only at the exercise quoted in the question, after thinking about it a bit, I think defining cat to be a function or script that does something other than the standard cat might also work. I found some online copies of the book, and this exercise has existed in the second, third and fourth editions, with the timestamp in the output changing, so I believe this is not a typo.

Depending on whether echo "This is my own version of date." in the third command is input or output, cat could be either:

cat () {
  read; # Reads a line of input, but we won't do anything with it
  echo date; # Write to stdout
  chmod +x /proc/self/fd/1; # Apply execute permissions to stdout's backing file
}

Or:

cat () {
  echo 'echo "This is my own version of date."' >&2 ; # Write to stderr
  echo date; 
  chmod +x /proc/self/fd/1;
}

The reason this works is:

  • /proc/self/fd/1 is a symlink to the actual file if stdout is redirected to a file.
  • chmod changes the permissions of the pointed-to file if given a symlink as an argument.

I checked the manpages Red Hat 4.2 (released 1997), and both of these hold true even back then (proc(5), chmod(1)), so these functions would have worked fine even going back to the first edition of the book. (Of course, the fake cat could have chmod +x ./date directly as well.)

Answered By: muru
Categories: Answers Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.