当我popd
单独使用时,它会从堆栈中删除一个目录并将我带到该目录。但是,如果我这样做,cd $(popd)
则不会从堆栈中删除任何目录。
既然进程只是分叉,并且结果被放置在 shell 扩展的位置,为什么不从堆栈中取出目录呢?
答案1
语法$(...)
不是“shell 扩展”,而是“命令替换”。
使用此语法,将创建一个子 shell,执行其中的命令并在命令行上返回标准输出。所以,举例来说,
x=$(cd /tmp ; ls)
将在子 shell 中运行该cd
命令,这意味着主进程的当前目录保持不变。
以类似的方式,cd $(popd)
将导致popd
在子进程中运行,因此仅影响子进程;父进程未受影响。
通过这个简单的测试,您可以看到它已经影响了子进程:
$ pushd /tmp
/tmp ~
$ pushd /
/ /tmp ~
$ dirs
/ /tmp ~
$ cd $(popd ; dirs >&2)
/tmp ~
$ dirs
/tmp /tmp ~
表明在 shelldirs >&2
内部$(...)
目录堆栈已被弹出,但是因为这是一个孩子进程的父堆栈未受影响。
答案2
命令替换$(…)
在子 shell 中运行命令。子 shell 最初是主 shell 的相同副本,但从那时起,主 shell 和子 shell 就过着自己的生活。
- shell 进程创建管道和叉子。
- 子进程运行
popd
时其输出连接到管道,然后退出。 - 父级从管道读取数据并将其替换到命令行中。
由于popd
在子进程中运行,因此其作用仅限于子进程。目录是从堆栈中取出 — 从子堆栈中取出。父级中的堆栈没有任何变化。
1几乎相同;这些差异在这里无关紧要。
答案3
pushd
并将popd
堆栈保留在名为 的变量中DIRSTACK
,该变量在子 shell 中发生变化,但在父 shell 中保持不变,就像任何其他环境变量一样。