【问题标题】:Bash Anonymous PipesBash 匿名管道
【发布时间】: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


【解决方案1】:

当您使用<( ... ) 进行进程替换时,内部运行的进程没有控制终端。但是pv 总是向终端显示它的结果;如果没有,它就会停止。

如果您执行您的代码,并在运行时执行ps axf,您将看到如下内容:

23412 pts/16   S      0:00  \_ bash
24255 pts/16   S+     0:00      \_ cat /dev/zero
24256 pts/16   S+     0:00      \_ tee /dev/fd/63
24258 pts/16   S      0:00      |   \_ bash
24259 pts/16   T      0:00      |       \_ pv -c
24257 pts/16   S+     0:00      \_ pv -c

...告诉您在进程替换中执行的pv -c(第二个bash 下面的那个)处于T 状态,已停止。它正在等待有一个控制终端才能运行。它没有任何数据,因此它将永远停止,bash 最终会停止向该管道发送数据。

【讨论】:

  • mhm - 好的,我理解对于 () 完全相反 - 通过匿名管道将输出从外壳重定向到内壳。换句话说, /dev/fd/63 不应该是停止 pv 的自动输入吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-07-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多