291 votes

find : argument manquant pour -exec

On m'a aidé aujourd'hui avec une commande, mais elle ne semble pas fonctionner. Voici la commande :

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

Le shell renvoie

find: missing argument to `-exec'

Ce que j'essaie de faire, c'est de parcourir un répertoire de manière récursive (s'il contient d'autres répertoires) et d'exécuter la commande ffmpeg sur le fichier .rm et les convertir en .mp3 types de fichiers. Une fois que cela est fait, supprimez le .rm qui vient d'être converti.

J'apprécie toute aide à ce sujet.

444voto

Marian Points 1640

A -exec doit être terminée par un ; (vous devez donc généralement taper \; ou ';' pour éviter l'interprétation par l'interpréteur de commandes) ou un fichier + . 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 :

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

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

Cependant, vous ne devriez pas ajouter les {} à l'intérieur de 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 à l'interpréteur de commandes 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 le $ est évalué par le shell dans le premier exemple. Imaginez qu'il y ait un fichier appelé $(rm -rf /) :-)

(Note complémentaire : le - n'est pas nécessaire, mais la première variable après la commande est assignée à la variable $0 Il s'agit d'une variable spéciale contenant normalement le nom du programme en cours d'exécution et le fait de la définir comme paramètre est un peu impur, même si cela ne causera probablement aucun dommage ici. - et commencer par $1 .)

Votre commande pourrait donc être quelque chose comme

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

Mais il y a un meilleur moyen. Trouvez des supports and et or donc vous pouvez faire des choses comme find -name foo -or -name bar . Mais cela fonctionne aussi avec -exec qui est évalué à true si la commande se termine avec succès, et à false sinon. Voir cet exemple :

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

Il n'exécute l'impression que si la commande s'est déroulée avec succès, ce qui a été le cas pour true mais pas pour false .

Vous pouvez donc utiliser deux instructions exec enchaînées avec une instruction -and et il n'exécutera la seconde que si la première a été exécutée avec succès.

4 votes

La clé semble être la ligne de Marian "the ; is an arg on it's own", c'est ce qui a fait l'affaire pour moi, dans le sens de l'illumination et pour mon échantillon de code. merci.

4 votes

C'est à peu près la meilleure description que j'ai lue sur -exec. Il est extrêmement puissant mais je trouve toujours difficile d'obtenir la bonne syntaxe pour lui. Cela a rendu certaines choses beaucoup plus claires. En particulier le fait d'envelopper la commande dans le shell séparé. Joli. Merci.

4 votes

Notez que -and et -or ne sont pas portables. POSIX spécifie -a et -o et en fait -a est toujours présumée (et n'est donc pas nécessaire).

79voto

Dustin Cowles Points 145

Essayez de mettre un espace avant chaque mot ;

Travaux :

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

Ça ne marche pas :

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

3 votes

Cela me fait trébucher assez souvent. Un de ces jours, j'ajouterai un espace par défaut.

0 votes

Pour moi, cela fonctionne exactement à l'inverse dans Cygwin sous Windows 7 : sans espace avant \ ; fonctionne, avec espace - ne fonctionne pas. Mais si j'enlève \, avec un espace avant ; ça marche, et sans espace avant ; ça ne marche pas, exactement comme c'est décrit ici.

68voto

Abs Points 6035

J'ai trouvé la solution maintenant. Lorsque vous devez exécuter deux commandes en exec dans un find, vous devez en fait avoir deux exec séparés. Cela a finalement fonctionné pour moi.

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

0 votes

Je ne suis pas sûr qu'il obtiendra la variable du fichier à supprimer ? Quelqu'un sait-il si c'est le cas ?

9 votes

Pour tester de telles choses, il suffit d'ajouter un echo avant les commandes et voir ce que ça donne.

3 votes

@Marian, echo n'est pas du tout fiable - on ne peut pas faire la différence entre echo "one argument" et echo one argument (la sortie de cette dernière étant fausse, car elle passe en fait echo deux arguments complètement distincts). Il est préférable de 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 visibles les caractères non imprimables afin que vous puissiez détecter les nouvelles lignes DOS et autres bizarreries.

3voto

Matthew Smith Points 469

Tu dois t'échapper, je pense.

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

1voto

VeeArr Points 3504

{} et && causent tous deux des problèmes car ils sont développés par la ligne de commande. Je vous suggère d'essayer :

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

0 votes

Si la première commande dans exec réussit et que la deuxième commande dans exec est exécutée, aura-t-elle toujours accès au {} variable pour supprimer le bon fichier ?

0 votes

Qu'est-ce que tu crois ? {} s'étend à ? À moins qu'il ne contienne deux points ou deux virgules, il restera tel quel.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X