Wie kann ich testen, ob ein Befehl eine leere Zeichenkette ausgibt?
Antworten
Zu viele Anzeigen?Zuvor wurde die Frage gestellt, wie man prüfen kann, ob sich Dateien in einem Verzeichnis befinden. Der folgende Code erfüllt diese Aufgabe, aber siehe <a href="https://stackoverflow.com/a/35165216/58635">rsp's Antwort </a>für eine bessere Lösung.
Leere Ausgabe
Befehle sind nicht return Werte - sie geben sie aus. Sie können diese Ausgabe erfassen, indem Sie Befehlsersetzung ; z.B.. $(ls -A)
. Sie können in der Bash wie folgt auf eine nicht leere Zeichenkette testen:
if [[ $(ls -A) ]]; then
echo "there are files"
else
echo "no files found"
fi
Beachten Sie, dass ich -A
statt -a
da sie den symbolischen Strom auslässt ( .
) und Eltern ( ..
) Verzeichniseinträge.
Anmerkung: Wie in den Kommentaren erwähnt, ist die Befehlssubstitution erfasst keine nachgestellten Zeilenumbrüche . Wenn der Befehl also Folgendes ausgibt seulement Zeilenumbrüche, wird die Ersetzung nichts erfassen und der Test wird falsch zurückgeben. Obwohl dies sehr unwahrscheinlich ist, ist es im obigen Beispiel möglich, da ein einzelner Zeilenumbruch ein gültiger Dateiname ist! Weitere Informationen unter diese Antwort .
Exit-Code
Wenn Sie überprüfen möchten, ob der Befehl erfolgreich abgeschlossen wurde, können Sie die $?
der den Exit-Code des letzten Befehls enthält (Null für Erfolg, ungleich Null für Misserfolg). Zum Beispiel:
files=$(ls -A)
if [[ $? != 0 ]]; then
echo "Command failed."
elif [[ $files ]]; then
echo "Files found."
else
echo "No files found."
fi
Mehr Infos aquí .
TL;DR
if [[ $(ls -A | head -c1 | wc -c) -ne 0 ]]; then ...; fi
Dank an netj um 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 angeführten Beispiele einfach nicht funktionieren . Sie verwenden die ls -al
y ls -Al
Befehle - beide geben nicht leere Zeichenketten in leeren Verzeichnissen aus. Diese Beispiele immer melden, dass es Dateien gibt auch wenn es keine gibt .
Aus diesem Grund sollten Sie nur ls -A
- Warum sollte jemand die -l
Schalter, der "ein langes Auflistungsformat verwenden" bedeutet, wenn Sie ohnehin nur testen wollen, ob es eine Ausgabe gibt oder nicht?
Die meisten Antworten hier sind also schlichtweg falsch.
Zweites Problem
Das zweite Problem ist, dass die algunos Antworten funktionieren gut (diejenigen, die nicht verwenden. ls -al
o ls -Al
sondern ls -A
stattdessen) machen sie alle etwas Ähnliches:
- einen Befehl ausführen
- seine gesamte Ausgabe im RAM puffern
- die Ausgabe in eine große einzeilige Zeichenkette umwandeln
- diese Zeichenkette mit einer leeren Zeichenkette vergleichen
Was ich stattdessen vorschlagen würde, wäre:
- einen Befehl ausführen
- die Zeichen in seiner Ausgabe zählen, ohne sie zu speichern
- oder noch besser - zählen Sie die Anzahl der maximal 1 Zeichen
using head -c1
(Dank an netj für die Veröffentlichung dieser Idee in den Kommentaren unten)
- oder noch besser - zählen Sie die Anzahl der maximal 1 Zeichen
- diese Zahl mit Null zu vergleichen
Also zum Beispiel, anstatt von:
if [[ $(ls -A) ]]
Ich würde verwenden:
if [[ $(ls -A | wc -c) -ne 0 ]]
# or:
if [[ $(ls -A | head -c1 | wc -c) -ne 0 ]]
Anstelle von:
if [ -z "$(ls -lA)" ]
Ich würde verwenden:
if [ $(ls -lA | wc -c) -eq 0 ]
# or:
if [ $(ls -lA | head -c1 | wc -c) -eq 0 ]
und so weiter.
Bei kleinen Leistungen mag das kein Problem sein, aber bei größeren Leistungen kann der Unterschied erheblich sein:
$ time [ -z "$(seq 1 10000000)" ]
real 0m2.703s
user 0m2.485s
sys 0m0.347s
Vergleichen Sie es mit:
$ time [ $(seq 1 10000000 | wc -c) -eq 0 ]
real 0m0.128s
user 0m0.081s
sys 0m0.105s
Und noch besser:
$ time [ $(seq 1 10000000 | head -c1 | wc -c) -eq 0 ]
real 0m0.004s
user 0m0.000s
sys 0m0.007s
Vollständiges Beispiel
Aktualisiertes Beispiel aus der Antwort von Will Vousden:
if [[ $(ls -A | wc -c) -ne 0 ]]; then
echo "there are files"
else
echo "no files found"
fi
Erneut aktualisiert nach Vorschlägen von netj :
if [[ $(ls -A | head -c1 | wc -c) -ne 0 ]]; then
echo "there are files"
else
echo "no files found"
fi
Zusätzliche Aktualisierung durch jakeonfire :
grep
wird mit einem Fehler beendet, wenn es keine Übereinstimmung gibt. Wir können dies ausnutzen, um die Syntax etwas zu vereinfachen:
if ls -A | head -c1 | grep -E '.'; then
echo "there are files"
fi
if ! ls -A | head -c1 | grep -E '.'; then
echo "no files found"
fi
Whitespace verwerfen
Wenn der Befehl, den Sie testen, ein Leerzeichen ausgeben könnte, das Sie als leere Zeichenkette behandeln wollen, dann können Sie anstelle von:
| wc -c
können Sie verwenden:
| tr -d ' \n\r\t ' | wc -c
oder mit head -c1
:
| tr -d ' \n\r\t ' | head -c1 | wc -c
oder so ähnlich.
Zusammenfassung
-
Verwenden Sie zunächst einen Befehl, der Werke .
-
Zweitens: Vermeiden Sie die unnötige Speicherung im RAM und die Verarbeitung potenziell großer Datenmengen.
In der Antwort wurde nicht angegeben, dass der Output immer klein ist, so dass auch die Möglichkeit eines großen Outputs in Betracht gezogen werden muss.
if [ -z "$(ls -lA)" ]; then
echo "no files found"
else
echo "There are files"
fi
Damit wird der Befehl ausgeführt und geprüft, ob die zurückgegebene Ausgabe (Zeichenkette) eine Länge von Null hat. Vielleicht möchten Sie die Test"-Handbuchseiten für andere Flaggen.
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 ist!
Anmerkung: dass ls -la
gibt immer zurück .
y ..
also wird das nicht funktionieren, siehe ls Handbuchseiten . Auch wenn dies bequem und einfach zu sein scheint, wird es vermutlich leicht zu Problemen führen. Ein kleines Skript/Anwendung zu schreiben, die je nach Ergebnis 0 oder 1 zurückgibt, ist viel zuverlässiger!
Für diejenigen, die eine elegante, von der Bash-Version unabhängige Lösung suchen (sollte auch in anderen modernen Shells funktionieren) und diejenigen, die gerne Einzeiler für schnelle Aufgaben verwenden. Los geht's!
ls | grep . && echo 'files found' || echo 'files not found'
(Anmerkung, wie in einem der Kommentare erwähnt, ls -al
und in der Tat, nur -l
y -a
werden alle etwas zurückgeben, daher verwende ich in meiner Antwort einfache ls
6.4 Bash Bedingte Ausdrücke
-z string
True if the length of string is zero.
-n string
string
True if the length of string is non-zero.
Sie können eine Kurzfassung verwenden:
if [[ $(ls -A) ]]; then
echo "there are files"
else
echo "no files found"
fi
- See previous answers
- Weitere Antworten anzeigen