Não consigo discernir por que timeout
uma chamada de função fará com que um loop pare. Eu tenho uma "solução", mas estou realmente muito intrigado em saber como/por que isso está acontecendo! Parece ter algo a ver com cat
o tempo limite do comando expirar?
DR
while read -r line; do ... done < file
é encerrado quando timeout
ocorre on cat
, produzindo a saída e o código de saída incorretos. O loop faznãopercorrer cada linha do arquivo.
Se, em vez disso, uma matriz for criada primeiro de todas as linhas do arquivo e depois ...
executada em a for line in "${all_lines[@]}"; do
, todas as linhas serão processadas e a saída de timeout
em relação aos códigos de saída estará correta.
Suponha que o script grade.sh
pretenda ler tudo tests.txt
e executar soln.sh
, certificando-se de que soln.sh
termine. Para demonstrar um exemplo "funcional", soln.sh
primeiro 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]"
resultado esperado
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
Se mudarmos soln
para fazer algo que continuará para sempre (aguardando entrada), o loop terminará
soln.sh
#!/usr/bin/env bash
if [[ "$1" == "third" ]]; then
cat $(find . -name iamnothere.txt) | wc -l
fi
echo "[soln running $1]"
a saída termina antecipadamente, código extra 2
e erradoexit
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
A solução hacky é percorrer cada linha primeiro e usar um for
loop que irá contornar isso.
"fixo"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
resultado esperado
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
isso é um recurso ou um bug ou estou faltando alguma coisa?
Parece-me que cat
é de alguma forma predominante timeout
, já que o restante do script é executado.
Responder1
cat $(find . -name iamnothere.txt) | wc -l
assumir que iamnothere.txt
não existe torna-se
cat | wc -l
que consome entrada padrão,a mesma entrada padrão da qual o while
loop está lendo as linhas. for
evita isso não usando entrada padrão como while
faz. Isso pode ser observado usando um bare cat
para o caso da segunda linha, pois mostra que a terceira linha foi lida por aquele 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
$