web-dev-qa-db-ja.com

popdのシェル拡張でスタックからディレクトリが削除されないのはなぜですか?

popdを単独で使用すると、スタックからディレクトリが削除され、そのディレクトリに移動します。ただし、cd $(popd)を実行すると、スタックからディレクトリが削除されません。

プロセスは単純にフォークされ、結果はシェル拡張の代わりに配置されるので、なぜディレクトリがスタックから削除されないのですか?

3
Adam Thompson

コマンド置換$(…)は、サブシェルでコマンドを実行します。サブシェルはメインシェルの同一¹コピーとして始まりますが、その時点からメインシェルとサブシェルは独自の生活を送っています。

  1. シェルプロセスは、パイプとフォークを作成します。
  2. 子は、出力をパイプに接続してpopdを実行し、終了します。
  3. 親はパイプからデータを読み取り、それをコマンドラインに置き換えます。

popdは子プロセスで実行されるため、その効果は子プロセスに限定されます。ディレクトリisスタックから削除されました—子のスタックから削除されました。親のスタックには何も起こりません。

¹ ほぼ同じ。ここでは違いは関係ありません。

構文$(...)は「シェル拡張」ではなく、「コマンド置換」です。

この構文を使用すると、サブシェルが作成され、内部のコマンドが実行され、標準出力がコマンド行に返されます。だから、例えば、

_x=$(cd /tmp ; ls)
_

サブシェルでcdコマンドを実行します。これは、メインプロセスの現在のディレクトリが変更されないままであることを意味します。

同様に、cd $(popd)popdを子プロセスで実行するため、子プロセスにのみ影響します。親プロセスは変更されていません。

この簡単なテストで、子プロセスに影響を与えていることがわかります。

_$ pushd /tmp
/tmp ~
$ pushd /
/ /tmp ~
$ dirs
/ /tmp ~
$ cd $(popd ; dirs >&2)
/tmp ~
$ dirs
/tmp /tmp ~
_

_dirs >&2_は、$(...)シェル内でディレクトリスタックがポップされたことを示していますが、これはchildプロセスであるため、親スタックは変更されていません。

8
Stephen Harris

pushdpopdは、スタックをDIRSTACKという変数に保持します。この変数はサブシェルで変更されますが、他の環境変数と同様に、親シェルでは変更されません。

さらに読む

3
Dmiters