TL; DR: Se sei qui solo per la risposta più corretta, probabilmente vuoi la mia preferenza personale, find . -name '*.txt' -exec process {} \;
(vedi il fondo di questo post). Se hai tempo, leggi tutto il resto per vedere diversi modi e problemi con la maggior parte di essi.
La risposta completa:
Il modo migliore dipende da cosa vuoi fare, ma qui ci sono alcune opzioni. Finché nessun file o cartella nella sottostruttura ha spazi vuoti nel suo nome, puoi semplicemente passare in rassegna i file:
for i in $x; do # Not recommended, will break on whitespace
process "$i"
done
Marginalmente meglio, ritaglia la variabile temporanea x
:
for i in $(find -name \*.txt); do # Not recommended, will break on whitespace
process "$i"
done
È molto meglio glob quando puoi. Spazio vuoto sicuro, per i file nella directory corrente:
for i in *.txt; do # Whitespace-safe but not recursive.
process "$i"
done
Abilitando l' globstar
opzione, puoi glob tutti i file corrispondenti in questa directory e in tutte le sottodirectory:
# Make sure globstar is enabled
shopt -s globstar
for i in **/*.txt; do # Whitespace-safe and recursive
process "$i"
done
In alcuni casi, ad esempio se i nomi dei file sono già in un file, potrebbe essere necessario utilizzare read
:
# IFS= makes sure it doesn't trim leading and trailing whitespace
# -r prevents interpretation of \ escapes.
while IFS= read -r line; do # Whitespace-safe EXCEPT newlines
process "$line"
done < filename
read
può essere utilizzato in sicurezza in combinazione con l' find
impostazione del delimitatore in modo appropriato:
find . -name '*.txt' -print0 |
while IFS= read -r -d '' line; do
process "$line"
done
Per ricerche più complesse, probabilmente vorrai utilizzare find
, con la sua -exec
opzione o con -print0 | xargs -0
:
# execute `process` once for each file
find . -name \*.txt -exec process {} \;
# execute `process` once with all the files as arguments*:
find . -name \*.txt -exec process {} +
# using xargs*
find . -name \*.txt -print0 | xargs -0 process
# using xargs with arguments after each filename (implies one run per filename)
find . -name \*.txt -print0 | xargs -0 -I{} process {} argument
find
può anche eseguire il cd nella directory di ciascun file prima di eseguire un comando utilizzando -execdir
invece di -exec
e può essere reso interattivo (prompt prima di eseguire il comando per ciascun file) utilizzando -ok
invece di -exec
(o -okdir
invece di-execdir
).
*: Tecnicamente, entrambi find
e xargs
(per impostazione predefinita) eseguiranno il comando con tutti gli argomenti che possono adattarsi alla riga di comando, tutte le volte che ci vuole per passare attraverso tutti i file. In pratica, a meno che tu non abbia un numero molto elevato di file, non importa, e se superi la lunghezza ma ne hai bisogno tutti sulla stessa riga di comando, sei SOL a trovare un modo diverso.