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ć?


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

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.


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.


1
for D in ./*; do
    if [ -d "$D" ]; then
        cd "$D"
        run_something
        cd ..
    fi
done
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.