Bash和Zsh中的重定向与管道行为差异

9
下面的命令在bash和zsh中运行时会输出不同的结果:
ls -l > x | wc -l

如果在非空目录中执行,bash 总是返回 0,而 zsh 返回正确的文件数。 x 包含预期的 ls -l 输出。为什么 bash 不起作用呢?

zsh 要实现这个功能的唯一方法就是使用 tee 命令(读取 ls -l 的输出,将其写入文件并同时写入 wc -l)。相比于直接将 ls -l 连接到文件 x 或者 wc -l 的标准输入,而不对正在处理的内容进行任何干预,这种方式显得有些突兀和不寻常,也不太适合作为 shell 提供的功能。 - Charles Duffy
一种可移植的编写方式是 ls -l | tee x | wc -l - Charles Duffy
2个回答

9
请参考zshmisc手册中的MULTIOS文档。它是zsh的一个功能,可以同时将输出重定向到多个文件,并且还可以作为管道使用。
例如:
ls >a >b

将同时使用ab填充目录的内容。

来自zshmisc文档:

如果用户尝试多次打开一个文件描述符进行写操作,则shell会将该文件描述符作为管道打开,将其输入复制到所有指定的输出中,类似于tee命令,前提是MULTIOS选项已设置,默认情况下已设置。 因此:

date >foo >bar

将日期写入两个名为foobar的文件中。请注意,管道是一个隐式重定向;因此
date >foo | cat

将日期写入文件foo,并将其传输到cat。要打开它,您需要执行setopt multios,要关闭它,您需要执行setopt nomultios
$ setopt nomultios
$ ls -l > x | wc -l
0
$ setopt multios
$ ls -l > x | wc -l
36

谢谢!我实际上偶然发现了一个解释它的答案(http://stackoverflow.com/a/20735659/3997816)。 - Bruno Parmentier

4
ls -l 的输出被重定向到一个名为 'x' 的文件中。没有输出可以进入管道(所有输出都进入了 'x' 文件)。这是大多数标准 shell 的工作方式。
问题不在于为什么 bash 不起作用,而在于为什么 zsh 做它所做的事情。

如果您有新的问题,请通过单击提问按钮来提出。如果它有助于提供上下文,请包含此问题的链接。 - bitoiu
2
@bitoiu 这是对这个问题的回答,不是吗?我在这里没有看到新的问题。 - Rup

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接