it-swarm.com.de

durchlaufen von ls führt zu einem Bash-Shell-Skript

Hat jemand ein Template-Shell-Skript, um etwas mit ls für eine Liste von Verzeichnisnamen zu tun und sich durch jedes zu drehen und etwas zu tun?

Ich plane, ls -1d */ zu machen, um die Liste der Verzeichnisnamen zu erhalten.

87
Daniel A. White

Bearbeitet, um nicht ls zu verwenden, wo ein Glob tun würde, wie @ Shawn-J-Goff und andere vorgeschlagen.

Benutze einfach eine for..do..done Schleife:

for f in *; do
  echo "File -> $f"
done

Sie können den * durch *.txt oder einen beliebigen anderen Globus ersetzen, der eine Liste (von Dateien, Verzeichnissen oder Ähnlichem) zurückgibt, einen Befehl, der eine Liste generiert, z. B. $(cat filelist.txt), oder ihn tatsächlich durch eine Liste ersetzen.

In der do-Schleife verweisen Sie einfach auf die Schleifenvariable mit dem Dollarzeichen-Präfix (im obigen Beispiel also $f). Sie können echo es oder irgendetwas anderes damit machen, was Sie wollen.

Um beispielsweise alle .xml-Dateien im aktuellen Verzeichnis in .txt umzubenennen, gehen Sie wie folgt vor:

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
100
CoverosGene

Die Ausgabe von ls zu verwenden, um Dateinamen zu erhalten, ist eine schlechte Idee . Dies kann zu Fehlfunktionen und sogar zu gefährlichen Skripten führen. Dies liegt daran, dass ein Dateiname jedes Zeichen außer / und dem Zeichen null enthalten kann und ls keines dieser Zeichen als Trennzeichen verwendet. Wenn ein Dateiname also ein Leerzeichen oder eine neue Zeile enthält, erhalten Sie wird unerwartete Ergebnisse.

Es gibt zwei sehr gute Möglichkeiten, Dateien zu durchlaufen. Hier habe ich einfach echo verwendet, um zu demonstrieren, wie etwas mit dem Dateinamen gemacht wird. Sie können jedoch alles verwenden.

Die erste besteht darin, die systemeigenen Globbing-Funktionen der Shell zu verwenden.

for dir in */; do
  echo "$dir"
done

Die Shell erweitert */ in separate Argumente, die von der for-Schleife gelesen werden. Selbst wenn der Dateiname ein Leerzeichen, ein Zeilenumbruch oder ein anderes merkwürdiges Zeichen enthält, sieht for jeden vollständigen Namen als eine atomare Einheit. Es analysiert die Liste in keiner Weise.

Wenn Sie rekursiv in Unterverzeichnisse wechseln möchten, funktioniert dies nur, wenn Ihre Shell über einige erweiterte Globbing-Funktionen verfügt (z. B. bashglobstar). Wenn Ihre Shell diese Funktionen nicht unterstützt oder wenn Sie sicherstellen möchten, dass Ihr Skript funktioniert Auf einer Vielzahl von Systemen besteht die nächste Option darin, find zu verwenden.

find . -type d -exec echo '{}' \;

Hier ruft der Befehl findecho auf und übergibt ihm ein Argument des Dateinamens. Dies wird einmal für jede gefundene Datei ausgeführt. Wie im vorherigen Beispiel wird keine Liste mit Dateinamen analysiert. Stattdessen wird ein Dateiformat vollständig als Argument gesendet.

Die Syntax des Arguments -exec sieht ein wenig komisch aus. find verwendet das erste Argument nach -exec und behandelt dieses als auszuführendes Programm. Jedes nachfolgende Argument wird als Argument zur Übergabe an dieses Programm verwendet. Es gibt zwei spezielle Argumente, die -exec sehen muss. Der erste ist {}; Dieses Argument wird durch einen Dateinamen ersetzt, den die vorherigen Teile von find generieren. Der zweite ist ;, der find mitteilt, dass dies das Ende der Liste der Argumente ist, die an das Programm übergeben werden sollen. find benötigt dies, da Sie mit weiteren Argumenten fortfahren können, die für find und nicht für das ausgeführte Programm bestimmt sind. Der Grund für den \ ist, dass die Shell auch ; speziell behandelt - er stellt das Ende eines Befehls dar, daher müssen wir ihn maskieren, damit die Shell ihn als Argument für find ausgibt, anstatt ihn für sich selbst zu verbrauchen. Eine andere Möglichkeit, die Shell dazu zu bringen, sie nicht speziell zu behandeln, besteht darin, sie in Anführungszeichen zu setzen: ';' funktioniert für diesen Zweck genauso gut wie \;.

64
Shawn J. Goff

Bei Dateien mit Leerzeichen müssen Sie die Variable wie folgt angeben:

 for i in $(ls); do echo "$i"; done; 

sie können auch die Umgebungsvariable IFS (Input Field Separator) ändern:

 IFS=$'\n';for file in $(ls); do echo $i; done

Je nachdem, was Sie gerade tun, brauchen Sie möglicherweise nicht einmal das ls:

 for i in *; do echo "$i"; done;
14
john

Wenn Sie GNU Parallel http://www.gnu.org/software/parallel/ installiert haben, können Sie dies tun:

ls | parallel echo {} is in this dir

So benennen Sie alle TXT-Dateien in XML-Dateien um:

ls *.txt | parallel mv {} {.}.xml

Sehen Sie sich das Intro-Video für GNU Parallel an, um mehr zu erfahren: http://www.youtube.com/watch?v=OpaiGYxkSuQ

5
Ole Tange

Um die Antwort von CoverosGene zu ergänzen, können Sie hier nur die Verzeichnisnamen auflisten:

for f in */; do
  echo "Directory -> $f"
done
4
n3o

Warum setzen Sie IFS nicht auf eine neue Zeile und erfassen dann die Ausgabe von ls in einem Array? Das Setzen von IFS auf newline sollte Probleme mit lustigen Zeichen in Dateinamen beheben. Die Verwendung von ls kann nützlich sein, da eine Sortierfunktion integriert ist.

(Beim Testen hatte ich Probleme, IFS auf \n zu setzen, aber das Setzen auf Newline Backspace funktioniert, wie an anderer Stelle hier vorgeschlagen):

Z.B. (unter der Annahme, dass das gewünschte ls Suchmuster in $1 übergeben wurde):

SAVEIFS=$IFS
IFS=$(echo -en "\n\b")

FILES=($(/bin/ls "$1"))

for AFILE in ${FILES[@]}
do
    ... do something with a file ...
done

IFS=$SAVEIFS

Dies ist unter OS X besonders praktisch, z. B. um eine Liste von Dateien nach Erstellungsdatum (älteste bis neueste) zu erfassen. Der Befehl ls lautet ls -t -U -r.

1
jetset