「which」コマンドが「cd」で機能しないのはなぜですか?「cd」の実行可能ファイルも見つかりません!


30

私は試しましたwhich cdが、パスを提供しませんでしたが、代わりに終了コード1を返しました(チェックされていますecho $?)。coreutil cd自体が動作しているので、実行可能ファイルがそこにあるはずですよね?私もfindforをcd実行しましたが、実行可能ファイルは表示されませんでした。それではどのように実装されますか?

更新:

別の投稿でこれを尋ねる必要があるかどうかはわかりませんが、ここでそれが良いと思うので、投稿を拡大します(?)。だから答えは実際には非常に簡単で、そのための実行ファイルはありません。ビルトイン—しかし、いくつかのビルトイン(Fedoraのbashシェル)には実行可能ファイルがあることがわかりました!だから組み込み->実行可能ファイルが正しくないのでしょうか?多分ビルトインが実際に何であるか(ビルトインコマンド?)を説明する答えかもしれませんが、これは実際にここで問題にcdなります。彼らはどのように機能しますか?それらは単にシェルの機能またはスレッドですか?


1
この答えを読んでください。typeコマンドを使用することをお勧めします
c0rp 14年

7
cd組み込みが必要な理由に関するこのQ&Aを参照してください。なぜcdはプログラムではないのですか?そして、これはなぜtypeよりも優れていますwhichなぜ「which」を使用しないのですか?次に何を使用しますか?
テルドン

同様の質問はこちら:askubuntu.com/q/613470/178596
Wilf

回答:


46

コマンドcdを実行可能にすることはできません

シェルでcdは、「別のディレクトリに移動する」ため、またはより正式には現在の作業ディレクトリ(CWD)を変更するために使用されます。外部コマンドとして実装することは不可能です。

ディレクトリはプロセスに属します

現在の作業ディレクトリは、相対パスを解釈してファイルへのアクセスに使用できるフルパスを取得するために使用されるディレクトリです。相対パスは多くの場所で使用されており、あるプロセスでの解釈が別のプロセスに影響を与えることはありません。
このため、すべてのプロセスには独自の現在の作業ディレクトリがあります。

cdたとえば、シェルプロセスの現在の作業ディレクトリを変更することbashです。

外部コマンドである場合、その実行可能ファイルを実行するパス内の実行可能ファイルは、現在のシェルのプロセスに影響を与えることなく、独自の作業ディレクトリを使用してプロセスを作成します。外部コマンドがディレクトリを変更したとしても、その変更は外部プロセスが終了すると消えます。

シェル組み込みコマンド

したがって、のタスクに対して外部コマンドを実行しても意味がありませんcd。このコマンドcdは、現在実行中のシェルプロセスに変更を適用する必要があります。

そのためには、シェルの「組み込みコマンド」です。

組み込みコマンドは、外部コマンドと同様に動作するコマンドですが、シェルに実装されています(したがってcd、coreutilsの一部ではありません)。これにより、コマンドはシェル自体の状態を変更できます。この場合、chdir()see(を参照man 2 chdir)を呼び出します。

which

さて、タイトルの質問への答えは簡単です:
実行可能コマンドwhichは組み込みコマンドについて何も知らないため、実行可能コマンドはcdが組み込みコマンドであることを教えてくれません。

代替案 type -a

の代替としてwhich、次を使用できますtype -a。実行可能なコマンドとビルトインを表示できます。さらに、エイリアスと関数も表示されます-シェルにも実装されています:

$ type -a cd
cd is a shell builtin
$ type -a type
type is a shell builtin
$ type -a which
which is /usr/bin/which
which is /bin/which

1
素晴らしい説明!
SaltyNuts 14年

3
現在受け入れられている答えよりもはるかに優れています。これは、なぜ cdシェルが組み込まれているのかを説明ています。
リリーチョン14年

28

cdあるPOSIXによって義務付けられたシェルの組み込みは:

単純なコマンドの結果、コマンド名とオプションの引数リストが生成される場合、次のアクションが実行されます。

  1. コマンド名にスラッシュが含まれていない場合、次のシーケンスで最初に成功するステップが発生します:
    ...
    • コマンド名が次の表にリストされているユーティリティの名前と一致する場合、そのユーティリティが呼び出されます。
      ...
      cd
      ...
    • それ以外の場合、コマンドはPATHを使用して検索されます...

