为什么 popd 上的 shell 扩展不会从堆栈中删除目录?

Ada*_*son 3 shell bash command-substitution pushd

当我popd单独使用时,它会从堆栈中删除一个目录并将我带到该目录。但是,如果我这样做,cd $(popd)则不会从堆栈中删除任何目录。

既然进程只是简单地分叉并且结果代替了 shell 扩展,为什么不从堆栈中取出一个目录?

Ste*_*ris 8

语法$(...)不是“shell 扩展”,而是“命令替换”。

使用此语法创建一个子 shell,执行里面的命令并在 comamnd 行返回标准输出。所以,例如,

x=$(cd /tmp ; ls)
Run Code Online (Sandbox Code Playgroud)

cd在子shell中运行命令,这意味着主进程的当前目录保持不变。

以类似的方式,cd $(popd)将导致popd在子进程中运行,因此仅影响子进程;父进程未受影响。

您可以通过这个简单的测试看到它影响了子进程:

$ pushd /tmp
/tmp ~
$ pushd /
/ /tmp ~
$ dirs
/ /tmp ~
$ cd $(popd ; dirs >&2)
/tmp ~
$ dirs
/tmp /tmp ~
Run Code Online (Sandbox Code Playgroud)

dirs >&2表明在$(...)shell内部目录堆栈已被弹出,但由于这是一个进程,因此父堆栈未受影响。

  • 挑剔:`$(...)` *是*外壳扩展——具体地说,它是外壳扩展的一部分,称为命令替换。 (4认同)

Gil*_*il' 6

命令替换$(…)在子 shell 中运行命令。子外壳开始时是主外壳的相同¹副本,但从那时起,主外壳和子外壳过着自己的生活。

  1. shell 进程创建一个管道和叉子。
  2. 子进程运行popd时将其输出连接到管道,然后退出。
  3. 父级从管道读取数据并将其替换到命令行中。

由于popd在子进程中运行,其作用仅限于子进程。该目录采取关闭堆栈-关子的堆栈。父级中的堆栈没有任何反应。

¹几乎相同;差异在这里无关紧要。