我无法辨别为什么timeout
函数调用会导致循环停止。我有一个“解决方案”,但我真的很好奇这是如何/为什么会发生!这似乎与cat
命令超时有关?
长话短说
while read -r line; do ... done < file
timeout
当 a发生时被终止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
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
$