Durchsuchen Sie alle Unterverzeichnisse und führen Sie etwas im Unix-Shell-Skript aus

17

Ich möchte, dass mein Shell-Skript alle Unterverzeichnisse in einem Hauptverzeichnis aufruft. Machen Sie etwas in Verzeichnissen, senden Sie die Ausgabe an eine Spooldatei und fahren Sie mit dem nächsten Verzeichnis fort. Betrachten Sie Main Dir = / tmp Sub Dir = ABCD (vier Unterverzeichnisse)

Ashish
quelle
2
OK, zeigen Sie uns bitte Ihr Skript. Welcher Teil davon bereitet dir Probleme?
terdon

Antworten:

22

Benutze eine forSchleife:

for d in $(find /path/to/dir -maxdepth 1 -type d)
do
  #Do something, the directory is accessible with $d:
  echo $d
done >output_file

Es werden nur die Unterverzeichnisse des Verzeichnisses durchsucht /path/to/dir. Beachten Sie, dass das obige einfache Beispiel fehlschlägt, wenn die Verzeichnisnamen Leerzeichen oder Sonderzeichen enthalten. Ein sicherer Ansatz ist:

find /tmp -maxdepth 1 -type d -print0 |
  while IFS= read -rd '' dir; do echo "$dir"; done

Oder im Klartext bash:

for d in /path/to/dir/*; do
  if [ -d "$d" ]; then
    echo "$d"
  fi
done

(Beachten Sie, dass man im Gegensatz dazu findauch Symlinks zu Verzeichnissen berücksichtigt und versteckte ausschließt)

Chaos
quelle
1
weisen Sie zumindest auf die Einschränkungen und Risiken hin, die mit der Verarbeitung der Ergebnisse verbunden sind find.
Stéphane Chazelas
Hi ... ich habe versucht, unten für die Schleife für d in $ (find / backup / ASHISH -maxdepth 1 -type d) zu laufen. Do ls -l | awk '{print $ 9}' | grep CC * _ date +"%m%d20%Y"| xargs echo echo $ d
Ashish
Hallo ... Ich habe unten für Schleife versucht. für d in $ (find / backup / ASHISH -maxdepth 1 -type d) do ls -l | awk '{print $ 9}' | grep CC * _ date +"%m%d20%Y"| xargs echo echo $ d Das erwartete Ergebnis ist ls -ltr aus allen Unterverzeichnissen . Die obige Schleife funktioniert nicht
Ashish
1

Ich bin ein bashabsoluter Neuling, aber ein UN * X-Veteran. Obwohl dies zweifellos in Bash-Shell-Skripten möglich ist, haben wir dies früher getan find [-maxdepth <levels>] <start-dir> -exec <command> ;. Du man findkönntest ein Spiel machen, vielleicht bis dir jemand sagt, wie es geht bash!

JonBrave
quelle
Ich bin sehr geschmeichelt, dass meine "Gliederungs" -Antwort hier positiv bewertet wurde. Warum wurde die Antwort von @chaos unten jedoch abgelehnt? (Als Neuling in diesem Forum kann ich diesen Kommentar nicht gegen seine, sondern nur gegen meine Antwort posten.) Sein zweiter Vorschlag ist für eine Shell-Skript-Lösung korrekt und vermeidet den Aufwand für die Ausführung eines externen findBefehls.
JonBrave
Sein zweiter ist in der Tat richtig. Sein erster Fehler tritt auf, wenn die Verzeichnisnamen Leerzeichen oder Sonderzeichen enthalten (z. B. umgekehrte Schrägstriche). Siehe die Bearbeitung, die ich an seiner Antwort vorgenommen habe, für die sichere Version.
terdon
Genau. Es war seine zweite Antwort nur auf Muscheln, die ich lobte.
JonBrave
Ich weiß, ich habe nur die Gegenstimme erklärt (die ich nicht ausgesprochen habe).
terdon
Ich habe es gewirkt. Die $(find...)Sache ist schlechte Praxis .
Stéphane Chazelas
1

Sieht so aus, als ob Sie die Dateinamen unter jedem der Unterverzeichnisse haben möchten. Das ls -l | awkist nicht robust genug. Wofür, wenn diese Dateinamen Leerzeichen und / oder Zeilenumbrüche enthalten? Das Folgende findwürde sogar für finds funktionieren, die nicht das richtige -maxdepthfür sie sind:

find . ! -name . -type d -prune -exec sh -c '
   cd "$1" && \
   find "." ! -name . -prune  -type f
' {} {} \;

quelle
0

Ich habe die Lösung. Der folgende Suchbefehl entspricht meinen Anforderungen.

find . -maxdepth 1 -type d \( ! -name . \) -exec bash -c "cd '{}' && ls -l |awk '{ print $9 }' |grep `date +"%m%d%Y"`|xargs echo" \;
Ashish
quelle
0

Es ist auch möglich, ls, grep und tr zu verwenden

for dir in $(ls -1FA | grep / | tr -d /); do echo $dir/something; done

ls -1FA | grep / | tr -d / | while IFS= read -r TD; do echo $TD/something; done

du / sed kann auch als Selektor verwendet werden, wenn Ihrem ls die oben genannten Optionen fehlen

du --max-depth=1 | sed -e 's/^.*\.\///' | grep -v '\.$'

Es kann wichtig sein, zu beachten, dass diese Beispiele versteckte Verzeichnisse zurückgeben und übergeordnete und aktuelle Verzeichnisse ausschließen

JGurtz
quelle
1
(1)  lsSchreibt -1standardmäßig eine Datei pro Zeile (wie in der Option angegeben), wenn die Standardausgabe eine Pipe ist (daher ist dies in Ihren Antworten überflüssig). (2) Das Parsen der Ausgabe von lsist eine schlechte Idee - sehen Sie dies und das . Ihre erste Antwort schlägt fehl, wenn Verzeichnisse Leerzeichen (oder Zeilenumbrüche) im Namen haben, und alle schlagen fehl, wenn sie Zeilenumbrüche im Namen haben. (3) Sie sollten immer Shell-Variablen (z. B. "$dir") angeben , es sei denn, Sie haben einen guten Grund, dies nicht zu tun, und Sie sind sicher, dass Sie wissen, was Sie tun.
Scott
Gute Punkte Scott. Wenn ich die Antwort so lasse, denke ich, dass es für viele Systeme ohne ungeheuerlich benannte Verzeichnisse für die einen noch nützlich sein kann.
JGurtz