timeout
関数呼び出しでループが停止する理由がわかりません。 「解決策」はありますが、なぜこのようなことが起こるのか、とても興味があります。cat
コマンドがタイムアウトになったことと関係があるようです。
要約
while read -r line; do ... done < file
timeout
は で が発生したときに終了しcat
、間違った出力と終了コードを生成します。ループはないファイル内のすべての行をループします。
代わりに、最初にファイル内のすべての行の配列を作成し、次に...
で実行すると、すべての行が処理され、終了コードに関する の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
ハッキーな修正方法は、まずすべての行をループし、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
。これは、2 行目の場合に bare を使用すると確認できますcat
。これは、3 行目がによって読み取られたことを示しています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
$