Verfügt jemand über ein Template-Shell-Skript, mit dem er etwas ls
für eine Liste von Verzeichnisnamen tun und die einzelnen durchlaufen und etwas tun kann?
Ich habe vor ls -1d */
, die Liste der Verzeichnisnamen abzurufen.
Verfügt jemand über ein Template-Shell-Skript, mit dem er etwas ls
für eine Liste von Verzeichnisnamen tun und die einzelnen durchlaufen und etwas tun kann?
Ich habe vor ls -1d */
, die Liste der Verzeichnisnamen abzurufen.
Antworten:
Bearbeitet, um nicht ls zu verwenden, wo ein Globus tun würde, wie @ shawn-j-goff und andere vorgeschlagen haben.
Benutze einfach eine for..do..done
Schleife:
for f in *; do
echo "File -> $f"
done
Sie können das *
mit *.txt
oder jedes andere Glob ersetzen, das eine Liste (von Dateien, Verzeichnissen oder irgendetwas anderem) zurückgibt, einen Befehl, der beispielsweise eine Liste erzeugt $(cat filelist.txt)
, oder sie tatsächlich durch eine Liste ersetzen.
Innerhalb der do
Schleife verweisen Sie einfach auf die Schleifenvariable mit dem Dollarzeichen-Präfix (so $f
im obigen Beispiel). Sie können echo
es tun oder was Sie wollen.
Um beispielsweise alle .xml
Dateien im aktuellen Verzeichnis umzubenennen, gehen Sie wie folgt vor .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
for
Schleifen und die typische Gefahr, die Ausgabe von zu analysieren ls
. @ DanielA.Weiß, Sie könnten in Betracht ziehen, diese Antwort nicht zu akzeptieren, wenn sie nicht hilfreich ist (oder möglicherweise irreführend ist), da Sie, wie Sie sagten, Verzeichnisse bearbeiten . Die Antwort von Shawn J. Goff sollte eine robustere und funktionsfähigere Lösung für Ihr Problem bieten.
ls
Ausgabe nicht analysieren , Sie sollten die Ausgabe nicht in einer for
Schleife lesen , Sie sollten $()
anstelle von `` und Use More Quotes ™ verwenden . Ich bin sicher, @CoverosGene hat es gut gemeint, aber das ist einfach schrecklich.
ls
ist ls -1 | while read line; do stuff; done
. Zumindest wird das nicht für Leerzeichen brechen.
mv -v
Ihnen brauchen nichtecho "moved $x -> $t"
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 das null
Zeichen enthalten kann und ls
keines dieser Zeichen als Trennzeichen verwendet. Wenn ein Dateiname also ein Leerzeichen oder eine neue Zeile enthält, werden unerwartete Ergebnisse erzielt.
Es gibt zwei sehr gute Möglichkeiten, Dateien zu durchlaufen. Hier habe ich einfach echo
gezeigt, wie man etwas mit dem Dateinamen macht. Sie können jedoch alles verwenden.
Die erste besteht darin, die nativen Globbing-Funktionen der Shell zu verwenden.
for dir in */; do
echo "$dir"
done
Die Shell erweitert sich */
in separate Argumente, die von der for
Schleife gelesen werden. Auch wenn der Dateiname ein Leerzeichen, eine neue Zeile oder ein anderes merkwürdiges Zeichen enthält, for
wird jeder vollständige Name als atomare Einheit angezeigt . Es analysiert die Liste in keiner Weise.
Wenn Sie rekursiv in Unterverzeichnissen gehen wollen, dann wird dies nicht tun , wenn Ihre Shell einige erweiterte Globbing Funktionen (zB bash
‚s globstar
. Wenn Ihre Shell nicht über diese Eigenschaften haben, oder wenn Sie wollen sicherstellen , dass Ihr Skript funktioniert auf einer Vielzahl von Systemen ist dann die nächste Option zu verwenden find
.
find . -type d -exec echo '{}' \;
Hier find
ruft der Befehl echo
ein Argument des Dateinamens auf und übergibt es. 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 -exec
Arguments sieht ein bisschen komisch aus. find
Nimmt das erste Argument nach -exec
und behandelt es als auszuführendes Programm. Jedes nachfolgende Argument wird als Argument zur Übergabe an dieses Programm verwendet. Es gibt zwei spezielle Argumente, -exec
die man sehen muss. Der erste ist {}
; Dieses Argument wird durch einen Dateinamen ersetzt, den die vorherigen Teile von find
generieren. Die zweite ist ;
, die mitteilt, find
dass dies das Ende der Liste der Argumente ist, die an das Programm übergeben werden sollen. find
benötigt dies, weil Sie mit weiteren Argumenten fortfahren können, find
die für das ausgeführte Programm bestimmt sind und nicht. Der Grund dafür \
ist, dass die Shell auch behandelt;
Insbesondere - es stellt das Ende eines Befehls dar, daher müssen wir es maskieren, damit die Shell es als Argument gibt, find
anstatt es 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 ';'
genauso gut wie \;
für diesen Zweck.
find
. Es gibt Magie, die getan werden kann, und sogar die wahrgenommenen Einschränkungen von -exec
können umgangen werden. Die -print0
Option ist auch nützlich für die Verwendung mit xargs
.
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;
\n
ist unzureichend. Es ist niemals eine gute Idee, das Parsen der Ausgabe von zu empfehlen ls
.
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 Einführungsvideo für GNU Parallel an, um mehr zu erfahren: http://www.youtube.com/watch?v=OpaiGYxkSuQ
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 ls
kann nützlich sein, da eine Sortierfunktion integriert ist.
(Beim Testen hatte ich Probleme, IFS auf zu setzen, \n
aber das Setzen auf Newline Backspace funktioniert, wie an anderer Stelle hier vorgeschlagen):
ZB (unter der Annahme, dass das gewünschte ls
Suchmuster übergeben wurde $1
):
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 besonders praktisch , auf OS X, zum Beispiel eine Liste von Dateien nach Erstellungsdatum (alt nach neu), der zu sortier erfassen ls
Befehl ist ls -t -U -r
.
\n
ist unzureichend. Die einzig gültigen Lösungen verwenden eine for-Schleife mit Pfadnamenerweiterung oder find
.
So mache ich das, aber es gibt wahrscheinlich effizientere Möglichkeiten.
ls > filelist.txt
while read filename; do echo filename: "$filename"; done < filelist.txt
ls | while read i; do echo filename: $i; done