Idealmente non lo fai affatto in questo modo, perché analizzare correttamente i nomi dei file in uno script di shell è sempre difficile (correggilo per gli spazi, avrai ancora problemi con altri caratteri incorporati, in particolare la nuova riga). Questo è anche elencato come la prima voce nella pagina BashPitfalls.
Detto questo, c'è un modo per fare quasi quello che vuoi:
oIFS=$IFS
IFS=$'\n'
find . -name '*.txt' | while read -r i; do
# use "$i" with whatever you're doing
done
IFS=$oIFS
Ricordati di citare anche $i
quando lo si utilizza, per evitare altre cose interpretando gli spazi in seguito. Ricorda inoltre di impostare $IFS
indietro dopo averlo usato, perché non farlo causerà errori sconcertanti in seguito.
Questo ha un altro avvertimento:cosa succede all'interno del while
loop può avvenire in una subshell, a seconda della shell esatta che stai utilizzando, quindi le impostazioni delle variabili potrebbero non persistere. Il for
la versione loop lo evita ma al prezzo che, anche se applichi il $IFS
soluzione per evitare problemi con gli spazi, ti ritroverai nei guai se find
restituisce troppi file.
Ad un certo punto la soluzione corretta per tutto questo diventa farlo in un linguaggio come Perl o Python invece che in shell.
Usa find -print0
e reindirizzalo a xargs -0
, o scrivi il tuo piccolo programma C e invialo al tuo piccolo programma C. Questo è ciò che -print0
e -0
sono stati inventati per.
Gli script di shell non sono il modo migliore per gestire i nomi di file con spazi all'interno:puoi farlo, ma diventa goffo.
Puoi impostare il "separatore di campo interno" (IFS
) in qualcosa di diverso dallo spazio per la suddivisione degli argomenti del ciclo, ad esempio
ORIGIFS=${IFS}
NL='
'
IFS=${NL}
for i in $(find . -name '*.txt'); do
IFS=${ORIGIFS}
#do stuff
done
IFS=${ORIGIFS}
Ho resettato IFS
dopo il suo utilizzo in find, soprattutto perché ha un bell'aspetto, credo. Non ho riscontrato alcun problema nell'averlo impostato su newline, ma penso che questo sia "più pulito".
Un altro metodo, a seconda di cosa vuoi fare con l'output di find
, consiste nell'usare direttamente -exec
con il find
comando o usa -print0
e reindirizzalo in xargs -0
. Nel primo caso find
si occupa dell'escape del nome del file. Nel -print0
caso, find
stampa il suo output con un separatore null, quindi xargs
si divide su questo. Poiché nessun nome di file può contenere quel carattere (quello che so), anche questo è sempre sicuro. Questo è utile soprattutto in casi semplici; e di solito non è un ottimo sostituto per un for
completo ciclo.