cd do wszystkich katalogów, wykonaj polecenie na plikach w tym katalogu i wróć do poprzedniego bieżącego katalogu

41

Próbuję napisać skrypt, który zostanie uruchomiony w danym katalogu z wieloma podkatalogami na jednym poziomie. Skrypt przejdzie do każdego z podkatalogów, wykona polecenie na plikach w katalogu i wyda polecenie cd, aby przejść do następnego katalogu. Jak najlepiej to zrobić?

Coś Jones
źródło
1
Biorąc pod uwagę obecny poziom informacji, nie widzę żadnego związku z tym youtube-dl.
HalosGhost,

Odpowiedzi:

83
for d in ./*/ ; do (cd "$d" && somecommand); done
psusi
źródło
12
Skoro więc odpowiadający pominął jakieś wyjaśnienie, spróbuję je wyjaśnić. for d in ./*/uruchamia pętlę, w której zapisywany jest każdy element ./*/(w tym przypadku lista plików / folderów) w zmiennej $d. do (cd "$d" && somecommand);uruchamia ciało pętli. Wewnątrz ciała uruchamia podpowłokę i uruchamia polecenia cdi somecommand. Ponieważ jest to powłoka podrzędna, powłoka nadrzędna (powłoka, z której uruchamiane jest to polecenie), zachowuje CWD i inne zmienne środowiskowe. donepo prostu zamyka korpus pętli.
Qix,
ta metoda działa dla podkatalogów katalogów:, for d in ./*/ ; do (cd "$d" && ls); donenie będzie działać. ale for d in ./*/ ; do (cd "$d" && for d in ./*/ ; do (cd "$d" && ls); done ); donezadziała. -korzystanie z ls jako polecenia w tym przykładzie.
Michael Dimmitt,
-bash: cd: ./*/: No such file or directory
S. Tarık Çetin
15

Najlepszym sposobem jest w ogóle nie używać cd:

find some/dir -type f -execdir somecommand {} \;

execdirjest jak exec, ale katalog roboczy jest inny:

   -execdir command {} [;|+]
          Like   -exec,   but  the  specified  command  is  run  from  the
          subdirectory containing the matched file, which is not  normally
          the  directory  in  which  you  started  find.  This a much more
          secure  method  for  invoking  commands,  as  it   avoids   race
          conditions  during resolution of the paths to the matched files.

To nie jest POSIX.

muru
źródło
Czy to działa z aliasami? Mam jeden plik do pobrania, ale nie rozpoznaje go, gdy wpisuję find * /. Link -type f -execdir md $ (cat .link) {} \;
Coś Jones
@SomethingJones nie, findwykonuje te polecenia, więc nie byłby świadomy aliasów. Co to mdjest .linkkatalog?
muru,
.link to plik tekstowy z adresem URL, który należy pobrać. md to alias do wget z zestawem flag. Czy istnieje sposób, aby uświadomić sobie aliasy?
Coś Jones
@SomethingJones dla konkretnego przypadku użytkowej, w bash: find . -type f -iname '*.link' -execdir ${BASH_ALIASES[md]} -i {} \;Nie trzeba robić catz wget, który ma -iflagę do czytania w URL z pliku. Również nieco różni się to od twojego pierwotnego pytania (ponieważ wydaje się, że jesteś zainteresowany tylko nazwanymi plikami, .linka nie innymi, które mogą być obecne).
muru
Czy wiesz jak to zrobić z Zsh? Próbowałem tego, co mi dałeś, i pojawia się błąd „Złe zastąpienie”. Jak mogę wyodrębnić zawartość pliku .link? Wiem, że nie potrzebuję tego w tym przypadku, ale wyobrażam sobie, że wkrótce.
Coś Jones
2
cd -P .
for dir in ./*/
do cd -P "$dir" ||continue
   printf %s\\n "$PWD" >&2
   command && cd "$OLDPWD" || 
! break; done || ! cd - >&2

Powyższe polecenie nie musi wykonywać żadnych podpowłok - po prostu śledzi swoje postępy w bieżącej powłoce na przemian $OLDPWDi $PWD. Kiedy ty cd -powłoka wymienia wartość tych dwóch zmiennych, w zasadzie, ponieważ zmienia katalogi. Wyświetla także nazwę każdego katalogu, ponieważ działa tam na stderr.

Właśnie rzuciłem na to okiem i zdecydowałem, że lepiej sobie radzę z obsługą błędów. Pominie katalog, do którego nie może cd- i cdwydrukuje komunikat o tym, dlaczego stderr - i breakw / niezerowy kod wyjścia, jeśli commandnie zostanie wykonany pomyślnie lub jeśli uruchomienie w commandjakiś sposób wpłynie na jego zdolność do powrotu do oryginalnego katalogu - $OLDPWD. W takim przypadku wykonuje również cd -ostatni - i zapisuje wynikową bieżącą nazwę katalogu roboczego do stderr.

mikeserv
źródło
1
for D in ./*; do
    if [ -d "$D" ]; then
        cd "$D"
        run_something
        cd ..
    fi
done
Cyryl
źródło