trouver: argument manquant à -exec

206

J'ai été aidé aujourd'hui avec une commande, mais cela ne semble pas fonctionner. Voici la commande:

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

Le shell revient

find: missing argument to `-exec'

Ce que j'essaie essentiellement de faire est de parcourir un répertoire récursivement (s'il a d'autres répertoires) et d'exécuter la commande ffmpeg sur les .rmtypes de fichiers et de les convertir en .mp3types de fichiers. Une fois cela fait, supprimez le .rmfichier qui vient d'être converti.

J'apprécie toute aide à ce sujet.

Abdos
la source

Réponses:

340

Une -execcommande doit être terminée par un ;(vous devez donc généralement taper \;ou ';'éviter une interprétation par le shell) ou un +. La différence est qu'avec ;, la commande est appelée une fois par fichier, avec +elle est appelée aussi peu de fois que possible (généralement une fois, mais il y a une longueur maximale pour une ligne de commande, donc elle peut être divisée) avec tous les noms de fichiers . Voir cet exemple:

$ 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

Votre commande comporte deux erreurs:

Tout d'abord, vous utilisez {};, mais le ;doit être un paramètre qui lui est propre.

Deuxièmement, la commande se termine à &&. Vous avez spécifié «exécuter la recherche, et si cela a réussi, supprimez le fichier nommé {};.». Si vous souhaitez utiliser des éléments shell dans la -execcommande, vous devez l'exécuter explicitement dans un shell, tel que -exec sh -c 'ffmpeg ... && rm'.

Cependant, vous ne devez pas ajouter le {} dans la commande bash, cela produira des problèmes lorsqu'il y a des caractères spéciaux. Au lieu de cela, vous pouvez passer des paramètres supplémentaires au shell après -c command_string(voir man sh):

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

Vous voyez que la $chose est évaluée par le shell dans le premier exemple. Imaginez qu'il y ait un fichier appelé $(rm -rf /):-)

(Note latérale: le -n'est pas nécessaire, mais la première variable après la commande est affectée à la variable $0, qui est une variable spéciale contenant normalement le nom du programme en cours d'exécution et la définition d'un paramètre est un peu impure, même si elle a gagné ne causera probablement aucun mal ici, nous avons donc réglé cela juste -pour commencer $1.)

Donc, votre commande pourrait être quelque chose comme

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

Mais il y a une meilleure façon. trouver des supports andet or, donc vous pouvez faire des choses comme find -name foo -or -name bar. Mais cela fonctionne également avec -exec, qui évalue à true si la commande se termine avec succès et à false dans le cas contraire. Voir cet exemple:

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

Il exécute l'impression uniquement si la commande a réussi, ce qu'elle a fait pour truemais pas pour false.

Vous pouvez donc utiliser deux instructions exec chaînées avec un -and, et il n'exécutera ce dernier que si le premier a été exécuté avec succès.

Marian
la source
3
La clé semble être la ligne de Marian de "the; is a arg on its own", c'est ce qui l'a fait pour moi, en ce qui concerne les ampoules et pour mon exemple de code. Merci.
pjammer
3
C'est à peu près la meilleure description que j'ai lue sur -exec. C'est extrêmement puissant mais j'ai toujours du mal à obtenir la bonne syntaxe. Cela a rendu certaines choses beaucoup plus claires. Emballage particulier de la commande dans un shell séparé. Agréable. Merci.
Eurospoofer
3
Notez que -andet -orne sont pas portables. POSIX spécifie -aet-o , et en fait -aest toujours supposé (donc pas nécessaire).
gniourf_gniourf
Il doit également y avoir un espace devant le terminateur. Ex "\;"ne fonctionne pas mais " \;"fonctionne
frmdstryr
56

Je l'ai compris maintenant. Lorsque vous devez exécuter deux commandes dans exec dans une recherche, vous devez en fait avoir deux execs distincts. Cela a finalement fonctionné pour moi.

find . -type f -name "*.rm" -exec ffmpeg -i {} -sameq {}.mp3 \; -exec rm {} \;
Abdos
la source
Vous ne savez pas si la variable du fichier sera supprimée? Quelqu'un sait si c'est le cas?
Abs
7
Pour tester de telles choses, ajoutez simplement un echoavant les commandes et voyez ce qu'il fait.
Marian
2
@Marian, echoest assez peu fiable - vous ne pouvez pas faire la différence entre echo "one argument"et echo one argument(la sortie de ce dernier étant fausse, car elle passe en fait echodeux arguments complètement séparés). Il vaut bien mieux faire quelque chose comme -exec bash -c 'printf "%q " "$@"' _ ffmpeg -i {} -sameq {}.mp3 \; -printf '\n', qui imprimera la sortie d'une manière qui rendra les caractères non imprimables visibles afin que vous puissiez détecter les sauts de ligne DOS et autres bizarreries.
Charles Duffy
52

Essayez de mettre un espace avant chaque \;

Travaux:

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

Ne fonctionne pas:

find . -name "*.log" -exec echo {}\;
Dustin Cowles
la source
1
Cela me fait monter souvent. Un de ces jours, j'ajouterai un espace par défaut.
harperville
Pour moi, cela fonctionne exactement dans Cygwin sous Windows 7: pas d'espace avant \; fonctionne, avec l'espace - ne fonctionne pas. Mais si j'enlève \, avec de l'espace avant; cela fonctionne, et sans espace avant; ce n'est pas le cas, juste comme il est décrit ici.
WebComer
7

Juste pour votre information:
je viens d'essayer d'utiliser la commande "find -exec" sur un système Cygwin (émulé UNIX sur Windows), et il semble que la barre oblique inverse avant le point-virgule doit être supprimée:
find ./ -name "blabla" -exec wc -l {} ;

Dominique
la source
J'ai vraiment confondu. find /etc/nginx -name '*.conf' -exec echo {} ;et a find /etc/nginx -name '*.conf' -exec echo {}\;donné le même résultat. :(
Kirby
J'utilise le shell Bash fourni avec Git pour Windows, et la réponse de Dustin Cowles fonctionne pour moi. En d'autres termes: pas de guillemets, barre oblique inverse échappée par un point-virgule, espace après {}.
mamacdon
Il n'y a pas de différence de sens, mais dans certains cas, vous devez mettre la barre oblique inverse, dans certains cas, vous ne pouvez pas le mettre, et dans d'autres cas, vous pouvez choisir.
Dominique
2

Juste au cas où quelqu'un verrait un "argument -exec manquant" similaire dans les scripts bash d'Amazon Opsworks Chef, j'avais besoin d'ajouter une autre barre oblique inverse pour échapper au \;

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

De plus, si quelqu'un d'autre a l'argument "find: missing to -exec", cela pourrait aider:

Dans certains shells, vous n'avez pas besoin de vous échapper, c'est-à-dire que vous n'avez pas besoin du "\" devant le ";".

find <file path> -name "myFile.*" -exec rm - f {} ;
sellmaurer
la source
2
Le fait de ;ne pas être cité ou échappé ici signifie qu'il peut être consommé par le shell, et non lu par find. Aussi, -fet ce - fsont deux choses différentes.
Charles Duffy
1

Vous devez vous échapper, je pense.

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

{} Et && causeront des problèmes en raison de l'extension de la ligne de commande. Je suggère d'essayer:

find /home/me/download/ -type f -name "*.rm" -exec ffmpeg -i \{} -sameq \{}.mp3 \; -exec rm \{} \;
VeeArr
la source
Si la première commande dans exec réussit et la deuxième commande dans exec est exécutée, aura-t-elle toujours accès à la {}variable pour supprimer le bon fichier?
Abs
À quoi vous épilez-vous {}? Sauf s'il contient deux points ou virgules qui resteront tels quels.
Marian
0

Vous devez mettre un espace entre {}et\;

La commande sera donc comme:

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

Si vous obtenez toujours "find: argument manquant à -exec", essayez de placer l'argument d'exécution entre guillemets.

find <file path> -type f -exec "chmod 664 {} \;"
courtiser
la source