web-dev-qa-db-ja.com

空の環境では、実行可能ファイルはどのように見つかりますか?

実験の目的で、$PATHを出力し、次のようにwhichを呼び出すバイナリを作成しました。

#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;
}

空の環境で実行すると

env -i ./printpath

次のプリントアウトが表示されます。

got no path
/usr/bin/which

私の質問は次のとおりです。$PATHがない場合でも、正しいwhichバイナリが呼び出されるのはなぜですか?

7
keppla

system関数を使用したので、別のシェルを使用してコマンドwhich whichを実行します。 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.

which whichコマンドをecho $PATHに変更した場合:

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

execveの代わりにsystemを使用するようにコードを変更すると、期待どおりの出力が得られます。

#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;                                                                   
} 

コンパイルして実行します。

$ gcc test.c && env -i ./a.out 
got no path
11
cuonglm

空の環境では、フルパスを指定しない限り実行可能ファイルは見つかりません。 execvpで試してみてください。

system関数はシェルを呼び出します— Linux with Glibcでは、/bin/shを呼び出します(したがって、PATHは必要ありません)。シェルは、環境からの変数に加えて、独自のいくつかの変数を定義します。 env -i /path/to/Shell -c setを実行することで定義されているものと、env -i /path/to/Shell -c exportを実行することでエクスポートされるものを確認できます。特に、ダッシュとbashの両方(Linuxで/bin/shとして検出される可能性が高い2つのシェル)は、環境に1つもない場合、PATHを「正常な」デフォルトに設定します(ただし、エクスポートはしません)。 。シェルが異なれば、設定される値も異なるか、まったく設定されません。

$ 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.

私のマシン(そして明らかにあなたのマシン)では、which自体が/bin/shスクリプトです。 systemによって呼び出されたシェルは、独自のパス変数を使用してwhichプログラムを検索しますが、それをエクスポートしません。 whichスクリプト自体を実行するシェルは、内部で使用するためにPATH変数も定義します。