我無法辨別為什麼timeout
函數呼叫會導致循環停止。我有一個“解決方案”,但我真的很好奇這是如何/為什麼會發生!這似乎與cat
命令超時有關?
長話短說
while read -r line; do ... done < file
timeout
當 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
$