【问题标题】:ZSH: Output from stdout from within while read gets lostZSH:读取时从内部输出的标准输出丢失
【发布时间】:2021-07-17 15:59:41
【问题描述】:

我遇到了一个奇怪的 ZSH 问题。我已将脚本修剪为仍能重现该问题的最小形式。

我在这里模拟的是通过子进程监视目录的更改(实际脚本使用fswatch)。因为我正在监视,这意味着我无法事先运行命令并保存输出。一个(工作)示例如下:

(echo "text.txt"; echo "text.txt") | while read filepath; do scp "$filepath" "trip:~/tom/"; echo $?; done
text.txt                    100%  822    51.1KB/s   00:00
0
text.txt                    100%  822    99.1KB/s   00:00
0

现在,当我在中间添加延迟时,似乎任何延迟都比 while 循环内 scp 命令的运行时间长,突然第二个输出和 scp 的任何后续命令将不可见:

(echo "text.txt"; sleep 2; echo "text.txt") | while read filepath; do scp "$filepath" "trip:~/tom/"; echo $?; done
text.txt                    100%  822    51.1KB/s   00:00
0
0

有趣的是,echo 仍然有效,并且错误会像您预期的那样显示。

(echo "doesnotexist.txt"; sleep 2; echo "doesnotexist.txt") | while read filepath; do scp "$filepath" "trip:~/tom/"; echo $?; done
doesnotexist.txt: No such file or directory
1
doesnotexist.txt: No such file or directory
1

这里发生了什么?我希望有人能帮我解决这个问题。谢谢!

编辑:

经过一番折腾,这似乎与 ZSH 有关,因为它在普通的 bash-shell 中工作。

【问题讨论】:

  • 嗯,我无法重现这种行为。随着延迟,您可以在trip 上看到 scp 发生了吗?即,是否只是输出到缺少的 scp 的标准输出?最后,我看到了两个 scp 调用的输出,成功时就像失败时一样。
  • 也许我们需要更多详细信息:操作系统类型和版本、bash 版本、scp 版本等,以便有人可以尝试使用尽可能接近您的环境。
  • 我添加了更多信息。我自己也在另一台 linux 计算机上尝试过(基本上是在相反的方向执行此评论),确实(!)它按预期工作。
  • @KamilCuk,我尝试了你的建议:它给出了相同的结果。
  • @mihi 谢谢,我没有尝试过那个变种,我认为这是一个很好的解决方法。

标签: shell zsh


【解决方案1】:

在子shell 中运行整个while 循环没有问题。这似乎可行:

(echo "text.txt"; sleep 2; echo "text.txt") | (while read filepath; do scp "$filepath" "trip:~/tom/"; echo $?; done)

在 scp 源代码中的一些挖掘表明,不输出是由该检查返回 false 引起的:progressmeter.c#L81-L85

static int
can_output(void)
{
    return (getpgrp() == tcgetpgrp(STDOUT_FILENO));
}

(即 scp 进程的进程组 id 突然与“与 stdout 关联的终端上的前台进程组”不同)。

bash 和 zsh 之间的一个区别是 zsh 在主 shell 进程中运行 while 循环,而 bash 不运行(我从 here 收集到)。但这是我现在所能挖掘的。

【讨论】:

    猜你喜欢
    • 2014-08-28
    • 1970-01-01
    • 2016-10-02
    • 1970-01-01
    • 2012-09-25
    • 1970-01-01
    • 2014-07-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多