No puedo discernir por qué timeout
una llamada a una función provocará la detención de un bucle. Tengo una "solución", pero estoy realmente muy intrigado sobre cómo y por qué sucede esto. ¿Parece tener algo que ver con cat
que se agote el tiempo de espera del comando?
TL;DR
while read -r line; do ... done < file
termina cuando timeout
ocurre a cat
, lo que produce una salida y un código de salida incorrectos. El bucle hacenorecorre cada línea del archivo.
Si, en cambio, se crea una matriz primero que todas las líneas del archivo y luego ...
se ejecuta en un archivo for line in "${all_lines[@]}"; do
, se procesan todas las líneas y la salida timeout
con respecto a los códigos de salida es correcta.
Supongamos que el script grade.sh
tiene la intención de leer todo tests.txt
y ejecutarlo soln.sh
, asegurándose de que soln.sh
finalice. Para demostrar un ejemplo "funcional", soln.sh
primero 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]"
Rendimiento 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
Si cambiamos soln
para hacer algo que continuará para siempre (esperando entrada), el ciclo termina.
soln.sh
#!/usr/bin/env bash
if [[ "$1" == "third" ]]; then
cat $(find . -name iamnothere.txt) | wc -l
fi
echo "[soln running $1]"
la salida termina antes de tiempo, código adicional 2
incorrectoexit
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
La solución Hacky es recorrer primero cada línea y usar un for
bucle que lo omitirá.
"fijado"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
Rendimiento 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
¿Es esto una característica o un error o me falta algo?
Me parece que cat
de alguna manera es primordial timeout
, ya que el resto del script se ejecuta.
Respuesta1
cat $(find . -name iamnothere.txt) | wc -l
asumir que iamnothere.txt
no existe se convierte
cat | wc -l
que consume entrada estándar,la misma entrada estándar desde la que el while
bucle lee las líneas. for
evita esto al no utilizar la entrada estándar como while
lo hace. Esto se puede observar usando un cat
caso simple para la segunda línea, ya que esto muestra que la tercera línea ha sido leída por 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
$