我正在尝试下载一堆网页,一旦我下载了 N 行 html,我希望整个事情停止。但相反,管道中的先前步骤继续进行。查看问题的示例:
for i in /accessories /aches-pains /allergy-hayfever /baby-child /beauty-skincare; do echo $i; sleep 2; done | \
while read -r line; do curl "https://www.medino.com$line"; done \
| head -n 2
现在,我希望它发出一个请求,然后中止。
但是发生的事情是这样的:
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0<!DOCTYPE html>
<html lang="en" >
100 4412 0 4412 0 0 12788 0 --:--:-- --:--:-- --:--:-- 12751
curl: (23) Failed writing body (0 != 2358)
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 2358 0 2358 0 0 3772 0 --:--:-- --:--:-- --:--:-- 3766
curl: (23) Failed writing body (0 != 2358)
( ^ repeats 4 times)
为什么脚本没有立即中止,而是继续运行?我不是管道上的超级专家,所以感觉我在这里缺少一些基本的东西。
管道的第二部分是
while read -r line; do curl ...$line; done
. 当它运行时:在第一次迭代时,shell 将第一个值读入 line,然后运行 curl;curl(获取并)输出网页,其中
head -n2
提取前两行并退出,关闭第二部分和第三部分之间的管道。它出现在您的示例 curl 将此输出写入至少两个块,因此它在第二次写入时出错并失败,即以非零状态退出。当一个命令失败时,shell 不会终止大多数命令序列(包括复合命令),因为 shell 经常以交互方式使用,并且每次执行任何命令时让你的 shell 死掉迫使你重新登录并重新开始都是非常不方便的错误运行任何程序。
因此,shell 将第二个值读入 line 并运行第二个 curl,由于管道关闭,它立即失败,但 shell 再次继续并读取第三行并运行第三个 curl,依此类推,直到输入结束导致
read
失败;因为read
在 的 list-1 部分while
,它的失败会导致循环终止。您可以使用以下命令显式测试 curl 是否失败(然后终止):
或者您可以设置一个 shell 选项,使其在失败时终止:
请注意,这两种方法可能会运行一次,因为 curl 仅在管道关闭后(即最后一个块之后)写入时报告错误。如果您的输出限制 (
head -n$n
) 在 curl #2 的最后一个输出块期间用尽,则该 curl 将退出“成功”并且 shell 将启动 curl #3,这将在其第一次(或唯一一次)写入时失败。