Zsh

頭部完成時中止 curl,xargs 管道中的先前步驟

  • February 6, 2022

我正在嘗試下載一堆網頁,一旦我下載了 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. 當它執行時:

  1. 在第一次迭代時,shell 將第一個值讀入 line,然後執行 curl;curl(獲取並)輸出網頁,其中head -n2提取前兩行並退出,關閉第二部分和第三部分之間的管道。它出現在您的範例 curl 將此輸出寫入至少兩個塊,因此它在第二次寫入時出錯並失敗,即以非零狀態退出。
  2. 當一個命令失敗時,shell 不會終止大多數命令序列(包括複合命令),因為 shell 經常以互動方式使用,並且每次執行任何命令時讓 shell 當機迫使您重新登錄並重新開始都會非常不方便錯誤執行任何程序。
  3. 因此,shell 將第二個值讀入 line 並執行第二個 curl,由於管道關閉,它立即失敗,但 shell 再次繼續並讀取第三行並執行第三個 curl,依此類推,直到輸入結束導致read失敗;因為read在 的 list-1 部分while,它的失敗會導致循環終止。

您可以使用以下命令顯式測試 curl 是否失敗(然後終止):

generate_values | while read -n line && curl ...$line; do :; done | head -n2

或者您可以設置一個 shell 選項,使其失敗時終止:

generate_values | { set -e; while read -n line; do curl ...$line; done } | head -n2

請注意,這兩種方法都可能會執行一次,因為 curl 僅在管道關閉後(即在最後一個塊之後)寫入時報告錯誤。如果您的輸出限制 ( head -n$n) 在 curl #2 的最後一個輸出塊期間用盡,則該 curl 將退出“成功”並且 shell 將啟動 curl #3,這將在其第一次(或唯一一次)寫入時失敗。

引用自:https://unix.stackexchange.com/questions/689454