对于喜欢这些东西的人来说,这是一个 bash shell 场景。假设您有这样的脚本:
#!/bin/bash 读者 |作家
…并且“读取器”失败并且没有产生数据,然后“写入器”运行并向数据库系统写入一个漂亮的空白。然后,这会导致各种有趣的时光。
因此,这被用作编写那些可怕的公司中断公告之一的机会,该公告更多地是关于兜售公司的商品,而不是找出问题的根源。而且,其中的关键是“我们忘记了 pipefail”。
就像,你忘记的远不止这些。 pipefail 不会阻止第二件事的运行。严重地。它仍然会运行。只是看看。
让我在这里介绍一下我们的角色。首先,我们有“作家”:
#!/bin/bash echo "作者正在读取标准输入" 猫>输出 echo "writer 读完标准输入" ls -l 输出
它既简单又愚蠢:它打招呼,吸入数据,然后告诉我们它得到了什么。它模拟了您在这种情况下所拥有的任何“从 EOF 读取标准输入”。
接下来,这里是“工作的阅读器”:
#!/bin/bash echo "这里有一些数据。"
这个很好很容易。
现在这是它的伙伴,即将失败(并退出 1)的“阅读器失败”:
#!/bin/bash 1号出口
那里没有惊喜。现在,我们有了一个脚本,它可以模拟名为“run-good”的快乐路径:
#!/bin/bash 设置-o pipefail ./reader-that-works | 。/作家
最后,模拟不愉快路径的脚本称为“run-bad”:
#!/bin/bash 设置-o pipefail ./读者失败 | 。/作家
请注意,这两个运行器都已启用 pipefail。
让我们走幸福的道路。
/tmp/duh:$ ./run-good 作家正在阅读标准输入 writer 读完标准输入 -rw-r--r-- 1 rkroll rkroll 18 Apr 5 13:51 输出 /tmp/duh:$ 猫输出 这是一些数据。 /tmp/duh:$
好的,那么,现在是另一个:
/tmp/duh:$ ./run-bad 作家正在阅读标准输入 writer 读完标准输入 -rw-r--r-- 1 rkroll rkroll 0 Apr 5 13:52 输出
这是什么?管道的第二部分仍然运行?当然是的。它在阅读器失败时*已经在运行*。它的标准输入连接到另一个标准输出,Unix 蜈蚣风格。它*必须已经在那里运行*,否则阅读器无法在所有情况下运行!它会填充其标准输出的管道,然后它会阻塞。
这不是 MS-DOS,其中 foo | bar 涉及运行 foo,将输出发送到临时文件,然后运行 bar 并从同一个临时文件中获取输入。这里有并行执行,如果只涉及两个进程,则中止管道为时已晚。
这是人们关于“成为外壳”并试图了解它是如何做的事情的“面试问题”之一。他们在这些采访中向人们提出的一个问题是为什么你不希望有一个 shell 命令来 grep 文件中的某些内容,然后同时写回同一个文件。
也就是说,像这样(不要这样做):
grep -v 噪音 my_file > my_file
您认为“这将从文件中删除’噪音’。就像…它将…排序…通过从文件中删除 *everything*!shell 将愉快地打开 my_file 进行写入作为设置的一部分为子进程建立执行环境,并将破坏那里的任何东西。
…
而且,你知道吗,最糟糕的是,这些知识都不应该适用。事实上,我们正在谈论一些关键的shell 脚本,这意味着可靠性之战很久以前就失败了。