In che modo 'trova -exec' passa i nomi dei file con spazi?


14

Se ho una directory contenente alcuni file i cui nomi hanno spazi, ad es

$ ls -1 dir1
file 1
file 2
file 3

Posso copiarli con successo in un'altra directory come questa:

$ find dir1 -mindepth 1 -exec cp -t dir2 {} +

Tuttavia, l'output di find dir1 -mindepth 1contiene spazi non di escape:

$ find dir1 mindepth 1
dir1/file 1
dir1/file 3
dir1/file 3

Se uso print0invece di print, l'output contiene ancora spazi non di escape:

$ find dir1 mindepth 1 -print0
dir1/file 1dir1/file 2dir1/file 3

Per copiare questi file manualmente usando cp, avrei bisogno di sfuggire agli spazi; ma sembra che ciò non sia necessario quando cpprovengono gli strumenti find, indipendentemente dal fatto che io usi +o \;alla fine del comando.

Qual è la ragione di questo?

Risposte:


8

Il findcomando esegue direttamente il comando. Il comando, incluso l'argomento nome file, non verrà elaborato dalla shell o da qualsiasi altra cosa che possa modificare il nome file. È molto sicuro.

Lei ha ragione che non c'è bisogno di sfuggire i nomi dei file che sono rappresentati da {}sulla findlinea di comando.

findpassa il nome file non elaborato direttamente dal disco all'elenco degli argomenti interni del -execcomando, nel tuo caso il cpcomando.


1
In poche parole, find..execpuò gestire strani nomi di file da solo ..
heemayl

2
La prima regola del linux club è di non analizzare ls
Sergiy Kolodyazhnyy,

5

La domanda è in due parti:

  • come non find gestire i programmi di chiamata utilizzando -execsenza incorrere in problemi con spazi incorporati nei nomi dei file, e
  • a che serve l' -print0opzione?

Per il primo, findsta effettuando una chiamata di sistema, in realtà una di un gruppo di chiamate correlate indicate come "exec" . Passa il nome file come argomento direttamente a questa chiamata, che viene quindi passato direttamente (dopo aver creato un nuovo processo) senza perdere informazioni sul nome file.

La findfunzione POSIX +è spiegata come segue, nella logica :

Una caratteristica finddell'utilità di SVR4 era -exec+ terminator del primario. Ciò ha permesso di raggruppare nomi di file contenenti caratteri speciali (in particolare i caratteri di nuova riga ) senza i problemi che si verificano se tali nomi di file vengono convogliati xargs. Altre implementazioni hanno aggiunto altri modi per aggirare questo problema, in particolare un -print0primario che ha scritto nomi di file con un terminatore di byte null. Questo è stato considerato qui, ma non adottato. L'uso di un terminatore null significava che qualsiasi utilità che stava per elaborare l' -print0output di find doveva aggiungere una nuova opzione per analizzare i terminatori null che ora avrebbe letto.

Che "in particolare un -print0primario" si riferisce a GNU finde xargsche risolvono il problema in modo diverso. È anche supportato da FreeBSD finde xargs. Se hai aggiunto -0un'opzione (vedi la pagina del manuale ) alla xargschiamata, quel programma accetta le linee terminate da caratteri "null byte". A sua volta, xargschiama exec -functions per fare il suo lavoro. La principale distinzione tra la funzione -print0e -0rispetto alla+ funzione è che la prima passa i nomi dei file su una pipe, mentre la seconda no. Gli sviluppatori trovano usi per quasi tutte le funzionalità; i tubi non fanno eccezione.

Torna all'esempio di OP, che utilizza -tun'opzione per cp: che non si trova in POSIX cp . Piuttosto, è un'estensione (nota anche come "funzionalità non standard") fornita da GNU cp . L' -0estensione di xargsquesto esempio non migliorerebbe, ma ci sono altri casi in cui può essere utilizzato in modo efficace, tenendo presente che esiste un'alternativa portatile +, che GNU findaccetta.


-1

( Questo dovrebbe essere un commento ma è troppo grande. )

Per coloro a cui piace provare le cose:

Crea uno script che elenca i parametri posizionali passati, chiamalo list_positional_parameters.sh.

#!/bin/bash

# http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_09_07.html
# Try globbing patterns, e.g. "X[[:digit:]][[:digit:]]" to see what happens

if [ $# -lt 1 ]; then
   echo "Usage: $0 and then at least one parameter"
   exit 1
fi

counter=1

while (($#)); do
   echo "$counter = '$1'"
   # pop positional argument 1 off the stack of positional arguments
   shift
   (( counter++ ))
done

Esegui findcon esso su alcune directory $ dir:

find "$dir" -exec ./list_positional_parameters.sh '{}' ';' | less

Come previsto, esiste un solo parametro in tutte le chiamate, il nome file, indipendentemente dal fatto che vi siano spazi nel suo nome.


1
Puoi anche usare printflike printf '"%s"\n' "$@"per stampare tutti gli argomenti posizionali citati, per l'ispezione visiva.
Kusalananda
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.