Die folgende ifnotemptyFunktion leitet ihre Eingabe an den als Argument übergebenen Befehl weiter, außer dass sie nichts tut, wenn die Eingabe leer ist. Verwenden , um es Rohr source --fooin sink --bardurch Schreiben source --foo | pipe_if_not_empty sink --bar.
Ich würde erwarten, dass diese Implementierung auf allen POSIX / Unix-Plattformen funktioniert, obwohl sie streng genommen nicht standardkonform ist: Sie basiert darauf, dass nicht ddmehr als das Byte gelesen wird, das über die Standardeingabe gelesen werden soll.
Ich denke, head -c 1wäre ein geeigneter Ersatz für dd bs=1 count=1 2>/dev/nullLinux.
Auf der anderen Seite head -n 1wäre dies nicht geeignet, da headnormalerweise die Eingabe zwischengespeichert wird und möglicherweise mehr als die Zeile gelesen wird, die ausgegeben wird. Da die Daten aus einer Pipe gelesen werden, gehen nur die zusätzlichen Bytes verloren.
read -r headund sind auch read -r -n 1 headhier nicht geeignet, da, wenn das erste Zeichen eine neue Zeile ist, headauf die leere Zeichenkette gesetzt würde, was es unmöglich macht, zwischen leerer Eingabe und Eingabe, die mit einer leeren Zeile beginnt, zu unterscheiden.
Wir können nicht einfach schreiben, head=$(head -c 1)denn wenn das erste Zeichen eine neue Zeile ist, wird durch die Befehlsersetzung die letzte neue Zeile entfernt, wodurch es unmöglich wird, zwischen leerer Eingabe und Eingabe zu unterscheiden, die mit einer leeren Zeile beginnt.
In bash, ksh oder zsh können Sie catdurch </dev/stdineine mikroskopische Leistungssteigerung ersetzen .
Wenn es Ihnen nichts ausmacht, die gesamten Zwischendaten im Speicher abzulegen, ist hier eine etwas einfachere Implementierung von pipe_if_not_empty.
Hier ist eine etwas einfachere Implementierung mit den folgenden Einschränkungen:
Die von der Quelle erzeugten Daten gelten nur dann als leer, wenn sie ausschließlich aus Zeilenumbrüchen bestehen. (Dies kann in der Tat wünschenswert sein.)
Die in die Senke eingegebenen Daten enden mit genau einem Zeilenumbruchzeichen, unabhängig davon, mit wie vielen Zeilenumbrüchen die von der Quelle erzeugten Daten enden. (Dies könnte ein Problem sein.)
Auch hier werden die gesamten Daten im Speicher gespeichert.
$ echo -e "\n\n"| xargs -r ls
$ # No output. ls did not run.
$ echo -e "\n\n1"| xargs -r ls
ls: cannot access 1:No such file or directory
Es ist einfach, aber es sollte für Sie funktionieren. Wenn Ihre "a-Funktion" eine leere Zeichenfolge oder sogar eine neue Zeile in der Pipeline sendet, verhindert xargs -r den Durchgang zu "einer anderen Funktion".
Genau das macht ifne (1) von moreutils . Moreutils ist zumindest in Debian und Ubuntu als Paket verfügbar, wahrscheinlich auch in anderen Distributionen.
Die folgende Funktion versucht, das erste Byte zu lesen, und bei Erfolg wird dieses Byte wiedergegeben, und der Rest wird übertragen. Sollte effizient und 100% portabel sein.
Diese Funktion schlägt bei mir beim Laufen fehl echo -en "\nX" | pipe_if_not_empty mail -s "Subject line here" [email protected]. Es denkt, dass lineund herebeide Empfänger der E-Mail sind, keine Token im Betreff. Ich muss dem entkommen" dem Thema , damit es funktioniert. Die pipe_if_not_emptyFunktion aus der akzeptierten Antwort funktioniert jedoch auch für mich, ohne etwas zu umgehen.
Kuzzooroo
2
Zumindest funktioniert so etwas:
yourcommand | if [ $(wc -c) -gt "0" ]; then yourothercommand; fi
Beachten Sie, dass bei den obigen Anweisungen Zeilenumbrüche und andere Sonderzeichen als Ausgabe betrachtet werden. Daher wird eine leere Zeile an die if-Anweisung übergeben und als Ausgabe betrachtet. Erhöhen Sie einfach das -gt-Limit, wenn Ihre Ausgabe normalerweise höher als 1 Byte sein soll :)
Antworten:
Die folgende
ifnotempty
Funktion leitet ihre Eingabe an den als Argument übergebenen Befehl weiter, außer dass sie nichts tut, wenn die Eingabe leer ist. Verwenden , um es Rohrsource --foo
insink --bar
durch Schreibensource --foo | pipe_if_not_empty sink --bar
.Konstruktionshinweise:
dd
mehr als das Byte gelesen wird, das über die Standardeingabe gelesen werden soll.head -c 1
wäre ein geeigneter Ersatz fürdd bs=1 count=1 2>/dev/null
Linux.head -n 1
wäre dies nicht geeignet, dahead
normalerweise die Eingabe zwischengespeichert wird und möglicherweise mehr als die Zeile gelesen wird, die ausgegeben wird. Da die Daten aus einer Pipe gelesen werden, gehen nur die zusätzlichen Bytes verloren.read -r head
und sind auchread -r -n 1 head
hier nicht geeignet, da, wenn das erste Zeichen eine neue Zeile ist,head
auf die leere Zeichenkette gesetzt würde, was es unmöglich macht, zwischen leerer Eingabe und Eingabe, die mit einer leeren Zeile beginnt, zu unterscheiden.head=$(head -c 1)
denn wenn das erste Zeichen eine neue Zeile ist, wird durch die Befehlsersetzung die letzte neue Zeile entfernt, wodurch es unmöglich wird, zwischen leerer Eingabe und Eingabe zu unterscheiden, die mit einer leeren Zeile beginnt.cat
durch</dev/stdin
eine mikroskopische Leistungssteigerung ersetzen .Wenn es Ihnen nichts ausmacht, die gesamten Zwischendaten im Speicher abzulegen, ist hier eine etwas einfachere Implementierung von
pipe_if_not_empty
.Hier ist eine etwas einfachere Implementierung mit den folgenden Einschränkungen:
Auch hier werden die gesamten Daten im Speicher gespeichert.
quelle
Dies sollte für Sie arbeiten
Ein Beispiel
Es ist einfach, aber es sollte für Sie funktionieren. Wenn Ihre "a-Funktion" eine leere Zeichenfolge oder sogar eine neue Zeile in der Pipeline sendet, verhindert xargs -r den Durchgang zu "einer anderen Funktion".
Referenz für xargs: http://www.oreillynet.com/linux/cmd/cmd.csp?path=x/xargs
quelle
Genau das macht ifne (1) von moreutils . Moreutils ist zumindest in Debian und Ubuntu als Paket verfügbar, wahrscheinlich auch in anderen Distributionen.
quelle
Die folgende Funktion versucht, das erste Byte zu lesen, und bei Erfolg wird dieses Byte wiedergegeben, und der Rest wird übertragen. Sollte effizient und 100% portabel sein.
Testfälle:
quelle
echo -en "\nX" | pipe_if_not_empty mail -s "Subject line here" [email protected]
. Es denkt, dassline
undhere
beide Empfänger der E-Mail sind, keine Token im Betreff. Ich muss dem entkommen"
dem Thema , damit es funktioniert. Diepipe_if_not_empty
Funktion aus der akzeptierten Antwort funktioniert jedoch auch für mich, ohne etwas zu umgehen.Zumindest funktioniert so etwas:
yourcommand | if [ $(wc -c) -gt "0" ]; then yourothercommand; fi
Beachten Sie, dass bei den obigen Anweisungen Zeilenumbrüche und andere Sonderzeichen als Ausgabe betrachtet werden. Daher wird eine leere Zeile an die if-Anweisung übergeben und als Ausgabe betrachtet. Erhöhen Sie einfach das -gt-Limit, wenn Ihre Ausgabe normalerweise höher als 1 Byte sein soll :)
quelle
yourothercommand
sieht nie die Ausgabe vonyourcommand
.Anstelle von
sender | receiver
:Oder Sie könnten es allgemeiner machen, indem Sie es ändern, um das empfangende Programm als Argument zu akzeptieren, wie in Gilles 'Antwort:
quelle