【发布时间】:2015-11-17 09:27:36
【问题描述】:
在设计执行某个任务的命令链时,我遇到了匿名管道的行为与预期不同的问题。由于我正在运行的原始命令太复杂,无法在这里解释,我创建了一个显示问题的示例(我知道所有这些命令基本上什么都不做)。另外,我使用 pv 来显示数据是否实际从输入复制到输出。
cat /dev/zero | pv > /dev/null
这按预期工作。 (将数据从 /dev/zero 复制到 /dev/null)
cat /dev/zero | tee /dev/null | pv > /dev/null
这也可以按预期工作(复制数据并将两个副本发送到 /dev/null)
cat /dev/zero | tee >(pv -c > /dev/null) | pv -c > /dev/null
此命令仅部分有效。虽然从 STDIN 到 STDOUT 的副本仍然有效(一个 pv 将在短时间内显示进度),但整个命令被匿名管道停止,该管道不接收任何内容,因此 tee 停止,因为其中一个输出无法写入(我通过让它写入文件而不是 /dev/null 来检查这一点)。
如果有人知道为什么这在 bash 中不起作用(如预期的那样?),我会很高兴获得帮助。
PS:如果我使用 zsh 而不是 bash,命令会按预期运行。不幸的是,这个需要运行的系统没有 zsh,我无法在该系统上部署 zsh。
【问题讨论】:
-
直接通过
bash -c或在子shell(即:(cat /dev/zero | tee >(pv -c > /dev/null) | pv -c > /dev/null))中运行它似乎可以工作...在交互式shell 中运行它,它就像你提到的那样挂起。我不知道为什么。 -
这种情况只发生在
pv上吗?因为当我用cat替换第一个pv时,它对我有用。也许pv不能使用进程替换魔法? -
据我所知,cat 不会从 STDIN 读取数据。通过用 cat 替换第一个 pv,来自匿名管道的读取实际上忽略了匿名重定向。我不认为那是预期的效果。但是,将 pv 替换为其他内容(如 awk '{print $0}' 或 perl -ne 'print $_' 具有相同的效果(两个命令都有效地将 STDIN 复制到 STDOUT)
-
@Fabraxias : cat 确实从标准输入中读取。试试
echo "abc" | cat或者如果你有一个旧的unixen,你可能需要echo "abc" | cat -(-表示从标准输入读取)。祝大家好运。 -
@shellter - 只是对您的评论发表评论 - 即使在较新的 unicies 中,标准输入的
-也非常方便。考虑:yadda | cat header.txt - footer.txt
标签: linux bash pipe anonymous-pipes