これは明示的に組み込みである必要があるとは言いませんが、仕様書は次の記述でcd続けています:

cdは現在のシェル実行環境に影響を与えるため、常にシェルの標準ビルトインとして提供されます。

bashマニュアルから:

次のシェル組み込みコマンドは、Bourneシェルから継承されます。これらのコマンドは、POSIX標準の指定に従って実装されます。
...

cd
       cd [-L|[-P [-e]]] [directory]

ビルトインである必要のcdないアーキテクチャを考えることができると思います。ただし、組み込みの意味を確認する必要があります。何らかのコマンドのために何かをするためにシェルで特別なコードを書くと、ビルトインに近づいています。あなたがやるほど、単にビルトインする方が良いです。

たとえば、シェルにサブプロセスと通信するIPCを持たせることができます。またcd、ディレクトリの存在と、アクセスする権限があるかどうかを確認し、シェルと通信してその変更を指示するプログラムがあります。ディレクトリ。ただし、その後、あなたと通信しているプロセスが子であるか(または、特別なファイル記述子、共有メモリなど、子とのみ通信する特別な手段を作成するか)、プロセスが実際にあるかどうかを確認する必要があります信頼できるcdプログラムなどを実行します。それはワームの全体の缶です。

またはcdchdirシステムを呼び出して、現在のすべての環境変数を新しいシェルに適用して新しいシェルを開始し、完了時に親シェルを(なんとかして)終了するプログラムを作成することもできます。1

さらに悪いことには、プロセス他のプロセスの環境を変更できるシステムさえあります(技術的には、デバッガーでこれを行うことができると思います)。ただし、このようなシステムは非常脆弱です。

このようなメソッドをセキュリティで保護するためにコードを追加することが多くなり、単に組み込みにする方がはるかに簡単です。


何かが実行可能ファイルであることは、それが組み込みであることを妨げません。適例:

echo そして test

echoおよびtestPOSIXが義務付けているユーティリティ(/bin/echoおよび/bin/test)です。しかし、ほとんどすべての人気のあるシェルには組み込みechotest。同様に、killプログラムとしても利用可能なビルトインです。その他には以下が含まれます:

  • sleep (一般的ではない)
  • time
  • false
  • true
  • printf

