【问题标题】:stdout and stderr are out-of-order when a bash script is run from Atom从 Atom 运行 bash 脚本时,stdout 和 stderr 出现故障
【发布时间】:2021-06-16 16:08:54
【问题描述】:

我尝试编写一个小程序来列出一个不存在的目录并在 .sh 文件中完成回显:

#!/bin/bash
ls notexist
echo 'done'

但我的控制台输出在第一行完成,在错误消息列出不存在的目录之前:

done
ls: notexist: No such file or directory

我认为 bash 不会为每一行代码自动创建一个线程,是吗?我在 macOS Big Sur 中使用终端。

编辑:我从 macOS Big Sur 中 Atom 文本编辑器的 script 包间接访问终端。如果我通过./file.sh 直接在控制台中运行代码,错误就会消失。

【问题讨论】:

  • Bash 自己不会这样做,但是如果您的 stdout 和 stderr 不是同一个 fd 的副本(因为它们不是副本相同的文件描述符,操作系统不保证它们将被刷新的顺序)。
  • ...例如,如果您运行exec > >(tee stdout.log) 2> >(tee stderr.log >&2),则会创建允许此错误的条件。同样,如果运行此脚本时其 stdout 和 stderr 以不同的方式通过管道传输。
  • 要明确:操作仍按顺序运行;上面创建的问题是输出的写入顺序,(当 stdout 和 stderr 不去同一个地方时)不能保证与实际发生的顺序相同。
  • 导致问题的另一种方法是将标准输出通过管道传输到less,在这种情况下,您的脚本可能能够在标准输出被读取之前写入其标准错误,然后写入终端, less.
  • @chepner, ...尽管这将在相反的方向重新排序;在这里,我们在 stderr 之前显示了 stdout。

标签: bash atom-editor


【解决方案1】:

如果我们查看the Atom script plugin的源代码,问题就很清楚了:

它创建一个BufferedProcess带有单独的 stdout 和 stderr 回调(使用它们来确定是否任何输出已写入这些流中的每一个)。

实现这一点需要将 stdout 和 stderr 定向到不同的 FIFO。这意味着,与典型的终端不同,其中内容被写入到 stdout 和 stderr 同时共享的单个 FIFO 中的绝对顺序,没有严格保证内容将以相同的顺序通过这些函数进行处理写好了。


作为一种解决方法,您可以在脚本中exec 2>&1 将所有内容放在标准输出上,或exec >&2 将所有内容放在标准错误上。理想情况下,如果script 插件不需要单独跟踪两个流,它会自己执行此操作,并仅在所有内容已重定向到的单个流上放置回调。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-03-09
    • 2010-11-28
    • 1970-01-01
    • 1970-01-01
    • 2021-08-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多