Bash / csh: Test für das Dateiende (EOF) von stdin

5779
Ole Tange

Ich möchte zu tun:

if not eof(stdin): pass stdin to program else: do nothing 

Ich habe das Gefühl, dass es ziemlich nahe an Folgendes geschrieben werden kann:

if test ! --is-eof - ; then exec program 

Das Problem, das ich zu lösen versuche, ist, dass es programvon stdin liest, aber abstürzt, wenn es keine Eingabe erhält. Ich habe keinen Zugriff auf die Quelle für die programso programnicht geändert werden kann. Die Binäreingabe ist größer als der Speicher, daher ist es inakzeptabel langsam, stdin zuerst in eine Datei zu setzen. Die zeilenweise Verarbeitung der Eingabe in der Bash ist inakzeptabel langsam.

Die Lösung sollte idealerweise unter csh und bash funktionieren.

2
Sie müssen einen Stream lesen, bevor Sie auf EOF testen können. Hört sich an, als hätten Sie ein schlecht entworfenes Skript. fpmurphy1 vor 11 Jahren 2
Nun, was ist das Programm, das abstürzt? Wäre es nicht besser zu versuchen, es nicht zum Absturz zu bringen? slhck vor 11 Jahren 0

5 Antworten auf die Frage

1
glenn jackman

Lesen Sie zuerst eine Zeile aus stdin:

IFS= read -r line if [[ -n "$line" ]]; then # the line is non-empty. # add the line back into the stream and pipe it into your program { echo "$line"; cat -; } | your_program fi 
Ihre Antwort schlägt fehl, wenn die erste Zeile der Eingabe eine leere Zeile ist. Ich empfehle `if IFS = read -r Zeile; dann ... Oder, wenn die Eingabe eine unvollständige Zeile sein könnte (zB "echo" Der schnelle braune Fuchs springt ... \ c "| OleTange.sh"), tun Sie "if IFS = read -r line ||" [[-n "$ line"]]; dann ... Scott vor 11 Jahren 0
Ich mag die Idee. Es gibt eine Begrenzung vor, dass \ n vor der Größe der Speichermenge an Daten bestehen muss, was suboptimal ist, aber möglicherweise eine akzeptable Begrenzung ist. Es scheint auch nicht zu funktionieren, wenn der erste \ 0 vor dem ersten \ n steht, was nicht akzeptabel ist, da die Eingabe binäre Daten ist. Beispiel: printf "abc \ 0def \ nghi \ njkl" | ob ... . Können wir "read" bitten, anstelle einer vollständigen Zeile eine Anzahl von Bytes (incl \ 0) zu lesen? Ole Tange vor 11 Jahren 0
"read -N 1" scheint zu helfen, schlägt jedoch fehl, wenn das erste Zeichen \ 0 ist. Ole Tange vor 11 Jahren 0
1
Ole Tange

Dies scheint sowohl in csh als auch in bash zu funktionieren und eignet sich gut für die Binäreingabe (auch \ 0 als erstes Zeichen):

# Set $_FIRST_CHAR_FILE to the name of a temp file. eval `echo $SHELL | grep -E "/(t)?csh" > /dev/null && echo setenv _FIRST_CHAR_FILE /tmp/$$.first_char_file || echo export _FIRST_CHAR_FILE=/tmp/$$.first_char_file`  dd bs=1 count=1 of=$_FIRST_CHAR_FILE >&/dev/null test -s "$_FIRST_CHAR_FILE" && ( cat $_FIRST_CHAR_FILE; rm $_FIRST_CHAR_FILE; cat - ) | program 

Danke an @ glenn-jackman für die Idee, etwas zu lesen, bevor Sie dies und den Rest von stdin durchgehen cat.

0
Kannan Mohan

Welche Art von Input erwartet Ihr Programm? Leiten Sie die Ausgabe von einem Programm zum anderen oder lesen Sie eine Datei?

Wenn Sie die Pipe-Umleitung zum Erfassen von Eingaben für Ihr Skript verwenden, wird die Ausführung so lange ausgeführt, bis die Eingabe bereitgestellt wird.

Wenn Sie versuchen, aus einer Datei zu lesen, verwenden Sie "while" oder "bis", um die Aufgabe auszuführen.

Dies sollte ein Kommentar zur Frage sein, keine Antwort glenn jackman vor 11 Jahren 0
@glenn: Ich stimme nicht zu. @M fragt eine Frage zu der Frage, um nur die Situationen zu beleuchten, in denen jede seiner beiden Antworten zutrifft. … //… Ich stimme zu, dass es keine gute Antwort ist, aber es ist eine Antwort. Scott vor 11 Jahren 0
0
vike

Ich poste hier, da diese nach oben kamen bei der Suche und da es mir geholfen, das Debuggen auf Darwin (Snow Leopard) bash in set -x;trap 'test -s /dev/stdin||exit' debugein Gespräch zu finden, die den geerbte Eingang des übergeordneten Skript verzehrte.

Für schwache Nerven:

if [[ -s /dev/fd/0 ]] then echo 'Not at EOF' else echo 'Currently no input to read' fi 

Prüfung:

echo $((echo|test -s /dev/stdin)&&! (true|test -s /dev/stdin)&&echo pass||echo fail) $ 

Der obige Test ergibt Folgendes in meinen bash-Versionen und -Systemen.

pass 4 2 45 2 release i386-apple-darwin10.8.0
pass 3 2 48 1 release x86_64-apple-darwin10.0
fail 4 2 37 1 release x86_64-pc-linux-gnu

Das Piping cat /proc/self/fdinfo/0auf mein Debian (Wheezy) gibt nichts zu testen.

CheerIO oder besser cheerEO für fehlerhaft / Output%)

Wäre wunderbar, wenn es allgemein klappen würde. Aber leider nicht: / dev / fd / * existiert nicht auf Hurd, Aix, HPux, Qnx, Tru64, Ultrix. / dev / stdin existiert nicht auf irix, aix, hpux, tru64, ultrix. Ole Tange vor 9 Jahren 0
0
Hachi

Wenn Sie nicht möchten, dass Ihr Skript bei dem Versuch blockiert, nach etwas zu suchen, das Sie lesen möchten, können Sie (zumindest in bash) einen Read mit Timeout verwenden

$ ( read -t 0 var ; echo $? ) 1  $ echo foo | ( read -t 0 var ; echo $? ) 0 

Dies garantiert jedoch nicht, dass Sie über EOF verfügen, dass Sie jedoch momentan nichts lesen können