if comando in find -exec


10

Stavo solo cercando di elencare tutte le directory e i file nella directory corrente e anche di scrivere se sono file o directory con il seguente comando:

find -exec echo `echo {} : ;if [ -f {} ]; then echo file; else echo directory;fi` \;

So che è un comando sciocco, posso usare altre cose come -type fo -type d, ma voglio imparare perché quel pezzo di codice non ha funzionato come mi aspettavo. Stampa la directory su tutti. Ad esempio, mentre l'output di findè:

.
./dir
./dir/file

l'output del mio codice è:

. : directory
./dir : directory
./dir/file : directory

E uscita di

echo `echo dir/file : ;if [ -f dir/file ]; then echo file; else echo directory;fi`

è

dir/file : file

Sto lavorando Ubuntu 14.10e usandofind (GNU findutils) 4.4.2


1
find -exec bash -c 'echo -n "{} : ";if [ -f "{}" ]; then echo file; else echo directory;fi' \;
Costas,

1
Grazie @Costas ma so che usando bash o sh posso raggiungere il mio obiettivo iniziale, ma ora voglio capire perché se si comporta diversamente con il parametro exec.
Esref,

Metti gli argomenti tra virgolette "{}". Perché usi echodue volte?
Costas,

L'ho già provato e dà lo stesso risultato. trova -exec echo echo "{}" : ;if [ -f "{}" ]; then echo file; else echo directory;fi\;
Esref,

Risposte:


13

Innanzitutto, lo snippet esegue il comando

echo {} : ;if [ -f {} ]; then echo file; else echo directory;fi

perché ha bisogno del suo output per valutare la sostituzione del comando. Poiché non esiste alcun file denominato {}, questo produce l'output

{} :
directory

Poi il findcomando viene eseguito con gli argomenti -exec, echo, {}, :, directory, quindi per ogni file, emette il nome del file seguito da uno spazio e : directory.

Quello che vuoi veramente fare è eseguire lo snippet di shell echo {} :; …su ogni file trovato da find. Questo frammento deve essere eseguito da una shell generata da find, non dalla shell che si avvia find, poiché sta ricevendo dati dalla findsua riga di comando. Pertanto è necessario istruire findl'esecuzione di una shell:

find -exec sh -c 'echo {} : ;if [ -f {} ]; then echo file; else echo directory;fi' \;

Questo è meglio, ma ancora non è giusto. Funzionerà con alcune (non tutte) findimplementazioni se i nomi dei file non contengono caratteri speciali, ma poiché si interpola il nome del file in uno script di shell, si consente ai nomi di file di eseguire comandi di shell arbitrari, ad esempio se si dispone di un file chiamato $(rm -rf /)quindi il comando rm -rf /verrà eseguito. Per passare i nomi dei file allo script, passali come argomenti separati.

Anche il primo echostampa una nuova riga dopo i due punti. Usa echo -n(se la tua shell lo supporta) o printfper evitarlo.

find -exec sh -c 'printf "%s :" "$0"; if [ -f "$0" ]; then echo file; else echo directory; fi' {} \;

È possibile utilizzare -exec … {} +per raggruppare le invocazioni della shell, che è più veloce.

find -exec sh -c 'for x; do printf "%s :" "$x"; if [ -f "$x" ]; then echo file; else echo directory; fi; done' _ {} +

3

Un altro modo per eseguire if; then; else; fiinsieme findè:

find |
while read p; do if [ -f "$p" ]; then echo file; else echo directory; fi; done

1
Soluzione interessante. Evita schemi di virgolette complessi e complicazioni di subshell. Potresti aver precedentemente definito una funzione shell ed eseguirla sui file corrispondenti alla condizione "if".
Gerlos,
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.