Wie schreibe ich einen Bash - Skript , das in einem parent_directory durch jedes Verzeichnis geht und führt einen Befehl in jedem Verzeichnis .
Die Verzeichnisstruktur ist wie folgt:
parent_directory (Name kann alles sein - folgt keinem Muster)
- 001 (Verzeichnisnamen folgen diesem Muster)
- 0001.txt (Dateinamen folgen diesem Muster)
- 0002.txt
- 0003.txt
- 002
- 0001.txt
- 0002.txt
- 0003.txt
- 0004.txt
- 003
- 0001.txt
Die Anzahl der Verzeichnisse ist unbekannt.
cd "$d"
Dies wäre insofern besser, als es in Situationen übertragen wird, in denen der Platzhalter mit Dateien übereinstimmt, deren Namen Leerzeichen und / oder Shell-Metazeichen enthalten.for f in foo bar; do cat "$f"/*.txt; done >output
ist funktional äquivalent zucat foo/*.txt bar/*.txt >output
. Es handelt sich jedochls
um einen Befehl, der je nach Übergabe der Argumente eine geringfügig andere Ausgabe erzeugt. In ähnlicher Weise unterscheidet sich eingrep
oder,wc
das einen relativen Dateinamen ausgibt,, wenn Sie ihn in einem Unterverzeichnis ausführen (aber häufig möchten Sie genau aus diesem Grund vermeiden, in ein Unterverzeichnis zu wechseln).Diese Antwort von Todd hat mir geholfen.
Die
\( ! -name . \)
Vermeiden den Befehl im aktuellen Verzeichnis auszuführen.quelle
find FOLDER* -maxdepth 0 -type d \( ! -name . \) -exec bash -c "cd '{}' && pwd" \;
-exec bash -c 'cd "$0" && pwd' {} \;
da einige Verzeichnisse einfache Anführungszeichen und einige doppelte Anführungszeichen enthielten.-mindepth 1
pwd
direktdisd(){find . -maxdepth 1 -type d \( ! -name . \) -exec bash -c 'cd "{}" && "$@"' \;}
nicht arbeiten.Wenn Sie GNU verwenden
find
, können Sie-execdir
Parameter ausprobieren , z.oder (gemäß @gniourf_gniourf Kommentar ):
Hinweis: Sie können
${0#./}
anstelle von verwenden$0
, um./
in der Front zu reparieren .oder praktischeres Beispiel:
Wenn Sie das aktuelle Verzeichnis einschließen möchten, ist es noch einfacher, wenn Sie Folgendes verwenden
-exec
:oder mit
xargs
:Oder ein ähnliches Beispiel, das von @gniourf_gniourf vorgeschlagen wurde :
Die obigen Beispiele unterstützen Verzeichnisse mit Leerzeichen im Namen.
Oder durch Zuweisen in ein Bash-Array:
Ändern Sie
.
Ihren spezifischen Ordnernamen. Wenn Sie nicht rekursiv ausgeführt werden müssen, können Siedirs=(*)
stattdessen Folgendes verwenden. Das obige Beispiel unterstützt keine Verzeichnisse mit Leerzeichen im Namen.Wie @gniourf_gniourf vorgeschlagen hat, ist die einzig richtige Möglichkeit, die Ausgabe von find in ein Array zu setzen, ohne eine explizite Schleife zu verwenden, in Bash 4.4 verfügbar mit:
Oder kein empfohlener Weg (der das Parsen von
ls
beinhaltet ):Das obige Beispiel würde das aktuelle Verzeichnis ignorieren (wie von OP angefordert), aber es wird bei Namen mit den Leerzeichen unterbrochen.
Siehe auch:
quelle
find
in ein Array zu setzen, ohne eine explizite Schleife zu verwenden, ist in Bash 4.4 mit verfügbarmapfile -t -d '' dirs < <(find . -type d -print0)
. Bis dahin besteht Ihre einzige Option darin, eine Schleife zu verwenden (oder die Operation auf zu verschiebenfind
).dirs
Array nicht wirklich . Sie könnten denfind
Ausgang (sicher) wie folgt durchlaufen :find . -type d -print0 | while IFS= read -r -d '' file; do ...; done
.IFS
,read
gibt es den Eindruck zusätzlicher Komplexität. Ich muss darüber nachdenken, vielleicht gibt es einen einfacheren Weg, es zu tun.IFS
undread
(wie Sie sagen) , um eine zweite Natur , wie Sie sie zu gewöhnen ... sie sind Teil der kanonischen und idiomatischen Möglichkeiten von Skripten zu schreiben.find . -type d -execdir echo $(pwd)/{} ';'
macht nicht das, was Sie wollen (der Befehl$(pwd)
wird erweitert, bevor erfind
überhaupt ausgeführt wird)…Sie können dies erreichen, indem Sie Rohrleitungen verwenden und dann verwenden
xargs
. Der Haken ist, dass Sie das-I
Flag verwenden müssen, das den Teilstring in Ihrem bash-Befehl durch den Teilstring ersetzt, der von jedem der Befehle übergeben wirdxargs
.Möglicherweise möchten Sie durch einen
pwd
beliebigen Befehl ersetzen, den Sie in jedem Verzeichnis ausführen möchten.quelle
Wenn der Ordner auf oberster Ebene bekannt ist, können Sie einfach Folgendes schreiben:
Auf dem $ (SPIELEN SIE SO VIEL, WIE SIE WOLLEN); Sie können so viel Code eingeben, wie Sie möchten.
Beachten Sie, dass ich in keinem Verzeichnis "cd" habe.
Prost,
quelle
ls
" - Sie können diesfor dir in $YOUR_TOP_LEVEL_FOLDER/*
stattdessen einfach tun .ls $dir
Ausdruckquelle
Während ein Liner für den schnellen und schmutzigen Gebrauch gut ist, bevorzuge ich unten eine ausführlichere Version zum Schreiben von Skripten. Dies ist die Vorlage, die ich verwende, die sich um viele Randfälle kümmert und es Ihnen ermöglicht, komplexeren Code für die Ausführung in einem Ordner zu schreiben. Sie können Ihren Bash-Code in die Funktion dir_command schreiben. Im Folgenden implementiert dir_coomand die Kennzeichnung jedes Repositorys in git als Beispiel. Der Rest des Skripts ruft dir_command für jeden Ordner im Verzeichnis auf. Das Beispiel für das Durchlaufen nur eines bestimmten Ordnersatzes ist ebenfalls enthalten.
quelle
Ich verstehe den Punkt beim Formatieren der Datei nicht, da Sie nur durch Ordner iterieren möchten ... Suchen Sie nach so etwas?
quelle
Sie können verwenden
um alle Dateien / Verzeichnisse im aktuellen Verzeichnis rekursiv zu durchsuchen
Dann können Sie die Ausgabe mit dem Befehl xargs wie folgt weiterleiten
quelle
quelle
cd
sichern oder in einer Subshell ausführen.cd
so dass dieser Code eigentlich nichts Nützliches tut.