Timeout führt dazu, dass die while-read-Schleife beendet wird, wenn die Zeit für „cat“ abgelaufen ist

Timeout führt dazu, dass die while-read-Schleife beendet wird, wenn die Zeit für „cat“ abgelaufen ist

Ich kann nicht erkennen, warum timeoutbei einem Funktionsaufruf eine Schleife angehalten wird. Ich habe eine „Lösung“, aber ich bin wirklich sehr neugierig, wie/warum das passiert! Es scheint etwas damit zu tun zu haben, dass catder Befehl eine Zeitüberschreitung erfährt?

Kurz zusammengefasst

while read -r line; do ... done < filewird beendet, wenn ein timeoutauftritt cat, was zu einer falschen Ausgabe und einem falschen Exit-Code führt. Die Schleifenichtdurchläuft jede Zeile in der Datei.

Wenn stattdessen zuerst ein Array aus allen Zeilen der Datei erstellt und anschließend ...in einem ausgeführt wird for line in "${all_lines[@]}"; do, werden alle Zeilen verarbeitet und die Ausgabe von timeouthinsichtlich der Exitcodes ist korrekt.


Angenommen, das Skript grade.shsoll alles lesen tests.txtund ausführen soln.shund sicherstellen, dass soln.shes beendet wird. Um ein „funktionierendes“ Beispiel zu demonstrieren, soln.shwerden wir zuerst 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]"

erwartete Ausgabe

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

Wenn wir solnetwas tun, das ewig andauert (auf Eingabe warten), endet die Schleife stattdessen

soln.sh

#!/usr/bin/env bash
if [[ "$1" == "third" ]]; then
    cat $(find . -name iamnothere.txt) | wc -l
fi
echo "[soln running $1]"

Ausgabe bricht vorzeitig ab, zusätzlicher 2, falscher exitCode

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

Die Hack-Lösung besteht darin, zuerst jede Zeile zu durchlaufen und eine forSchleife zu verwenden, die dies umgeht.

"Fest"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

erwartete Ausgabe

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

ist das ein Feature oder ein Fehler oder übersehe ich etwas?

Es scheint mir, als catwürde es irgendwie außer Kraft gesetzt timeout, da der Rest des Skripts ausgeführt wird.

Antwort1

 cat $(find . -name iamnothere.txt) | wc -l

vorausgesetzt, dass iamnothere.txtes nicht existiert, wird

cat | wc -l

die Standardeingabe verbraucht,dieselbe Standardeingabe, whilevon der die Schleife die Zeilen liest. forvermeidet dies, indem es nicht die Standardeingabe verwendet, wie whiledies der Fall ist. Dies kann beobachtet werden, indem man für den Fall der zweiten Zeile ein Leerzeichen verwendet cat, da dies zeigt, dass die dritte Zeile von diesem gelesen wurde 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
$ 

verwandte Informationen