當「cat」逾時時,逾時會導致 while read 迴圈結束

當「cat」逾時時,逾時會導致 while read 迴圈結束

我無法辨別為什麼timeout函數呼叫會導致循環停止。我有一個“解決方案”,但我真的很好奇這是如何/為什麼會發生!這似乎與cat命令超時有關?

長話短說

while read -r line; do ... done < filetimeout當 a發生時終止cat,產生錯誤的輸出和退出代碼。循環確實不是循環遍歷文件中的每一行。

相反,如果首先在文件中的所有行中建立一個數組,然後...在 a 中執行,則所有行都會被處理,並且關於退出程式碼for line in "${all_lines[@]}"; do的輸出是正確的。timeout


假設腳本grade.sh打算讀取所有內容tests.txt並執行soln.sh,確保soln.sh終止。為了示範一個「工作」範例,soln.sh首先將sleep.

tests.txt

first
second
third
fourth
fifth

grade.sh

#!/usr/bin/env bash

while read -r line; do
    echo "Test: $line"
    output="$(timeout 2 ./soln.sh "$line")"
    timed_exit=$?
    echo "  Soln Output: $output"
    echo "  Timed exit:  $timed_exit"
done < "tests.txt"

soln.sh

#!/usr/bin/env bash
if [[ "$1" == "third" ]]; then
    sleep 3
fi
echo "[soln running $1]"

預期產出

Test: first
  Soln Output: [soln running first]
  Timed exit:  0
Test: second
  Soln Output: [soln running second]
  Timed exit:  0
Test: third
  Soln Output: 
  Timed exit:  124
Test: fourth
  Soln Output: [soln running fourth]
  Timed exit:  0
Test: fifth
  Soln Output: [soln running fifth]
  Timed exit:  0

如果我們改變soln做一些將永遠持續下去的事情(等待輸入),循環就會結束

soln.sh

#!/usr/bin/env bash
if [[ "$1" == "third" ]]; then
    cat $(find . -name iamnothere.txt) | wc -l
fi
echo "[soln running $1]"

輸出提前終止、額外的2、錯誤的exit程式碼

Test: first
  Soln Output: [soln running first]
  Timed exit:  0
Test: second
  Soln Output: [soln running second]
  Timed exit:  0
Test: third
  Soln Output: 2
[soln running third]
  Timed exit:  0

Hacky 修復方法是先循環遍歷每一行,然後使用for循環來繞過它。

“固定的”grade.sh

#!/usr/bin/env bash

all_lines=()
idx=0
while read -r line; do
    all_lines[idx]="$line"
    (( idx++ ))
done < "tests.txt"

for line in "${all_lines[@]}"; do
    echo "Test: $line"
    output="$(timeout 2 ./soln.sh "$line")"
    timed_exit=$?
    echo "  Soln Output: $output"
    echo "  Timed exit:  $timed_exit"
done

預期產出

Test: first
  Soln Output: [soln running first]
  Timed exit:  0
Test: second
  Soln Output: [soln running second]
  Timed exit:  0
Test: third
  Soln Output: 
  Timed exit:  124
Test: fourth
  Soln Output: [soln running fourth]
  Timed exit:  0
Test: fifth
  Soln Output: [soln running fifth]
  Timed exit:  0

這是一個功能還是一個錯誤,或者我錯過了什麼?

在我看來,這似乎cat是壓倒一切的timeout,因為腳本的其餘部分開始執行。

答案1

 cat $(find . -name iamnothere.txt) | wc -l

假設iamnothere.txt不存在則變為

cat | wc -l

它消耗標準輸入,while循環從中讀取行的相同標準輸入for透過不使用標準輸入來避免這種情況while。這可以透過對第二行情況使用 bare 來觀察cat,因為這表明第三行已被讀取cat

$ cat lines 
first
secon
third
$ cat looper 
#!/bin/sh
while read line; do
    x=$(timeout 2 ./doer "$line")
    echo "$line out=$x code=$?"
done < lines

$ cat doer 
#!/bin/sh
if [ "$1" = secon ]; then
    cat
else
    echo "$1 pid$$"
fi

$ ./looper 
first out=first pid42079 code=0
secon out=third code=0
$ 

相關內容