trova: argomento mancante per -exec


206

Sono stato aiutato oggi con un comando, ma non sembra funzionare. Questo è il comando:

find /home/me/download/ -type f -name "*.rm" -exec ffmpeg -i {} -sameq {}.mp3 && rm {}\;

La shell ritorna

find: missing argument to `-exec'

Quello che sto sostanzialmente cercando di fare è passare ricorsivamente in una directory (se ha altre directory) ed eseguire il comando ffmpeg sui .rmtipi di file e convertirli in .mp3tipi di file. Fatto ciò, rimuovere il .rmfile che è appena stato convertito.

Apprezzo qualsiasi aiuto in merito.

Risposte:


340

Un -execcomando deve essere terminato con un ;(quindi di solito è necessario digitare \;o ';'per evitare l'interpretazione da parte della shell) o un +. La differenza è che con ;, il comando viene chiamato una volta per file, con +, viene chiamato il minor numero di volte possibile (di solito una volta, ma esiste una lunghezza massima per una riga di comando, quindi potrebbe essere suddiviso) con tutti i nomi di file . Vedi questo esempio:

$ cat /tmp/echoargs
#!/bin/sh
echo $1 - $2 - $3
$ find /tmp/foo -exec /tmp/echoargs {} \;
/tmp/foo - -
/tmp/foo/one - -
/tmp/foo/two - -
$ find /tmp/foo -exec /tmp/echoargs {} +
/tmp/foo - /tmp/foo/one - /tmp/foo/two

Il tuo comando ha due errori:

In primo luogo, si utilizza {};, ma ;deve essere un parametro a sé stante.

In secondo luogo, il comando termina in &&. Hai specificato "run find, e se ciò ha avuto successo, rimuovi il file chiamato {};.". Se si desidera utilizzare roba di shell nel -execcomando, è necessario eseguirla esplicitamente in una shell, ad esempio -exec sh -c 'ffmpeg ... && rm'.

Comunque non dovresti aggiungere {} all'interno del comando bash, produrrà problemi quando ci sono caratteri speciali. Invece, puoi passare parametri aggiuntivi alla shell dopo -c command_string(vedi man sh):

$ ls
$(echo damn.)
$ find * -exec sh -c 'echo "{}"' \;
damn.
$ find * -exec sh -c 'echo "$1"' - {} \;
$(echo damn.)

Vedi la $cosa viene valutata dalla shell nel primo esempio. Immagina che ci fosse un file chiamato $(rm -rf /):-)

(Nota a margine: -non è necessario, ma la prima variabile dopo il comando è assegnata alla variabile $0, che è una variabile speciale che normalmente contiene il nome del programma in esecuzione e l'impostazione su un parametro è un po 'sporca, anche se ha vinto probabilmente causerà qualche danno qui, quindi lo impostiamo su giusto -e per cominciare $1.)

Quindi il tuo comando potrebbe essere qualcosa di simile

find -exec bash -c 'ffmpeg -i "$1" -sameq "$1".mp3 && rm "$1".mp3' - {} \;

Ma c'è un modo migliore. trovare supporti ande or, quindi, puoi fare cose come find -name foo -or -name bar. Ma funziona anche con -exec, che valuta vero se il comando termina correttamente e falso in caso contrario. Vedi questo esempio:

$ ls
false  true
$ find * -exec {} \; -and -print
true

Esegue la stampa solo se il comando è stato eseguito correttamente, cosa che ha fatto per truema non per false.

Quindi puoi usare due istruzioni exec concatenate con an -and, e eseguirà quest'ultima solo se la prima è stata eseguita con successo.


3
La chiave sembra essere la linea di Marian di "il; è un argomento a parte" che è quello che ha fatto per me, saggia lampadina e per il mio esempio di codice. Grazie.
— Pjammer,

3
Questa è la migliore descrizione che ho letto su -exec. È estremamente potente ma trovo sempre difficile ottenere la sintassi giusta per questo. Questo ha reso alcune cose molto più chiare. In particolare avvolgendo il comando nella shell separata. Bello. Grazie.
— Eurospoofer,

3
Si noti che -ande -ornon sono portatili. POSIX specifica -ae-o , di fatto, -aviene sempre assunto (quindi non necessario).
— gniourf_gniourf

Inoltre, deve essere presente uno spazio prima del terminatore. Ex "\;"non funziona ma " \;"funziona
— frmdstryr

56

L'ho capito ora. Quando è necessario eseguire due comandi in exec in una ricerca, è necessario disporre effettivamente di due exec separati. Questo alla fine ha funzionato per me.

find . -type f -name "*.rm" -exec ffmpeg -i {} -sameq {}.mp3 \; -exec rm {} \;

Non sei sicuro se riuscirà a eliminare la variabile del file? Qualcuno sa se questo è il caso?
— Abs

7
Per provare queste cose basta aggiungere un echoprima dei comandi e vedere cosa fa.
— Marian,

2
@Marian, echoè abbastanza inaffidabile - non puoi dire la differenza tra echo "one argument"e echo one argument(l'output di quest'ultimo è falso, dato che in realtà sta passando echodue argomenti completamente separati). Molto meglio fare qualcosa del genere -exec bash -c 'printf "%q " "$@"' _ ffmpeg -i {} -sameq {}.mp3 \; -printf '\n', che stamperà l'output in modo da rendere visibili i caratteri non stampabili in modo da poter rilevare nuove righe DOS e altre stranezze.
— Charles Duffy,

52

Prova a mettere uno spazio prima di ogni \;

Lavori:

find . -name "*.log" -exec echo {} \;

Non funziona:

find . -name "*.log" -exec echo {}\;

1
Questo mi fa inciampare abbastanza spesso. Uno di questi giorni, aggiungerò uno spazio per impostazione predefinita.
— Harperville,

Per me funziona esattamente l'opposto in Cygwin in Windows 7: nessuno spazio prima di \; funziona, con spazio - no. Ma se rimuovo \, con spazio prima; funziona e senza spazio prima; non lo è, proprio come descritto qui.
— WebComer

7

Per vostra informazione:
ho appena provato a usare il comando "trova -exec" su un sistema Cygwin (UNIX emulato su Windows), e lì sembra che la barra rovesciata prima del punto e virgola debba essere rimossa:
find ./ -name "blabla" -exec wc -l {} ;


Sono davvero confuso. find /etc/nginx -name '*.conf' -exec echo {} ;e ha find /etc/nginx -name '*.conf' -exec echo {}\;dato lo stesso risultato. :(
— Kirby

Sto eseguendo la shell Bash fornita con Git per Windows e la risposta di Dustin Cowles funziona per me. In altre parole: senza virgolette, barra rovesciata sfuggita al punto e virgola, spazio dopo {}.
— mamacdon,

Non c'è differenza nel significato, ma in alcuni casi è necessario inserire la barra rovesciata, in alcuni casi non è possibile inserirla, e in altri casi è possibile scegliere.
— Dominique,

2

Nel caso in cui qualcuno veda un simile "Argomento -exec mancante" negli script bash di Amazon Opsworks Chef, ho dovuto aggiungere un'altra barra rovesciata per sfuggire a \;

bash 'remove_wars' do
  user 'ubuntu'
  cwd '/'
  code <<-EOH
    find /home/ubuntu/wars -type f -name "*.war" -exec rm {} \\;
  EOH
  ignore_failure true
end

2

Inoltre, se qualcun altro ha l'argomento "trova: manca a -exec" questo potrebbe aiutare:

In alcune shell non è necessario eseguire l'escaping, ovvero non è necessario il "\" davanti al ";".

find <file path> -name "myFile.*" -exec rm - f {} ;

2
Il ;non essere citato o sfuggito qui significa che può essere consumato dalla shell, non letto da find. Inoltre, -fe - fsono due cose diverse.
— Charles Duffy,

1

Dovresti scappare, credo.

find /home/me/download/ -type f -name "*.rm" -exec ffmpeg -i {} \-sameq {}.mp3 \&\& rm {}\;

0

Sia {} che && causeranno problemi a causa dell'espansione dalla riga di comando. Suggerirei di provare:

find /home/me/download/ -type f -name "*.rm" -exec ffmpeg -i \{} -sameq \{}.mp3 \; -exec rm \{} \;

Se il primo comando in exec ha esito positivo e viene eseguito il secondo comando in exec, avrà comunque accesso alla {}variabile per eliminare il file giusto?
— Abs

In cosa si {}espande Thinik ? A meno che non contenga due punti o virgole che rimarranno così come sono.
— Marian,

0

Devi mettere uno spazio tra {}e\;

Quindi il comando sarà come:

find /home/me/download/ -type f -name "*.rm" -exec ffmpeg -i {} -sameq {}.mp3 && rm {} \;

-4

Se stai ancora ottenendo "trova: argomento mancante per -exec" prova a racchiudere l'argomento execute tra virgolette.

find <file path> -type f -exec "chmod 664 {} \;"
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.