Przejrzyj wszystkie podkatalogi i zrób coś w skrypcie powłoki systemu Unix

17

Chcę, aby mój skrypt powłoki odwiedził wszystkie podkatalogi w katalogu głównym. Zrób coś w katalogach, wyślij dane wyjściowe do pliku buforowania i przejdź do następnego katalogu. Rozważ główny katalog = / tmp podkatalog = ABCD (cztery podkatalogi)

Ashish
źródło
2
OK, pokaż nam swój skrypt do tej pory. Która część sprawia ci problemy?
terdon

Odpowiedzi:

22

Użyj forpętli:

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

Przeszukuje tylko podkatalogi katalogu /path/to/dir. Zauważ, że powyższy prosty przykład zawiedzie, jeśli nazwy katalogów zawierają spacje lub znaki specjalne. Bezpieczniejsze podejście to:

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

Lub wprost bash:

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

(zauważ, że w przeciwieństwie do findtego rozważa również dowiązania symboliczne do katalogów i wyklucza ukryte)

chaos
źródło
1
przynajmniej wskaż ograniczenia i ryzyko związane z przetwarzaniem findpodobnych wyników.
Stéphane Chazelas
Cześć ... próbowałem uruchomić poniżej dla pętli dla d w $ (find / backup / ASHISH -maxdepth 1 -type d) do ls -l | awk '{print $ 9}' | grep CC * _ date +"%m%d20%Y"| xargs echo echo $ d
Ashish
Cześć ... Próbowałem poniżej dla pętli. for 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 Oczekiwany wynik to ls -ltr ze wszystkich podkatalogów . Powyższa pętla nie działa
Ashish
1

Jestem kompletnym bashnowicjuszem, ale weteranem ONZ * X. Chociaż niewątpliwie można tego dokonać w skryptach powłoki Bash, w dawnych czasach to robiliśmy find [-maxdepth <levels>] <start-dir> -exec <command> ;. Możesz zrobić man findi bawić się, może dopóki ktoś nie powie ci, jak to zrobić bash!

JonBrave
źródło
Bardzo mi pochlebia fakt, że moja „zarysowa” odpowiedź uzyskała poparcie w głosowaniu. Dlaczego jednak poniższa odpowiedź @chaos została odrzucona? (Jako nowicjusz na tym forum nie mogę opublikować tego komentarza wbrew jego odpowiedzi, tylko wbrew własnej). Jego druga sugestia jest poprawna dla rozwiązania skryptu powłoki i pozwala uniknąć nakładania się findpoleceń zewnętrznych .
JonBrave
Jego druga prawda jest rzeczywiście poprawna. Jego pierwsza nie powiedzie się, jeśli nazwy katalogów zawierają spacje lub znaki specjalne (na przykład odwrotne ukośniki). Zobacz edycję, której dokonałem w odpowiedzi na bezpieczną wersję.
terdon
Zgadzam się. To była jego druga, jedyna odpowiedź, którą chwaliłem.
JonBrave
Wiem, właśnie tłumaczyłem downvote (którego nie oddałem).
terdon
Rzuciłem to. Chodzi $(find...)o złą praktykę .
Stéphane Chazelas
1

Wygląda na to, że chcesz mieć nazwy plików w każdym podkatalogu; ls -l | awknie jest wystarczająco wytrzymała, na co, jeśli te nazwy plików zawierają białymi znakami i / lub znaki nowej linii? Poniższe finddziałałoby nawet dla findtych, którzy nie mają -maxdepthszans na ich spełnienie :

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

źródło
0

Mam rozwiązanie. Poniższe polecenie find spełnia moje wymagania.

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

Jest to również możliwe przy użyciu ls, grep i tr

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 może być również używany jako selektor, jeśli twojemu ls brakuje powyższych opcji

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

Warto pamiętać, że te przykłady zwracają ukryte katalogi i wykluczają katalogi nadrzędne i bieżące

JGurtz
źródło
1
(1)  domyślnie lszapisuje jeden plik w wierszu (co -1określa opcja), gdy standardowym wyjściem jest potok (więc jest zbyteczny w twoich odpowiedziach). (2) Analiza wyniku lsjest złym pomysłem - zobacz to i to . Twoja pierwsza odpowiedź nie powiedzie się, jeśli katalogi mają spacje (lub znaki nowej linii) w swoich nazwach, a wszystkie zawiodą, jeśli będą miały nazwy nowych linii. (3) Zawsze powinieneś cytować zmienne powłoki (np. "$dir"), Chyba że masz dobry powód, aby tego nie robić i jesteś pewien, że wiesz, co robisz.
Scott
Dobre punkty Scott. Pozostawiając odpowiedź, ponieważ dla wielu systemów bez nazwanych z grubsza nazwami katalogów, myślę, że może być nadal przydatny dla tych jednorazowych.
JGurtz