I risultati del ritrovamento non possono essere incapsulati tra virgolette

0

Su Linux, la gestione degli spazi quando sto utilizzando i risultati find richiede solo il wrapping della variabile tra virgolette. Questo non funziona su OS X. Questo codice, per esempio, non funziona:

for file in $(find . -name "*.txt")
do
    ls -l "${file}"
done

Anche racchiusi tra virgolette, parti di nomi di file separati da spazi vengono considerati come il loro risultato. Come posso risolvere questo problema?

    
posta Melab 29.08.2016 - 19:13
fonte

2 risposte

2

Da Bash Pitfalls (che spiega anche in dettaglio perché for file in (find ...); do non fa funziona):

When using find use it properly eg. use -exec

find . -type f -exec some command {} \;

Instead of ls consider,

for i in *.mp3; do    # Better! and...
    some command "$i" # ...always double-quote expansions!
done

POSIX shells such as Bash have the globbing feature specifically for this purpose -- to allow the shell to expand patterns into a list of matching filenames. There is no need to interpret the results of an external utility. Because globbing is the very last expansion step, each match of the *.mp3 pattern correctly expands to a separate word, and isn't subject to the effects of an unquoted expansion. (If you need to process files recursively, see UsingFind.)

Question: What happens if there are no *.mp3-files in the current directory? Then the for loop is executed once, with i="*.mp3", which is not the expected behavior! The workaround is to test whether there is a matching file:

# POSIX
for i in *.mp3; do
    [ -e "$i" ] || continue
    some command "$i"
done

Note the quotes around $i in the loop body above.

    
risposta data 30.08.2016 - 20:41
fonte
1

Il tuo codice non funziona su OS X o Linux.

for file in $(find . -name "*.txt")
do
    ls -l "${file}"
done

Prima la shell esegue l'espansione della sostituzione di comando $(find . -name "*.txt") I risultati sono simili ai seguenti: file with spaces\nanother file with spaces e così via. Ora, la shell esegue word spitting in base al valore di IFS - il separatore di campo interno. Il valore è in genere spazio bianco, tab e newline.

Esegui il seguente codice:

for file in $(find . -name "*.txt")
do
    echo "${file}"
done

Ora modifichiamo IFS solo per il carattere di nuova riga.

IFS='
'
for file in $(find . -name "*.txt")
do
    ls -l -- "${file}"
done

Il tuo codice funzionerà anche se ti consiglio di non cambiare IFS e trovare soluzioni alternative.

Sia GNU find che BSD find sono molto robusti e possono gestire nomi di file con spazi. Puoi evitare il loop e ottenere risultati simili con una riga

find . -name "*.txt" -ls
    
risposta data 29.08.2016 - 23:24
fonte

Leggi altre domande sui tag