ただし、コマンドが組み込み以外のものになれない場合があります。それらの1つですcd。通常、フルパスが指定されておらず、コマンド名が組み込みコマンドの名前と一致する場合、そのコマンドに適した関数が呼び出されます。シェルに応じて、組み込みの行動と実行のそれは、これは特にです(異なる場合がありますのための問題echoがある、乱暴に異なる行動を。あなたが行動の特定になりたい場合は、実行ファイルが使用して呼び出すことが望ましいですフルパス、次のような変数を設定しますPOSIXLY_CORRECT(それでも実際の保証はありません)。

技術的には、シェルでもあり、すべてのコマンドが組み込みのOSを提供することを妨げるものはありません。この極端な終わりに近いのは、モノリシックなBusyBoxです。BusyBoxは単一のバイナリで、(呼び出される名前に応じて)Almquist Shell()を含む240以上のプログラムのいずれかとして動作できますashPATHBusyBoxの実行中に設定を解除しても、BusyBox ashで使用可能なプログラムには、.yを指定しなくてもアクセスできますPATH。シェル自体がBusyBoxの一種のビルトインであることを除けば、シェル組み込みに近いものになります。


ケーススタディ:Debian Almquist Shell(dash

dashソースを見ると、実行スレッドは次のようなものです(もちろん、パイプやその他のものを使用する場合は追加の機能が含まれます)。

maincmdloopevaltreeevalcommand

evalcommand次にfindcommand、コマンドが何であるかを決定するために使用します。それは組み込みであれば、その後

 case CMDBUILTIN:
     if (spclbltin > 0 || argc == 0) {
         poplocalvars(1);
         if (execcmd && argc > 1)
             listsetvar(varlist.list, VEXPORT);
     }
     if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
         if (exception == EXERROR && spclbltin <= 0) {
             FORCEINTON;
             break;

cmdentry.u.cmdstructstruct builtincmd)であり、そのメンバーの1つは、次の典型的なシグネチャを持つ関数ポインターmainです(int, char **)evalbltin(組み込みであるか否かに応じて、関数呼び出しevalのいずれかコマンドかどうか)evalcmd、またはこの関数ポインタ。実際の関数は、さまざまなソースファイルで定義されています。echo例えば、あります

int
echocmd(int argc, char **argv)
{
    int nonl;

    nonl = *++argv ? equal(*argv, "-n") : 0;
    argv += nonl;

    do {
        int c;

        if (likely(*argv))
            nonl += print_escape_str("%s", NULL, NULL, *argv++);
        if (nonl > 0)
            break;

        c = *argv ? ' ' : '\n';
        out1c(c);
    } while (*argv);
    return 0;
}

このセクションのソースコードへのリンクはすべて行番号ベースであるため、予告なく変更される場合があります。


1 POSIXシステムにはcd実行可能ファイルがあります


サイドノート:

UnixおよびLinuxには、シェルの動作を扱う多くの優れた投稿があります。特に:

これまでにリストされた質問のパターンに気付いていない場合、それらのほぼすべてにステファンシャゼラスが関係しています。


4
(すべてのシェル組み込みコマンドに同じもの)でcdヘルプテキストを取得できることに注意してくださいhelp cd
シルヴァンピノー14年

@SylvainPineauはbashマニュアルにリンクしていますが、そのアドバイスは一般的にzshなどの他のシェルには適用できません。
ムル

実際help、bashはビルトインです(zshの場合はrun-help cd
Sylvain Pineau

POSIX仕様のリンクされた説明は、cdシェルビルトインである必要があると明示的に述べていませんが、シェルビルトインとしてUNIXでプロセスプロパティとその転送がどのように機能するかに基づいてcd、唯一の簡単な実装です。Volker Siegel返信を参照してください。
pabouk 14年

@paboukは確かに(ユーティリティと呼ばれます)、続いて「cdは現在のシェル実行環境に影響を与えるため、常にシェルの標準ビルトインとして提供されます」と言います。
ムル14年

8

実行ファイルがないため、実行可能ファイルが見つかりcdません。

cdシェルの内部コマンドです(例:)bash


7

からman which

現在の環境で実行されるファイル(またはリンク)のパス名を返します。引数が厳密にPOSIX準拠のシェルでコマンドとして指定されていた場合。これは、引数の名前と一致する実行可能ファイルのPATHを検索することにより行います。シンボリックリンクをたどりません。

の説明からわかるようにwhich、チェックのみPATHです。したがって、いくつかを実装した場合bash function、何も表示されません。と共にコマンドを使用することをお勧めします。typewhich

たとえば、Ubuntu lsコマンドのエイリアスls --color=auto

$ type ls
ls is aliased to `ls --color=auto'

$ which ls
/bin/ls

そして、テスト機能を実装する場合hello

$ function hello() { for i in {1,2,3}; do echo Hello $i;done }
$ which hello

which何も表示されません。しかしtype

$ type hello
hello is a function
hello () 
{ 
    for i in {1,2,3};
    do
        echo Hello $i;
    done
}

あなたの場合:

$ type cd
cd is a shell builtin

これcdは、組み込みシェルであり、内部にあることを意味しbashます。man bashセクションSHELL BUILTINコマンドので説明されているすべてのbashビルトイン

SHELL BUILTIN COMMANDS
       Unless otherwise noted, each builtin command documented in this section
       as accepting options preceded by - accepts -- to signify the end of the
       options.   The  :, true, false, and test builtins do not accept options
       and do not treat -- specially.  The exit, logout, break, continue, let,
       and  shift builtins accept and process arguments beginning with - with‐
       out requiring --.  Other builtins that accept  arguments  but  are  not
       specified  as accepting options interpret arguments beginning with - as
       invalid options and require -- to prevent this interpretation.


1
おそらくもっと強調する必要があります:使用しないwhich、使用するtype
トリプリー14年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.