
Hat jemand eine Shell-Skript-Vorlage, um etwas mit ls
einer Liste von Verzeichnisnamen zu tun, jeden einzelnen zu durchlaufen und etwas zu tun?
Ich habe vor, ls -1d */
die Liste der Verzeichnisnamen abzurufen.
Antwort1
Bearbeitet, um kein ls zu verwenden, wo ein Glob ausreichen würde, wie @shawn-j-goff und andere vorgeschlagen haben.
Verwenden Sie einfach eine for..do..done
Schleife:
for f in *; do
echo "File -> $f"
done
Sie können es *
durch *.txt
oder jeden anderen Glob ersetzen, der eine Liste (von Dateien, Verzeichnissen oder was auch immer) zurückgibt, einen Befehl, der eine Liste generiert, z. B. $(cat filelist.txt)
, oder es tatsächlich durch eine Liste ersetzen.
Innerhalb der do
Schleife verweisen Sie einfach mit dem Dollarzeichen als Präfix auf die Schleifenvariable (so $f
im obigen Beispiel). Sie können echo
damit machen, was Sie wollen.
.xml
So können Sie beispielsweise alle Dateien im aktuellen Verzeichnis wie folgt umbenennen .txt
:
for x in *.xml; do
t=$(echo $x | sed 's/\.xml$/.txt/');
mv $x $t && echo "moved $x -> $t"
done
Oder noch besser: Wenn Sie Bash verwenden, können Sie Bash-Parametererweiterungen verwenden, anstatt eine Subshell zu erzeugen:
for x in *.xml; do
t=${x%.xml}.txt
mv $x $t && echo "moved $x -> $t"
done
Antwort2
Die Ausgabe von ls
zum Abrufen von Dateinamen zu verwenden, ist keine gute Idee. Dies kann zu Fehlfunktionen und sogar gefährlichen Skripten führen. Dies liegt daran, dass ein Dateiname jedes beliebige Zeichen außer /
und enthalten kann null
und ls
keines dieser Zeichen als Trennzeichen verwendet. Wenn ein Dateiname also ein Leerzeichen oder eine neue Zeile enthält,Willeerhalten Sie unerwartete Ergebnisse.
Es gibt zwei sehr gute Möglichkeiten, über Dateien zu iterieren. Hier habe ich einfach echo
demonstriert, wie man mit dem Dateinamen etwas macht; Sie können jedoch alles andere verwenden.
Die erste besteht darin, die nativen Globbing-Funktionen der Shell zu verwenden.
for dir in */; do
echo "$dir"
done
Die Shell erweitert die Datei */
in einzelne Argumente, die von der for
Schleife gelesen werden. Auch wenn der Dateiname ein Leerzeichen, eine neue Zeile oder ein anderes seltsames Zeichen enthält, for
wird jeder vollständige Name als atomare Einheit betrachtet. Die Liste wird in keiner Weise analysiert.
Wenn Sie rekursiv in Unterverzeichnisse gehen möchten, ist dies nicht möglich, es sei denn, Ihre Shell verfügt über erweiterte Globbing-Funktionen (wie beispielsweise ) bash
. globstar
Wenn Ihre Shell diese Funktionen nicht hat oder Sie sicherstellen möchten, dass Ihr Skript auf einer Vielzahl von Systemen funktioniert, besteht die nächste Option in der Verwendung von find
.
find . -type d -exec echo '{}' \;
Hier find
wird der Befehl aufgerufen echo
und ihm als Argument der Dateiname übergeben. Dies geschieht einmal für jede gefundene Datei. Wie im vorherigen Beispiel wird keine Liste von Dateinamen analysiert; stattdessen wird ein vollständiger Dateiname als Argument gesendet.
Die Syntax des -exec
Arguments sieht etwas komisch aus. find
nimmt das erste Argument nach -exec
und behandelt das als das auszuführende Programm und jedes nachfolgende Argument nimmt es als Argument, das an dieses Programm übergeben wird. Es gibt zwei spezielle Argumente, die -exec
gesehen werden müssen. Das erste ist {}
; dieses Argument wird durch einen Dateinamen ersetzt, den die vorherigen Teile von find
generiert haben. Das zweite ist ;
, das mitteilt, dass find
dies das Ende der Liste der an das Programm zu übergebenden Argumente ist; find
benötigt dies, weil Sie mit weiteren Argumenten fortfahren können, die find
für das ausgeführte Programm bestimmt sind und nicht. Der Grund dafür \
ist, dass die Shell auch speziell behandelt ;
– es stellt das Ende eines Befehls dar, also müssen wir es maskieren, damit die Shell es als Argument an übergibt, anstatt find
es für sich selbst zu verwenden; eine andere Möglichkeit, die Shell dazu zu bringen, es nicht speziell zu behandeln, besteht darin, es in Anführungszeichen zu setzen: funktioniert für diesen Zweck ';'
genauso gut wie .\;
Antwort3
Bei Dateien, die Leerzeichen enthalten, müssen Sie darauf achten, die Variable wie folgt in Anführungszeichen zu setzen:
for i in $(ls); do echo "$i"; done;
oder Sie können die Umgebungsvariable „Eingabefeldtrennzeichen“ (IFS) ändern:
(IFS=$'\n';for i in $(ls); do echo $i; done) # subshell to restore IFS
Abhängig davon, was Sie tun, benötigen Sie das LS möglicherweise nicht einmal:
for i in *; do echo "$i"; done;
Antwort4
Als Ergänzung zur Antwort von CoverosGene gibt es hier eine Möglichkeit, nur die Verzeichnisnamen aufzulisten:
for f in */; do
echo "Directory -> $f"
done