cdコマンドが他のコマンドとは異なる方法でSTDINを処理するのはなぜですか?

cdコマンドが他のコマンドとは異なる方法でSTDINを処理するのはなぜですか?

このようなコマンドは、cdディレクトリを変更するために出力をパイプできません。コマンドライン引数が必要です。

から読み取ると、このコマンド(および、、&cdなどの類似コマンド)が他のほとんどのコマンドのように機能しないのはなぜですか?ディレクトリを変更するために標準入力を読み取らないようにするロジックは何ですか?mvcprmSTDIN

最高私が見つけることができる答え指摘した:

cd は外部コマンドではありません。シェル組み込み関数です。外部コマンドなど、ブランチ/実行コンテキストでは、別のプロセスではなく、現在のシェルのコンテキストで実行されます。

しかし、私に上記の答えは実際にはまったく説明しません。cd処理STDINがで読んだ他の多くのコマンドと異なる理由は何ですかSTDIN

答え1

読み取りコマンドは、stdinほとんど常にテキストデータストリームを変換されたデータストリームに変換するプログラムであるフィルタシリーズに属します。

cat、、、sedは、awkこれらの「フィルタ」の良い例gzipです。sh

参照されるコマンドはcpフィルタでmvはなく、rm渡された引数(この場合はファイルまたはディレクトリ)を使用して操作を実行するコマンドです。

このcdコマンドは、引数を取る(または指定されていない場合はデフォルトの引数をエミュレートするという点で)通常は何も出力しませんが、場合によっては(stdoutcontentを使用するときなど)一部を出力できるという点で似ていますCDPATH

stdinからターゲットディレクトリを取得するバリアントを作成したい場合でも、Bournecdシェルのパイプで使用しても効果はありません。コマンドの最後のコンポーネントはサブシェルで実行され、新しいディレクトリに対する変更は現在のシェルには影響しません。例: 使用できますが使用できません , , , , ...dashbashecho /tmp | cdksh93bashdashzshsh

cd <(echo /tmp)プロセス置換(少なくともkshbash)をサポートするシェルzshで使用できますが、cd $(echo tmp)

興味がある唯一のユースケースは次のとおりです。

echo tmp | (cd ; pwd)

最後に、引数が指定されていないが予想される動作がディレクトリをユーザーのホームディレクトリに変更する場合、または引数が指定されていないが予想される動作が名前を読み取る場合を説明するために、これらのバリエーションが必要です。 stdinのターゲットディレクトリ。信頼できる決定方法がないので、これは当然のことです。

答え2

コマンドライン引数はstdinとは全く異なります。両方を使用するコマンドも通常、さまざまな目的で使用されます。例えばcat:

echo foo bar | cat    # outputs "foo bar"
cat foo bar           # looks for files named "foo" and "bar", and concatenates them (if found)

stdinで読んでいる他のほとんどのコマンドを見ると、同様のことがわかります。つまり、引数と stdin を入れ替えて処理するのではなく、コマンドにさまざまな種類の情報を提供する方法で処理します。

どちらにしても、同じ種類の情報を取得できるコマンドがありますが、そのような場合でも、通常どのコマンドを使用するかを知らせるオプションを指定する必要があります。たとえば、perl特に指示がない限り、stdinで読み込むプログラムは次のようになります。

echo 'print 1' | perl    # runs "print 1" as a perl program, which prints "1"
perl -e 'print 1'        # runs "print 1" as a perl program, which prints "1"
perl print 1             # tries to run a file named "print" as a script, giving it the argument "1"

...だから質問の前提が間違っていると思います。ほとんどのコマンドは、引数から得られるのと同じ種類の情報を標準入力から得ることができないので、cdその点ではまれではありません。

関連情報