Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

For experimentation purposes I created a binary that prints the $PATH, and calls which as follows:

#include <stdlib.h>
#include <stdio.h>

int main() {
    char *path = getenv("PATH");

    if (path)
        printf("got a path: %s\n", path);
    else
        printf("got no path\n");

    system("which which");
    return 0;
}

when I run it in an empty environment via

env -i ./printpath

I get the following printout:

got no path
/usr/bin/which

My question is: why is the correct which binary called, even if there is no $PATH?

share|improve this question

2 Answers 2

up vote 10 down vote accepted

You have used system function, so it will use another shell to run the command which which. From man system:

DESCRIPTION
       system()  executes a command specified in command by calling /bin/sh -c
       command, and returns after the command has been completed.  During exe‐
       cution  of the command, SIGCHLD will be blocked, and SIGINT and SIGQUIT
       will be ignored.

If you change which which command to echo $PATH:

$ env -i ./a.out 
got no path
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

If you change your code to use execve instead of system, you will get expected output:

#include <stdlib.h>                                                             
#include <stdio.h>  

int main() {                                                                    
    char *path = getenv("PATH");                                                

    if (path)                                                                   
        printf("got a path: %s\n", path);                                       
    else                                                                        
        printf("got no path\n");                                                

    execve("echo $PATH");                                                       
    return 0;                                                                   
} 

Compile and run it:

$ gcc test.c && env -i ./a.out 
got no path
share|improve this answer
    
i expected the subshell to inherit the empty path and therefore had no consequence. thank you for pointing out that missconception! –  keppla Apr 19 at 19:30
1  
The subshell does inherit the empty path. However, as a feature of bash (and presumably other shells too), if it is started with PATH unset, it sets it to a default value, which is what we see in the echo $PATH example. –  Nate Eldredge Apr 20 at 1:35

In an empty environment, executables are not found unless you specify the full path. Try it with execvp.

The system function invokes a shell — on Linux with Glibc, it invokes /bin/sh (so no PATH needed). Shells define a few variables of their own in addition to the ones coming from the environment. You can see what they define by running env -i /path/to/shell -c set, and which ones they export by running env -i /path/to/shell -c export. In particular, both dash and bash — the two shells that you're likely to find as /bin/sh on Linux — set (but do not export) PATH to a “sane” default if there isn't one in the environment. Different shells set different values or none at all.

$ env -i bash -c 'echo $PATH'
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
$ env -i dash -c 'echo $PATH'
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
$ env -i mksh -c 'echo $PATH'
/usr/bin:/bin
$ env -i ksh93 -c 'echo $PATH'

$ env -i zsh -c 'echo $PATH' 
/bin:/usr/bin:/usr/ucb:/usr/local/bin
$ env -i csh -c 'echo $PATH' 
PATH: Undefined variable.
$ env -i tcsh -c 'echo $PATH'
PATH: Undefined variable.

On my machine (and yours, apparently), which is itself a /bin/sh script. The shell invoked by system uses its own path variable to find the which program, but does not export it. The shell that runs the which script itself also defines the PATH variable for its internal use.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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