当“cat”超时时,超时会导致 while read 循环结束

当“cat”超时时,超时会导致 while read 循环结束

我无法辨别为什么timeout函数调用会导致循环停止。我有一个“解决方案”,但我真的很好奇这是如何/为什么会发生!这似乎与cat命令超时有关?

长话短说

while read -r line; do ... done < filetimeout当 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
$ 

相关内容