Ein Befehl gibt keine Zeichenfolge zurück (er gibt einen kleinen ganzzahligen Exit-Code zurück, normalerweise 0 für Erfolg und 1 oder 2 bei Fehler), kann jedoch einige Daten ausgeben , um eine Zeichenfolge einzugeben.
Basile Starynkevitch
@BasileStarynkevitch das ist das, was ich brauche. Ich weiß, Befehl gibt Exit-Code zurück. Aber meine Befehle Exit-Code ist immer 0. Also muss ich die Ausgabe steuern
Zuvor wurde gefragt, wie überprüft werden soll, ob sich Dateien in einem Verzeichnis befinden. Der folgende Code erreicht dies, aber siehe Antwort von rsp für eine bessere Lösung.
Ausgabe leeren
Befehle nicht zurückgeben Werte - sie geben sie. Sie können diese Ausgabe mithilfe der Befehlssubstitution erfassen . zB $(ls -A). Sie können in Bash wie folgt auf eine nicht leere Zeichenfolge testen:
if[[ $(ls -A)]];then
echo "there are files"else
echo "no files found"fi
Beachten Sie, dass ich -Aeher als verwendet habe -a, da die symbolischen Verzeichniseinträge current ( .) und parent ( ..) weggelassen werden.
Hinweis: Wie in den Kommentaren erwähnt, werden beim Ersetzen von Befehlen keine nachgestellten Zeilenumbrüche erfasst . Wenn der Befehl nur Zeilenumbrüche ausgibt , erfasst die Ersetzung daher nichts und der Test gibt false zurück. Dies ist im obigen Beispiel zwar sehr unwahrscheinlich, aber möglich, da ein einzelner Zeilenumbruch ein gültiger Dateiname ist! Weitere Informationen in dieser Antwort .
Code beenden
Wenn Sie überprüfen möchten, ob der Befehl erfolgreich ausgeführt wurde, können Sie überprüfen $?, welcher den Exit-Code des letzten Befehls enthält (Null für Erfolg, Nicht-Null für Fehler). Beispielsweise:
Sie können weglassen-n , so wird es nur seinif [[ $(ls -A) ]]; then
Benutzer
6
Diese Methode gibt false für Befehle aus, die nur Zeilenumbrüche ausgeben.
Ciro Santilli 18 冠状 病 六四 事件 18
89
TL; DR
if [[ $(ls -A | head -c1 | wc -c) -ne 0 ]]; then ...; fi
Vielen Dank an netj
für einen Vorschlag zur Verbesserung meines Originals: if [[ $(ls -A | wc -c) -ne 0 ]]; then ...; fi
Dies ist eine alte Frage, aber ich sehe mindestens zwei Dinge, die verbessert oder zumindest geklärt werden müssen.
Erstes Problem
Das erste Problem, das ich sehe, ist, dass die meisten der hier bereitgestellten Beispiele einfach nicht funktionieren . Sie verwenden die Befehle ls -alund ls -Al- beide geben nicht leere Zeichenfolgen in leeren Verzeichnissen aus. In diesen Beispielen wird immer angegeben , dass Dateien vorhanden sind, auch wenn keine vorhanden sind .
Aus diesem Grund sollten Sie nur ls -A- Warum sollte jemand den -lSchalter verwenden wollen, was "ein langes Listenformat verwenden" bedeutet, wenn Sie nur testen möchten, ob eine Ausgabe vorhanden ist oder nicht?
Die meisten Antworten hier sind also einfach falsch.
Zweites Problem
Das zweite Problem ist , dass , während einige Antworten gut funktionieren (diejenigen , die nicht verwendet werden ls -aloder ls -Alaber ls -Astattdessen) sie alle etwas tun:
Führen Sie einen Befehl aus
Puffern Sie die gesamte Ausgabe im RAM
Konvertieren Sie die Ausgabe in eine große einzeilige Zeichenfolge
Vergleichen Sie diese Zeichenfolge mit einer leeren Zeichenfolge
Was ich stattdessen vorschlagen würde, wäre:
Führen Sie einen Befehl aus
Zählen Sie die Zeichen in der Ausgabe, ohne sie zu speichern
oder noch besser - zähle die Anzahl von maximal 1 Zeichen using head -c1 (danke an netj für die Veröffentlichung dieser Idee in den Kommentaren unten)
Vergleiche diese Zahl mit Null
Also zum Beispiel anstelle von:
if[[ $(ls -A)]]
Ich würde ... benutzen:
if[[ $(ls -A | wc -c)-ne 0]]# or:if[[ $(ls -A | head -c1 | wc -c)-ne 0]]
[[ $(... | head -c | wc -c) -gt 0 ]]oder [[ -n $(... | head -c1) ]]sind besser, weil wc -cdie gesamte Ausgabe des Befehls verbrauchen müsste.
netj
@netj Das ist eine sehr gute Idee. Siehe meine aktualisierte Antwort - Ich habe Ihren Vorschlag hinzugefügt. Vielen Dank!
rsp
Irgendwelche Ideen, wie man die Ausgabe in den Griff bekommt?
fahrradflucht
Ich denke, das Original (ohne Kopf) ist im allgemeinen Fall besser. Es ist nicht immer eine gute Idee, den Befehl zu beenden, sobald er mit dem Schreiben der Ausgabe beginnt!
stk
@stk Die meisten Programme werden nach dem Empfang eines Kill-Signals sicher beendet.
Cambunctious
40
if[-z "$(ls -lA)"];then
echo "no files found"else
echo "There are files"fi
Dadurch wird der Befehl ausgeführt und geprüft, ob die zurückgegebene Ausgabe (Zeichenfolge) eine Länge von Null hat. Möglicherweise möchten Sie die 'Test'-Handbuchseiten auf andere Flags überprüfen .
Verwenden Sie das "" um das zu prüfende Argument, da sonst leere Ergebnisse zu einem Syntaxfehler führen, da kein zweites zu prüfendes Argument angegeben wird!
Hinweis: Das ls -lakehrt immer zurück .und ..daher funktioniert die Verwendung nicht, siehe ls Handbuchseiten . Obwohl dies bequem und einfach erscheinen mag, wird es wahrscheinlich leicht brechen. Das Schreiben eines kleinen Skripts / einer kleinen Anwendung, die je nach Ergebnis 0 oder 1 zurückgibt, ist viel zuverlässiger!
Sie könnten es vorziehen, $(anstelle von Backquote zu verwenden, weil $(Nest besser
Basile Starynkevitch
Sie haben Recht, es ist besser, sie immer zu verwenden, obwohl wir hier keine Verschachtelung benötigen.
Veger
23
Für diejenigen, die eine elegante, von der Bash-Version unabhängige Lösung suchen (die eigentlich in anderen modernen Shells funktionieren sollte) und für diejenigen, die gerne Einzeiler für schnelle Aufgaben verwenden. Auf geht's!
ls | grep .&& echo 'files found'|| echo 'files not found'
(Beachten Sie als einer der erwähnten Kommentare, ls -alund in der Tat, nur -lund -awerden alle etwas zurückgeben, so verwende ich in meiner Antwort einfachls
Wenn Sie grep -q ^stattdessen verwenden, werden auch Zeilenumbrüche abgeglichen, und grep druckt nichts in die Standardausgabe. Darüber hinaus wird es beendet, sobald eine Eingabe empfangen wird, anstatt auf das Ende seines Eingabestreams zu warten.
Dies funktioniert nicht: Der Befehl lswird nie ausgeführt. Sie prüfen nur, ob die Erweiterung der VariablenLS nicht leer ist.
gniourf_gniourf
1
@gniourf_gniourf - warum denkst du das? Die Backtick-Beschwörung ist zwar nicht so hübsch oder flexibel wie $ (), aber sie funktioniert ...
Tink
Der -aSwitch gibt niemals keinen Inhalt zurück (dh er gibt Inhalt zurück, unabhängig davon, ob Dateien vorhanden sind oder nicht), da immer das Implizite .und die ..Verzeichnisse vorhanden sind.
Wrlee
3
Hier ist eine Lösung für extremere Fälle:
if[`command | head -c1 | wc -c`-gt 0];then...;fi
Das wird funktionieren
für alle Bourne Muscheln;
wenn die Befehlsausgabe alle Nullen ist;
effizient unabhängig von der Ausgabegröße;
jedoch,
Der Befehl oder seine Unterprozesse werden beendet, sobald etwas ausgegeben wird.
Alle bisher gegebenen Antworten beziehen sich auf Befehle, die eine nicht leere Zeichenfolge beenden und ausgeben.
Die meisten sind in folgenden Sinnen gebrochen:
Sie behandeln Befehle, die nur Zeilenumbrüche ausgeben, nicht richtig.
Ab Bash≥4.4 werden die meisten Standardfehler als Spam versenden, wenn der Befehl null Bytes ausgibt (da sie die Befehlssubstitution verwenden).
Die meisten schlürfen den gesamten Ausgabestream und warten, bis der Befehl beendet ist, bevor sie antworten. Einige Befehle werden nie beendet (versuchen Sie es z yes. B. ).
Um all diese Probleme zu beheben und die folgende Frage effizient zu beantworten,
Wie kann ich testen, ob ein Befehl eine leere Zeichenfolge ausgibt?
Sie können auch eine Zeitüberschreitung hinzufügen, um zu testen, ob ein Befehl innerhalb einer bestimmten Zeit eine nicht leere Zeichenfolge ausgibt, indem Sie readdie -tOption 'verwenden. ZB für eine Zeitüberschreitung von 2,5 Sekunden:
Anmerkung. Wenn Sie der Meinung sind, dass Sie feststellen müssen, ob ein Befehl eine nicht leere Zeichenfolge ausgibt, liegt höchstwahrscheinlich ein XY-Problem vor.
Ich denke, diese Antwort wird eher unterschätzt. Ich war Leistungstests hier einige der Lösungen 100 Iterationen für jede der drei Eingangsszenarien ( seq 1 10000000, seq 1 20, und printf""). Das einzige Matchup, das dieser Leseansatz nicht gewann, war der -z "$(command)"Ansatz für eine leere Eingabe. Selbst dann verliert es nur um etwa 10-15%. Sie scheinen ausgeglichen zu sein seq 1 10. Unabhängig davon wird der -z "$(command)"Ansatz mit zunehmender Eingabegröße so langsam, dass ich ihn nicht für Eingaben mit variabler Größe verwenden würde.
Abathur
0
Hier ist ein alternativer Ansatz, bei dem std-out und std-err eines Befehls in eine temporäre Datei geschrieben und anschließend überprüft wird, ob diese Datei leer ist. Ein Vorteil dieses Ansatzes besteht darin, dass beide Ausgänge erfasst werden und keine Unterschalen oder Rohre verwendet werden. Diese letzteren Aspekte sind wichtig, da sie die Behandlung des Bash-Exit-Trapping beeinträchtigen können (z. B. hier ).
tmpfile=$(mktemp)
some-command &>"$tmpfile"if[[ $?!=0]];then
echo "Command failed"elif[[-s "$tmpfile"]];then
echo "Command generated output"else
echo "Command has no output"fi
rm -f "$tmpfile"
Manchmal möchten Sie die Ausgabe speichern, wenn sie nicht leer ist, um sie an einen anderen Befehl zu übergeben. Wenn ja, könnten Sie so etwas verwenden
list=`grep -l "MY_DESIRED_STRING" *.log `if[ $?-eq 0]then/bin/rm $list
fi
Auf diese Weise rmbleibt der Befehl nicht hängen, wenn die Liste leer ist.
ifne
. joeyh.name/code/moreutilsAntworten:
Zuvor wurde gefragt, wie überprüft werden soll, ob sich Dateien in einem Verzeichnis befinden. Der folgende Code erreicht dies, aber siehe Antwort von rsp für eine bessere Lösung.
Ausgabe leeren
Befehle nicht zurückgeben Werte - sie geben sie. Sie können diese Ausgabe mithilfe der Befehlssubstitution erfassen . zB
$(ls -A)
. Sie können in Bash wie folgt auf eine nicht leere Zeichenfolge testen:Beachten Sie, dass ich
-A
eher als verwendet habe-a
, da die symbolischen Verzeichniseinträge current (.
) und parent (..
) weggelassen werden.Hinweis: Wie in den Kommentaren erwähnt, werden beim Ersetzen von Befehlen keine nachgestellten Zeilenumbrüche erfasst . Wenn der Befehl nur Zeilenumbrüche ausgibt , erfasst die Ersetzung daher nichts und der Test gibt false zurück. Dies ist im obigen Beispiel zwar sehr unwahrscheinlich, aber möglich, da ein einzelner Zeilenumbruch ein gültiger Dateiname ist! Weitere Informationen in dieser Antwort .
Code beenden
Wenn Sie überprüfen möchten, ob der Befehl erfolgreich ausgeführt wurde, können Sie überprüfen
$?
, welcher den Exit-Code des letzten Befehls enthält (Null für Erfolg, Nicht-Null für Fehler). Beispielsweise:Mehr Infos hier .
quelle
-n
, so wird es nur seinif [[ $(ls -A) ]]; then
TL; DR
if [[ $(ls -A | head -c1 | wc -c) -ne 0 ]]; then ...; fi
Vielen Dank an netj für einen Vorschlag zur Verbesserung meines Originals:
if [[ $(ls -A | wc -c) -ne 0 ]]; then ...; fi
Dies ist eine alte Frage, aber ich sehe mindestens zwei Dinge, die verbessert oder zumindest geklärt werden müssen.
Erstes Problem
Das erste Problem, das ich sehe, ist, dass die meisten der hier bereitgestellten Beispiele einfach nicht funktionieren . Sie verwenden die Befehle
ls -al
undls -Al
- beide geben nicht leere Zeichenfolgen in leeren Verzeichnissen aus. In diesen Beispielen wird immer angegeben , dass Dateien vorhanden sind, auch wenn keine vorhanden sind .Aus diesem Grund sollten Sie nur
ls -A
- Warum sollte jemand den-l
Schalter verwenden wollen, was "ein langes Listenformat verwenden" bedeutet, wenn Sie nur testen möchten, ob eine Ausgabe vorhanden ist oder nicht?Die meisten Antworten hier sind also einfach falsch.
Zweites Problem
Das zweite Problem ist , dass , während einige Antworten gut funktionieren (diejenigen , die nicht verwendet werden
ls -al
oderls -Al
aberls -A
stattdessen) sie alle etwas tun:Was ich stattdessen vorschlagen würde, wäre:
using head -c1
(danke an netj für die Veröffentlichung dieser Idee in den Kommentaren unten)
Also zum Beispiel anstelle von:
Ich würde ... benutzen:
Anstatt:
Ich würde ... benutzen:
und so weiter.
Bei kleinen Ausgängen ist dies möglicherweise kein Problem, bei größeren Ausgängen kann der Unterschied jedoch erheblich sein:
Vergleichen Sie es mit:
Und noch besser:
Vollständiges Beispiel
Aktualisiertes Beispiel aus der Antwort von Will Vousden:
Nach Vorschlägen von netj erneut aktualisiert :
Zusätzliches Update von jakeonfire :
grep
wird mit einem Fehler beendet, wenn keine Übereinstimmung vorliegt. Wir können dies nutzen, um die Syntax etwas zu vereinfachen:Leerzeichen verwerfen
Wenn der zu testende Befehl ein Leerzeichen ausgeben könnte, das Sie als leere Zeichenfolge behandeln möchten, dann anstelle von:
Du könntest benutzen:
oder mit
head -c1
:oder etwas ähnliches.
Zusammenfassung
Verwenden Sie zunächst einen funktionierenden Befehl .
Vermeiden Sie zweitens unnötiges Speichern im RAM und die Verarbeitung potenziell großer Datenmengen.
In der Antwort wurde nicht angegeben, dass die Ausgabe immer klein ist, daher muss auch die Möglichkeit einer großen Ausgabe berücksichtigt werden.
quelle
[[ $(... | head -c | wc -c) -gt 0 ]]
oder[[ -n $(... | head -c1) ]]
sind besser, weilwc -c
die gesamte Ausgabe des Befehls verbrauchen müsste.Dadurch wird der Befehl ausgeführt und geprüft, ob die zurückgegebene Ausgabe (Zeichenfolge) eine Länge von Null hat. Möglicherweise möchten Sie die 'Test'-Handbuchseiten auf andere Flags überprüfen .
Verwenden Sie das "" um das zu prüfende Argument, da sonst leere Ergebnisse zu einem Syntaxfehler führen, da kein zweites zu prüfendes Argument angegeben wird!
Hinweis: Das
ls -la
kehrt immer zurück.
und..
daher funktioniert die Verwendung nicht, siehe ls Handbuchseiten . Obwohl dies bequem und einfach erscheinen mag, wird es wahrscheinlich leicht brechen. Das Schreiben eines kleinen Skripts / einer kleinen Anwendung, die je nach Ergebnis 0 oder 1 zurückgibt, ist viel zuverlässiger!quelle
$(
anstelle von Backquote zu verwenden, weil$(
Nest besserFür diejenigen, die eine elegante, von der Bash-Version unabhängige Lösung suchen (die eigentlich in anderen modernen Shells funktionieren sollte) und für diejenigen, die gerne Einzeiler für schnelle Aufgaben verwenden. Auf geht's!
(Beachten Sie als einer der erwähnten Kommentare,
ls -al
und in der Tat, nur-l
und-a
werden alle etwas zurückgeben, so verwende ich in meiner Antwort einfachls
quelle
grep -q ^
stattdessen verwenden, werden auch Zeilenumbrüche abgeglichen, und grep druckt nichts in die Standardausgabe. Darüber hinaus wird es beendet, sobald eine Eingabe empfangen wird, anstatt auf das Ende seines Eingabestreams zu warten.ls -A
wenn SieBash Referenzhandbuch
6.4 Bedingte Bash-Ausdrücke
Sie können die Kurzversion verwenden:
quelle
string
ein Synonym für ist-n string
.Wie Jon Lin kommentierte,
ls -al
wird immer (für.
und..
) ausgegeben . Sie möchtenls -Al
diese beiden Verzeichnisse vermeiden.Sie können beispielsweise die Ausgabe des Befehls in eine Shell-Variable einfügen:
Eine ältere, nicht verschachtelbare Notation ist
aber ich bevorzuge die nestbare Notation
$(
...)
Sie können testen, ob diese Variable nicht leer ist
Und Sie könnten beide als kombinieren
if [ -n "$(ls -Al)" ]; then
quelle
Ich vermute, Sie möchten die Ausgabe des
ls -al
Befehls, also hätten Sie in bash so etwas wie:quelle
ls
wird nie ausgeführt. Sie prüfen nur, ob die Erweiterung der VariablenLS
nicht leer ist.-a
Switch gibt niemals keinen Inhalt zurück (dh er gibt Inhalt zurück, unabhängig davon, ob Dateien vorhanden sind oder nicht), da immer das Implizite.
und die..
Verzeichnisse vorhanden sind.Hier ist eine Lösung für extremere Fälle:
Das wird funktionieren
jedoch,
quelle
Alle bisher gegebenen Antworten beziehen sich auf Befehle, die eine nicht leere Zeichenfolge beenden und ausgeben.
Die meisten sind in folgenden Sinnen gebrochen:
yes
. B. ).Um all diese Probleme zu beheben und die folgende Frage effizient zu beantworten,
Sie können verwenden:
Sie können auch eine Zeitüberschreitung hinzufügen, um zu testen, ob ein Befehl innerhalb einer bestimmten Zeit eine nicht leere Zeichenfolge ausgibt, indem Sie
read
die-t
Option 'verwenden. ZB für eine Zeitüberschreitung von 2,5 Sekunden:Anmerkung. Wenn Sie der Meinung sind, dass Sie feststellen müssen, ob ein Befehl eine nicht leere Zeichenfolge ausgibt, liegt höchstwahrscheinlich ein XY-Problem vor.
quelle
seq 1 10000000
,seq 1 20
, undprintf""
). Das einzige Matchup, das dieser Leseansatz nicht gewann, war der-z "$(command)"
Ansatz für eine leere Eingabe. Selbst dann verliert es nur um etwa 10-15%. Sie scheinen ausgeglichen zu seinseq 1 10
. Unabhängig davon wird der-z "$(command)"
Ansatz mit zunehmender Eingabegröße so langsam, dass ich ihn nicht für Eingaben mit variabler Größe verwenden würde.Hier ist ein alternativer Ansatz, bei dem std-out und std-err eines Befehls in eine temporäre Datei geschrieben und anschließend überprüft wird, ob diese Datei leer ist. Ein Vorteil dieses Ansatzes besteht darin, dass beide Ausgänge erfasst werden und keine Unterschalen oder Rohre verwendet werden. Diese letzteren Aspekte sind wichtig, da sie die Behandlung des Bash-Exit-Trapping beeinträchtigen können (z. B. hier ).
quelle
Manchmal möchten Sie die Ausgabe speichern, wenn sie nicht leer ist, um sie an einen anderen Befehl zu übergeben. Wenn ja, könnten Sie so etwas verwenden
Auf diese Weise
rm
bleibt der Befehl nicht hängen, wenn die Liste leer ist.quelle