cd ke semua direktori, jalankan perintah pada file di direktori itu, dan kembali ke direktori saat ini sebelumnya

41

Saya mencoba untuk menulis skrip yang akan dijalankan di direktori yang diberikan dengan banyak sub direktori tingkat tunggal. Script akan melakukan cd ke masing-masing sub direktori, menjalankan perintah pada file dalam direktori, dan keluar untuk melanjutkan ke direktori berikutnya. Apa cara terbaik untuk melakukan ini?

Sesuatu Jones
sumber
1
Mengingat tingkat informasi yang diberikan saat ini, saya tidak melihat relevansi dengan youtube-dl.
HalosGhost

Jawaban:

83
for d in ./*/ ; do (cd "$d" && somecommand); done
psusi
sumber
12
Jadi karena penjawab telah menghilangkan segala jenis penjelasan, saya akan mencoba satu. for d in ./*/memulai loop yang menyimpan setiap item dalam ./*/(daftar file / folder, dalam hal ini) dalam sebuah variabel $d. do (cd "$d" && somecommand);memulai badan loop. Di dalam tubuh, itu mulai subkulit dan menjalankan cddan somecommandperintah. Karena ini adalah shell anak, shell induk (shell dari mana Anda menjalankan perintah ini) mempertahankan CWD dan variabel lingkungan lainnya. donecukup menutup tubuh loop.
Qix
metode ini berfungsi untuk sub direktori direktori:, for d in ./*/ ; do (cd "$d" && ls); donetidak akan berfungsi. tapi, for d in ./*/ ; do (cd "$d" && for d in ./*/ ; do (cd "$d" && ls); done ); doneakan berhasil. -menggunakan ls sebagai perintah dalam contoh ini.
Michael Dimmitt
-bash: cd: ./*/: No such file or directory
S. Tarık Çetin
15

Cara terbaik adalah tidak menggunakan cdsama sekali:

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

execdirseperti exec, tetapi direktori kerja berbeda:

   -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.

Ini bukan POSIX.

muru
sumber
Apakah ini berhasil dengan alias? Saya punya satu untuk mengunduh file tertentu tetapi tidak mengenalinya ketika saya mengetikkan tautan find * /. -Type f -execdir md $ (cat .link) {} \;
Sesuatu Jones
@SesuatuJones tidak, findjalankan perintah-perintah itu, jadi tidak akan tahu alias. Apakah mddan apakah .linkdirektori itu?
muru
.link adalah file teks yang memiliki URL yang perlu diunduh. md adalah alias untuk wget dengan set flag yang ditetapkan. Apakah ada cara untuk membuatnya sadar akan alias?
Sesuatu Jones
@SomethingJones Untuk penggunaan-kasus tertentu, di bash: find . -type f -iname '*.link' -execdir ${BASH_ALIASES[md]} -i {} \;Anda tidak perlu melakukan catdengan wget, yang memiliki -ibendera untuk membaca di sebuah URL dari file. Ini juga agak berbeda dari pertanyaan awal Anda (karena Anda tampaknya tertarik hanya pada file yang diberi nama .linkdan bukan file lain yang mungkin ada).
muru
Apakah Anda tahu cara melakukannya dengan zsh? Saya mencoba apa yang Anda berikan kepada saya dan saya mendapatkan kesalahan "substitusi buruk". Juga, bagaimana saya bisa mengekstraksi konten file .link? Saya tahu saya tidak membutuhkannya dalam kasus ini, tetapi saya membayangkan saya akan segera melakukannya.
Sesuatu Jones
2
cd -P .
for dir in ./*/
do cd -P "$dir" ||continue
   printf %s\\n "$PWD" >&2
   command && cd "$OLDPWD" || 
! break; done || ! cd - >&2

Perintah di atas tidak perlu melakukan subshell - hanya melacak kemajuannya di shell saat ini dengan bergantian $OLDPWDdan $PWD. Ketika Anda cd -shell bertukar nilai dari dua variabel ini, pada dasarnya, karena perubahan direktori. Ia juga mencetak nama untuk setiap direktori karena berfungsi di sana untuk stderr.

Saya baru saja melihatnya dan memutuskan untuk melakukan pekerjaan yang lebih baik dengan penanganan kesalahan. Ini akan melewati sebuah dir ke mana ia tidak bisa cd- dan cdakan mencetak pesan tentang mengapa harus stderr - dan itu akan breakw / kode keluar tidak nol jika Anda commandtidak berhasil menjalankan atau jika commandentah bagaimana menjalankan mempengaruhi kemampuannya untuk kembali ke direktori asli Anda - $OLDPWD. Dalam hal ini ia juga melakukan yang cd -terakhir - dan menulis nama direktori kerja saat ini yang dihasilkan ke stderr.

mikeserv
sumber
1
for D in ./*; do
    if [ -d "$D" ]; then
        cd "$D"
        run_something
        cd ..
    fi
done
Kirill
sumber