Dokumente sind in einem Dateisystem gespeichert, das "tägliche" Verzeichnisse enthält, z.B. 20050610. In einem Bash-Skript möchte ich die Dateien in einem Monat im Wert dieser Verzeichnisse auflisten. Daher führe ich einen Find-Befehl aus find /200506* -type f >> jun2005.lst
. Möchte überprüfen, dass dieses Verzeichnisset nicht null ist, bevor ich den Find-Befehl ausführe. Wenn ich jedoch if[ -d 200506* ]
verwende, erhalte ich einen "zu viele Argumente" Fehler. Wie kann ich das umgehen?
Antworten
Zu viele Anzeigen?Ihr "zu viele Argumente" Fehler kommt nicht daher, dass es eine riesige Anzahl von Dateien gibt und das Limit für Befehlszeilenargumente überschritten wird. Es kommt daher, dass mehr als ein oder zwei Verzeichnisse mit dem Glob übereinstimmen. Ihr Glob "200506*" erweitert sich zu etwas wie "20050601 20050602 20050603..." und der -d
Test erwartet nur ein Argument.
$ mkdir test
$ cd test
$ mkdir a1
$ [ -d a* ] # kein Fehler
$ mkdir a2
$ [ -d a* ]
-bash: [: a1: binärer Operator erwartet
$ mkdir a3
$ [ -d a* ]
-bash: [: zu viele Argumente
Die Antwort von zed_0xff ist auf dem richtigen Weg, aber ich würde einen anderen Ansatz verwenden:
shopt -s nullglob
path='/pfad/zu/verzeichnissen'
glob='200506*/'
outfile='jun2005.lst'
dirs=("$path"/$glob) # dirs ist ein Array, das bei Bedarf iteriert werden kann
if (( ${#dirs[@]} > 0 ))
then
echo "Verzeichnisse gefunden"
# append ist hier möglicherweise nicht notwendig
find "$path"/$glob -type f >> "$outfile"
fi
Die Position der Anführungszeichen in "$path"/$glob
gegenüber "$path/$glob"
ist entscheidend dafür, dass dies funktioniert.
Bearbeitung:
Korrekturen wurden vorgenommen, um Dateien auszuschließen, die dem Glob entsprechen (so dass nur Verzeichnisse eingeschlossen sind) und um mit dem sehr ungewöhnlichen Fall eines Verzeichnisses umzugehen, das buchstäblich wie der Glob benannt ist ("200506*").
S=200506*
if [ ${#S} -gt 6 ]; then
echo haz filez!
else
echo no filez
fi
Keine sehr elegante, aber ohne externe Hilfsmittel/Befehle (wenn "[" nicht als extern angesehen wird)
Der Hinweis ist, dass, wenn einige Dateien übereinstimmen, die "S"-Variable deren Namen mit Leerzeichen getrennt enthält. Andernfalls enthält es den String "200506*" selbst.
Weil es in den meisten Shells eine Begrenzung der Befehlszeilenlänge gibt: Alles wie "$(ls -d | grep 200506)" oder /path/200506* läuft Gefahr, die Grenze zu überschreiten. Ich bin mir nicht sicher, ob Substitutionen und Globus-Erweiterungen in BASH dazu zählen, aber ich vermute es. Sie müssten es testen und die Bash-Dokumentation und den Quellcode überprüfen, um sicher zu gehen.
Die Antwort liegt in der Vereinfachung Ihrer Frage.
find /200506* -type f -exec somescript '{}' \;
Wo somescript ein Shell-Skript ist, das den Test durchführt. Vielleicht etwas wie folgt:
#!/bin/sh
[ -d "$@" ] && echo "$@" >> june2005.lst
Das Übergeben der june2005.lst an das Skript (Rat: Verwenden Sie eine Umgebungsvariable) und der Umgang mit der Möglichkeit, dass sich 200506* zu einem zu großen Dateipfad ausweiten kann, bleibt als Übung für den OP ;)
Die Integration des gesamten Vorgangs in eine Pipeline oder die Anpassung einer allgemeineren Skriptsprache würde Leistungssteigerungen bringen, indem die Anzahl der gestarteten Shells minimiert wird. Das wäre spaßig. Hier ist ein Hinweis dazu, verwenden Sie -exec und ein anderes Programm (awk, perl, etc.), um den Verzeichnistest als Teil eines Einzeilers zu machen, und behalten Sie das >>june2005.lst in dem find-Befehl bei.