cd in tutte le directory, eseguire il comando sui file in quella directory e tornare alla directory corrente precedente


41

Sto tentando di scrivere uno script che verrà eseguito in una determinata directory con molte sottodirectory di livello singolo. Lo script eseguirà il cd in ciascuna delle sottodirectory, eseguirà un comando sui file nella directory e uscirà per continuare nella directory successiva. Qual è il modo migliore per farlo?


1
Dato l'attuale livello di informazioni fornite, non vedo alcuna rilevanza per youtube-dl.
HalosGhost

Risposte:


83
for d in ./*/ ; do (cd "$d" && somecommand); done

12
Quindi, dal momento che il rispondente ha omesso qualsiasi tipo di spiegazione, proverò uno. for d in ./*/avvia un ciclo che archivia ogni elemento in ./*/(un elenco di file / cartelle, in questo caso) in una variabile $d. do (cd "$d" && somecommand);avvia il corpo del loop. All'interno del corpo, avvia una subshell ed esegue i comandi cde somecommand. Poiché si tratta di una shell figlio, la shell padre (la shell da cui si esegue questo comando) conserva la sua CWD e altre variabili di ambiente. donechiude semplicemente il corpo del loop.
Qix

questo metodo funziona per le sottodirectory delle directory:, for d in ./*/ ; do (cd "$d" && ls); donenon funzionerà. ma for d in ./*/ ; do (cd "$d" && for d in ./*/ ; do (cd "$d" && ls); done ); donefunzionerà. -usando ls come comando in questo esempio.
Michael Dimmitt,

-bash: cd: ./*/: No such file or directory
S. Tarık Çetin,

15

Il modo migliore è di non usare cdaffatto:

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

execdirè come exec, ma la directory di lavoro è diversa:

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

Non è POSIX.


Funziona con gli alias? Ne ho uno per scaricare alcuni file ma non lo riconosco quando scrivo find * /. Link -type f -execdir md $ (cat .link) {} \;
Qualcosa Jones,

@SomethingJones no, findesegue quei comandi, quindi non sarebbe a conoscenza di alias. Cos'è mded è .linkuna directory?
Muru,

.link è un file di testo che ha l'URL che deve scaricare. md è un alias da scommettere con un gruppo di flag impostati. C'è un modo per renderlo consapevole degli alias?
Qualcosa Jones

@SomethingJones per il vostro particolare caso d'uso, in bash: find . -type f -iname '*.link' -execdir ${BASH_ALIASES[md]} -i {} \;Non hai bisogno di fare catcon wget, che ha una -ibandiera per la lettura in un URL da un file. Inoltre, questo è in qualche modo diverso dalla domanda originale (poiché sembra che tu sia interessato solo ai file con nome .linke non a qualsiasi altro file che potrebbe essere presente).
muru,

Sai come farlo con zsh? Ho provato quello che mi hai dato e sto ricevendo un errore "Sostituzione errata". Inoltre, come potrei essere in grado di estrarre il contenuto del file .link? So di non averne bisogno in questo caso, ma immagino che presto lo farò.
Qualcosa Jones

2
cd -P .
for dir in ./*/
do cd -P "$dir" ||continue
   printf %s\\n "$PWD" >&2
   command && cd "$OLDPWD" || 
! break; done || ! cd - >&2

Il comando sopra non ha bisogno di fare alcun subshells - tiene semplicemente traccia dei suoi progressi nella shell corrente alternando $OLDPWDe $PWD. Quando cd -la shell scambia il valore di queste due variabili, fondamentalmente, in quanto cambia directory. Stampa anche il nome per ogni directory mentre lavora lì su stderr.

Ho appena dato una seconda occhiata e ho deciso che avrei potuto fare un lavoro migliore con la gestione degli errori. Salterà una directory in cui non può cd- e cdstamperà un messaggio sul perché stderr - e avrà breakun codice di uscita diverso da zero se il tuo commandnon viene eseguito correttamente o se l'esecuzione in commandqualche modo influisce sulla sua capacità di tornare alla directory originale - $OLDPWD. In quel caso fa anche un cd -ultimo - e scrive il nome della directory di lavoro corrente risultante su stderr.


1
for D in ./*; do
    if [ -d "$D" ]; then
        cd "$D"
        run_something
        cd ..
    fi
done
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.