find -exec: aggiunge argomenti tra {} e +

Oct 21 2020

Voglio usare trova per individuare i file, quindi copiarli in una directory, quindi ho provato:

find . -name '*.png' -exec cp {} /tmp/dest +

Tuttavia, questo non riesce con

find: missing argument to `-exec'

Quando sostituisco +con a ;funziona, ma invoca cp per ogni file individualmente. Come posso aggiungere un argomento finale (come una directory di destinazione) quando si utilizza la +forma di -exec?

Ovviamente, in questo caso posso aggirare l'apparente limitazione usando cp -t(come indicato in questo post su Stack Overflow , ma quella soluzione è specifica per cp. Invece, potrei usare rsync, scp o qualche altro strumento. un modo generale per aggiungere argomenti tra {}e +in find -exec?

Risposte

12 Kusalananda Oct 21 2020 at 19:22

No, se stai usando -exec ... {} +, potrebbe non esserci nulla tra {}e +oltre agli spazi bianchi. Non c'è modo di aggirarlo.

Dalla specifica standard POSIX del il findcomando :

-exec utility_name [argument ...] ;
-exec utility_name [argument ...] {} +

La fine dell'espressione primaria deve essere punteggiata da a <semicolon>o da a <plus-sign>. Solo un <plus-sign>che segue immediatamente un argomento contenente solo i due caratteri {}punteggia la fine dell'espressione primaria. Altri usi del <plus-sign>non devono essere trattati come speciali.

Potrebbe essere una soluzione più generica

find ... -exec sh -c 'cp "$@" /tmp/dest' sh {} +

Qui, uno sh -cscript inline viene eseguito con batch di argomenti da find. All'interno dello script inline, "$@"ci sarà l'elenco degli argomenti passati (quotati individualmente), che ci permette di posizionarli come vogliamo sulla cpriga di comando.

Questo ci permette di usare non GNU cp(ad esempio su macOS o altri sistemi BSD, dove non ci sono -topzioni) o qualsiasi altra utility in cui si potrebbe voler aggiungere altri argomenti alla fine dell'elenco dei nomi di percorso provenienti da find.

Relazionato:

  • Comprensione dell'opzione -exec di `find`

Nessuno lo ha chiesto, ma comunque ...

Con la directory di destinazione in una variabile, destdir:

destdir=/tmp/dest

find ... -exec sh -c 'destdir=$1; shift; cp "$@" "$destdir"' sh "$destdir" {} +

Notare che la destdirchiamata nella shell findè una variabile separata dalla destdirnello sh -cscript.

Oppure, con bash:

destdir=/tmp/dest

find ... -exec bash -c 'cp "${@:2}" "$1"' bash "$destdir" {} +

Questo significa "affettare" l' "$@"elenco per riorganizzarlo in modo appropriato per la cpriga di comando, senza estrarre $1il percorso della directory di destinazione, in una variabile separata.