Ich versuche, eine if
Anweisung zu schreiben, um zu testen, ob Dateien vorhanden sind, die einem bestimmten Muster entsprechen. Befindet sich eine Textdatei in einem Verzeichnis, sollte ein bestimmtes Skript ausgeführt werden.
Mein Code derzeit:
if [ -f /*.txt ]; then ./script fi
Bitte geben Sie einige Ideen; Ich möchte das Skript nur ausführen, wenn sich ein .txt
im Verzeichnis befindet.
shell-script
files
wildcards
test
user40952
quelle
quelle
/
? Außerdem fehlt Ihnen zuvor ein Semikolonfi
.find
wie hier beim Stackoverflow erläutert .Antworten:
würde nur dann true zurückgeben, wenn es eine (und nur eine) nicht ausgeblendete Datei gibt,
/
deren Name auf endet,.txt
und wenn diese Datei eine reguläre Datei oder ein Symlink zu einer regulären Datei ist.Das liegt daran, dass Platzhalter von der Shell erweitert werden, bevor sie an den Befehl übergeben werden (hier
[
).Also , wenn es eine ist
/a.txt
und/b.txt
,[
wird 5 Argumente übergeben werden:[
,-f
,/a.txt
,/b.txt
und]
.[
würde mich dann beschweren, dass-f
zu viele argumente vorgebracht werden.Wenn Sie überprüfen möchten, ob das
*.txt
Muster auf mindestens eine nicht ausgeblendete Datei erweitert wird (regulär oder nicht):shopt -s nullglob
istbash
spezifisch, aber Muscheln mögenksh93
,zsh
,yash
,tcsh
gleichwertige Aussagen.Beachten Sie, dass diese Dateien beim Lesen des Inhalts des Verzeichnisses gefunden werden. Es wird nicht versucht, auf diese Dateien zuzugreifen. Dies macht es effizienter als Lösungen, die Befehle wie
ls
oderstat
in dieser Liste von Dateien aufrufen , die von der Shell berechnet werden.Das Standardäquivalent
sh
wäre:Das Problem ist, dass bei Bourne- oder POSIX-Shells ein Muster, das nicht übereinstimmt, sich selbst erweitert. Wenn also
*.txt
erweitert wird*.txt
, wissen Sie nicht, ob es sich um eine.txt
Datei handelt, die nicht im Verzeichnis enthalten ist, oder um eine Datei, die aufgerufen wird*.txt
. Mit[*].txt *.txt
können Sie zwischen beiden unterscheiden.quelle
[ -f /*.txt ]
ist ziemlich schnell im Vergleich zucompgen
.[ -f /*.txt ]
wäre falsch, aber in meinem Test auf ein Verzeichnis, das3425
Dateien enthält ,94
von denen nicht versteckte txt-Dateien sind,compgen -G "*.txt" > /dev/null 2>&1
scheinen so schnell wieset -- *.txt; [ "$#" -gt 0 ]
(20,5 Sekunden für beide, wenn in meinem Fall 10000 Mal wiederholt).Sie könnten immer verwenden
find
:Erläuterung:
find .
: Suche im aktuellen Verzeichnis-maxdepth 1
: Nicht in Unterverzeichnissen suchen-type f
: Nur normale Dateien durchsuchenname "*.txt"
: Suche nach Dateien mit der Endung.txt
2>/dev/null
: Fehlermeldungen umleiten an/dev/null
| grep -q .
: grep für ein beliebiges Zeichen, gibt false zurück, wenn keine Zeichen gefunden wurden.&& ./script
:./script
Nur ausführen , wenn der vorherige Befehl erfolgreich war (&&
)quelle
find
Gibt nur false zurück, wenn beim Suchen nach Dateien Probleme auftreten, nicht, wenn keine Datei gefunden wird. Sie möchten die Ausgabe weiterleiten, umgrep -q .
zu überprüfen, ob etwas gefunden wird.chmod a-x .
.Eine mögliche Lösung ist auch Bash Builtin
compgen
. Dieser Befehl gibt alle möglichen Übereinstimmungen für ein globales Muster zurück und verfügt über einen Beendigungscode, der angibt, ob Dateien übereinstimmen.Ich habe diese Frage gefunden, als ich nach Lösungen gesucht habe, die allerdings schneller sind.
quelle
LC_ALL=C compgen -G "*.txt" > /dev/null
.Hier ist ein Einzeiler, um es zu tun:
Dateien existieren
Dateien existieren nicht
Dieser Ansatz nutzt die
||
&&
Operatoren und in bash verwendet. Dies sind die Operatoren "oder" und "und".Wenn also der Befehl stat den Wert
$?
0 zurückgibt , dann den erstenecho
aufgerufen. Wenn er den Wert 1 zurückgibt, wird der zweiteecho
aufgerufen.Rückgabe ergibt sich aus stat
Diese Frage wird beim Stackoverflow ausführlich behandelt:
quelle
stat
wennls -d
dies auch möglich ist?ls -d
liste ein verzeichnis auf? Schien nicht zu funktionieren, als ichls -d *.pl
zum Beispiel versucht habe, ein Verzeichnis mit Dateien darin aufzulisten .&&
durch ersetzen,ls *.txt
und es wird auch funktionieren./dev/null
Stellen Sie sicher, dass Sie stdout und stderr an senden, wie von @slm vorgeschlagen.ls *.txt
und es gibt keine Dateien innerhalb des Verzeichnisses wird dies eine Rückkehr$? = 2
, das wird noch Arbeit mit dem , wenn dann, aber das war einer meiner Gründe für die Wahlstat
überls
. Ich wollte eine 0 für den Erfolg und eine 1 für einen Misserfolg.ls -d
ist, Verzeichnisse anstelle ihres Inhalts aufzulisten. Alsols -d
macht daslstat
auf der Datei genauso wie GNUstat
. Welche Exit-Status-Befehle ungleich Null bei einem Fehler zurückkehren, ist systemspezifisch. Es macht wenig Sinn, Annahmen darüber zu treffen.Wie Chazelas betont, schlägt Ihr Skript fehl, wenn die Platzhaltererweiterung mehr als einer Datei entspricht.
Es gibt jedoch einen Trick, den ich benutze (auch wenn ich ihn nicht sehr mag ), um herumzukommen:
Wie es funktioniert?
Die Platzhaltererweiterung stimmt mit einer Reihe von Dateinamen überein, wir erhalten den ersten, wenn einige vorhanden sind, andernfalls null, wenn keine Übereinstimmung vorliegt.
quelle
.txt
Dateien, die vom Typ regulär sind . Versuchen Sie es zum Beispiel danachmkdir a.txt; mkfifo b.txt; echo regular > c.txt
.Einfach wie:
wc -l
zählt die Zeilen im erweiterten Platzhalter.quelle
ls
Ausgabe nicht analysieren und fast nie$?
direkt untersuchen, da diesif
bereits erfolgt. Auch die Verwendung von, umwc
zu sehen, ob etwas passiert ist, wird in ähnlicher Weise fehlgeleitet.Ich mag die vorherige Array-Lösung, aber das könnte bei einer großen Anzahl von Dateien zu Verschwendung führen - die Shell würde viel Speicher zum Erstellen des Arrays verwenden und nur das erste Element würde jemals getestet werden.
Hier ist eine alternative Struktur, die ich gestern getestet habe:
$ cd /etc; if [[ $(echo * | grep passwd) ]];then echo yes;else echo no;fi yes $ cd /etc; if [[ $(echo * | grep password) ]];then echo yes;else echo no;fi no
Der Exit-Wert von grep scheint den Pfad durch die Kontrollstruktur zu bestimmen. Dies wird auch mit regulären Ausdrücken und nicht mit Shell-Mustern getestet. Einige meiner Systeme verfügen über den Befehl "pcregrep", der komplexere Regex-Übereinstimmungen ermöglicht.
(Ich habe diese Antwort bearbeitet, um ein "ls" in der Befehlsersetzung zu entfernen, nachdem ich die obige Kritik zum Parsen gelesen habe.)
quelle
Wenn Sie eine if-Klausel verwenden möchten, werten Sie die Anzahl aus:
quelle