Shell-Skript, um zu überprüfen, ob Datei vorhanden ist
Ich versuche zu schreiben ein einfaches Skript, das wird mir sagen, ob ein Dateiname existiert in $Temp, beginnt mit der Zeichenfolge "Test".
Beispielsweise, ich habe diese Dateien
Test1989.txt
Test1990.txt
Test1991.txt
Dann will ich einfach nur echo, dass eine Datei gefunden wurde.
Beispielsweise so etwas wie dieses:
file="home/edward/bank1/fiche/Test*"
if test -s "$file"
then
echo "found one"
else
echo "found none"
fi
Aber das funktioniert nicht.
- Die Frage gibt "shell" -- welche? Die Antwort halte ich für die beste hier ist bash-spezifisch, ist das angemessen, oder sind Sie targeting etwas anderes?
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ein Ansatz:
Erklärung:
shopt -s nullglob
verursachen/home/edward/bank1/fiche/Test*
zu erweitern, um nichts wenn keine Datei entspricht diesem Muster. (Ohne Sie, es wird intakt gelassen werden.)( ... )
setzt eine subshell, die Verhinderungshopt -s nullglob
von "Flucht".files=(/home/edward/bank1/fiche/Test*)
legt die Datei-Liste in einem array mit dem Namenfiles
. (Beachten Sie, dass dies innerhalb der subshell nur;files
wird nicht zugänglich sein, nachdem die subshell beendet.)"${#files[@]}"
ist die Anzahl der Elemente in diesem array.Bearbeitet-Adresse anschließende Frage ("Was ist, wenn ich auch brauchen, um zu überprüfen, dass diese Dateien haben, Daten, die in Ihnen und sind nicht null-byte-Dateien"):
In dieser version, brauchen wir
-s
(wie Sie es in Ihrer Frage), die auch tests für die Datei Existenz, also hat es keinen Sinn mitshopt -s nullglob
mehr: wenn keine Datei mit dem Muster entspricht, dann-s
auf das Muster wird falsch sein. Wir können also schreiben:(Hier die
( ... )
ist, um zu verhindern, dassfile
undfound_file
von "Flucht".)for file in "${files[@]}"
fork()
. Wenn das Ziel ist die Vermeidung umweltbelastender globalen namespace, erstellen einer Funktion und Verwendung von einheimischen ausreichen würde.Müssen Sie verstehen, wie Unix interpretiert Sie Ihre Eingabe.
Den standard-Unix-shell interpoliert Umgebungsvariablen, und was sind sogenannte Einheiten vor der übergabe der Parameter an Ihr Programm. Das ist ein bisschen anders als Windows, die das Programm interpretieren die expansion.
Versuchen Sie dies:
Diesem echo alle Dateien und Verzeichnisse im aktuellen Verzeichnis. Vor der
echo
Befehl wirkt die shell interpoliert die*
an und erweitert es, dann übergibt Sie diese erweiterten parameter wieder auf Ihren Befehl. Sehen Sie es in Aktion, dies zu tun:Den
set -xv
schaltet xtrace und ausführliche. Ausführliche hallt der Befehl eingegeben wurde, und xtrace echos der Befehl, der ausgeführt wird (das heißt, nach der shell-expansion).Nun versuchen, diese:
Beachten Sie, dass wenn man etwas in Anführungszeichen versteckt, die glob Ausdruck aus der Schale, und die Schale kann nicht erweitern. Versuchen Sie dies:
Beachten Sie, dass die Schale lässt sich noch erweitern-Umgebung Variablen innerhalb von doppelten Anführungszeichen, nicht jedoch in einfachen Anführungszeichen.
Nun schauen wir uns deine Aussage:
Den Anführungszeichen verhindern, dass die Schale aus dem ausbau der glob Ausdruck, so
file
ist gleich dem literalhome/edward/bank1/finche/Test*
. Daher müssen Sie, um dies zu tun:Den Mangel an Zitaten (und die einleitenden slash ist wichtig!) nun stellen Sie die Datei gleich alle Dateien, passen Sie den Ausdruck. (Es kann auch mehr als eine!). Wenn es keine Dateien, je nach der shell, und seine Einstellungen, die Schale kann einfach die Datei in das Zeichenfolgenliteral sowieso.
Du hast ganz sicher die richtige Idee:
Allerdings, könnten Sie noch bekommen keine gefunden zurückgegeben, wenn es mehr als eine Datei. Stattdessen erhalten Sie möglicherweise eine Fehlermeldung in Ihrem
test
Befehl, da gibt es zu viele Parameter.Eine Möglichkeit, dies zu umgehen, könnten sein:
In diesem Fall, ich bin unter Ausnutzung der exit-code des
ls
Befehl. Wennls
findet, eine Datei zugreifen kann, gibt es eine null exit-code. Wenn Sie nicht finden können, eine passende Datei, es gibt einen nicht-null exit-code. Dieif
Befehl lediglich einen Befehl ausführt, und dann, wenn der Befehl gibt null zurück, es übernimmt dieif
- Anweisung als wahr und führt dieif
- Klausel. Wenn der Befehl gibt einen Wert ungleich null, derif
- Anweisung wird angenommen, dass Sie falsch sind, und dieelse
- Klausel (falls vorhanden) ausgeführt wird.Den
test
Befehl arbeitet auf ähnliche Weise. Wenn dietest
ist wahr, dietest
Befehl gibt zurück ein null. Ansonsten, dietest
- Befehl gibt einen Wert ungleich null. Dies funktioniert hervorragend mit derif
Befehl. In der Tat, es gibt eine alias dertest
Befehl. Versuchen Sie dies:Den
i
druckt die inode. Die inode wird die echte ID der Datei. Dateien mit der gleichen ID die gleiche Datei. Sie können sehen, dass/bin/test
und/bin/[
sind Sie den gleichen Befehl. Dies macht die folgenden zwei Befehle die gleiche:Können Sie tun es in einer Zeile:
Zu verstehen, was es tut, müssen Sie zerlegen den Befehl und haben ein grundlegendes Bewusstsein der booleschen Logik.
Direkt von der bash man-page:
In der shell (und im Allgemeinen in der unix-Welt), die boolean true ist, dass ein Programm beendet mit dem status 0.
ls
versucht, um eine Liste der Muster, wenn es gelingt, (im Sinne der Muster vorhanden ist) beendet mit status 0, 2 sonst (siehe ls man-Seite für details).In unserem Fall sind es tatsächlich 3 Ausdrücke für den sake der Klarheit ich will Klammern, obwohl Sie sind nicht erforderlich, da
&&
hat Vorrang auf||
:also, wenn Ausdruck1 true ist (sprich:
ls
fand das Muster) Sie bewertet, expression2 ist (das ist nur ein echo und wird beendet mit status 0). In diesem Fall expression3 wird nie bewerten, weil das, was auf der linken Seite||
ist schon wahr, und es wäre eine Verschwendung von Ressourcen, zu versuchen zu beurteilen, was auf der rechten Seite.Sonst, wenn Ausdruck1 falsch ist, Ausdruck2 wird nicht ausgewertet, sondern in diesem Fall expression3 wird.
ls
ist ein externes Programm, anstatt eine shell integriert, so dass die Berufung auf Sie Gabeln. Die shell-check für Dateien ohne Rückgriff auf jeden externe Programme -- glob Ausdrücke, nachdem alle, tun Sie das. Auchls
verbringt die Zeit-und CPU-Sortieren der Argumente, drucken Sie (wenn auch nur/dev/null
); etc.Dem folgenden Skript wird u helfen, zu gehen zu einem Prozess, wenn das Skript existiert in einer angegebenen variable,
hier
-e
ist für die Arbeit mit Dateien,$1
ist eine shell-variable,schlafen für 10 Minuten
u können, führen Sie das Skript aus, indem Sie
./waitfor.csh ./temp ; echo "the file exits"
One-liner zu überprüfen, Datei existieren oder nicht -
Wildcards sind nicht erweitert, innen-quoted strings. Und wenn Platzhalter erweitert wird, wird es unverändert zurückgegeben, wenn es keine Spiele, es nicht Sie in eine leere Zeichenfolge. Versuchen:
Wenn der Platzhalter erweitert, um Dateinamen
ls
Liste Sie aufstdout
; sonst gibt es einen Fehler aufstderr
, und nichts auf die Standardausgabe ausgegeben. Der Inhaltstdout
zugeordnet sindoutput
.if [ -n "$output" ]
tests, ob$output
enthält alles.Einem anderen Weg zu schreiben, wäre dies:
test -n <string>
ist wahr, wenn<string>
ist nicht leer.ls
hier funktioniert nicht ordnungsgemäß, wenn es mehr als eine passende Datei. Besser einen glob Ausdruck. Siehe auch mywiki.wooledge.org/BashFAQ/004ls
erzeugte keine Ausgabe oder nicht, wir prüfen nicht, ob es eine tatsächliche Dateiname. Ich habe mich verändert die variable name weniger irreführend.[ -e "$output" ]
, nicht-n
. Ja, das wird Arbeit... aber es ist unnötig ineffizient. Warum ein externes tool (genannt in einer subshell!) generiert sortiert, formatiert die Ausgabe für den menschlichen Verzehr, wenn Sie nur wissen wollen, ob eine Datei existiert? Sie können die Aufzeichnung der Ausgabe von einem glob Ausdruck in einem array mit keine Gabel überhaupt-und in der shell hat zu laufen, dass glob-Ausdruck zum erstellen der argument-Liste fürls
, es ist also eine echte Teilmenge des overhead.