我正在尝试将命令的输出通过管道传输到read
我的 shell 的内置函数中,并且我得到了不同的行为zsh
and bash
:
$ bash -c 'echo hello | read test; echo $test'
$ zsh -c 'echo hello | read test; echo $test'
hello
虽然这在 中不起作用bash
,但以下适用于两者:
$ bash -c 'echo hello | while read test; do echo $test; done'
hello
$ zsh -c 'echo hello | while read test; do echo $test; done'
hello
这是为什么?我用read
错了吗?test="$(echo hello)"
与迫使我更仔细地处理引用问题相比,我发现在脚本中使用它更具可读性。
您正在观察未使用 POSIX 标准化的结果。
POSIX 没有标准化解释器如何运行管道。
对于历史悠久的 Bourne Shell,管道中最右边的程序甚至不是主 shell 的子程序。这样做的原因是因为这个实现很慢但需要很少的代码 - 如果你只有 64 kB 的内存,这很重要。由于在此变体中,
read
命令在子进程中运行,因此在子进程中分配 shell 变量在主 shell 中不可见。像
ksh
orbosh
(最近的 Bourne Shell)这样的现代 shell 创建管道的方式是,管道中的所有进程都是主 shell 的直接子进程,如果最右边的程序是内置 shell,它甚至由主 shell 运行。这一切都需要让
read
程序修改主 shell 的 shell 变量。所以只有在这个变体中(BTW 是最快的变体)才允许主 shell 看到变量赋值的结果。在您的第二个示例中,整个
while
循环在同一个子进程中运行,因此允许打印 shell 变量的修改版本。目前有一个请求添加对 POSIX shell 的支持,以获取有关任何管道命令是否具有非零退出代码的信息。为了实现这一点,shell 必须以管道中的所有程序都是主 shell 的直接子级的方式实现。这接近允许
做预期的事情,因为那时只缺少在主 shell 中运行读取的要求。