trouver: argument manquant à -exec


18

J'essaie d'exécuter la commande suivante:

find a/folder b/folder -name *.c -o -name *.h -exec grep -I foobar '{}' +

Cela renvoie une erreur:

find: missing argument to -exec

Je ne vois pas ce qui ne va pas avec cette commande, car elle semble correspondre à la page de manuel:

-exec commande {} +

Cette variante de l'option -exec exécute la commande spécifiée sur les fichiers sélectionnés, mais la ligne de commande est créée en ajoutant à la fin chaque nom de fichier sélectionné; le nombre total d'appels de la commande sera bien inférieur au nombre de fichiers correspondants. La ligne de commande est construite de la même manière que xargs construit ses lignes de commande. Une seule instance de '{}' est autorisée dans la commande. La commande est exécutée dans le répertoire de départ.

J'ai aussi essayé:

find a/folder b/folder -name *.c -o -name *.h -exec grep -I foobar {} +
find a/folder b/folder -name *.c -o -name *.h -exec 'grep -I foobar' {} +
find a/folder b/folder -name *.c -o -name *.h -exec 'grep -I foobar' '{}' +
find a/folder b/folder -name "*.c" -o -name "*.h" -exec grep -I foobar '{}' +
find a/folder b/folder \( -name *.c -o -name *.h \) -exec grep -I foobar '{}' +
find a/folder b/folder -name *.c -o -name *.h -exec grep -I foobar '{}' \+

Avez-vous essayé de vous échapper +à la fin? find a/folder b/folder -name *.c -o -name *.h -exec grep -I foobar '{}' \+
jayhendren

3
Vous utilisez peut-être une ancienne version de GNU find. Bien que la -exec cmd {} +variante soit POSIX et soit disponible depuis les années 80, GNU find l'a ajoutée (relativement) récemment (2005). Qu'est-ce que ça find --versionvous dit?
Stéphane Chazelas

2
@Koveras, ce serait alors. -exec {} +a été ajouté en 4.2.12 en 2005. Dans les anciennes recherches GNU, vous pouvez utiliser le (non-POSIX) -print0 | xargs -r0pour obtenir quelque chose de similaire. 4.1date de 1994.
Stéphane Chazelas

1
JRFerguson a souligné (dans une réponse qui a été supprimé) que les -namedevraient être cités arguments de motif: -name "*.c" -o -name "*.h". C'est vrai, bien que cela ne soit pas lié à l' -execerreur. Vous remarquerez que toutes les autres réponses mettent les caractères génériques entre guillemets, bien que seul Gilles le mentionne. … (Suite)
G-Man dit «Réintègre Monica»

1
(Suite)… la réponse de jlliagre réduit l'expression du nom à -name "*.[ch]"sans explication. Cela présente l'avantage de simplifier la ligne de commande et, en particulier, d'éliminer le  -o. Il -oest difficile de trouver les expressions impliquant impliquant . La tienne a tort; si votre commande est corrigée de manière à ne pas générer d'erreur (comme dans la réponse de Gilles), elle ne s'exécutera grepque sur les .hfichiers. Tu dois faire '(' -name '*.c' -o -name '*.h' ')'.
G-Man dit `` Réintègre Monica ''

Réponses:


18

Vous devez supprimer les guillemets simples que vous utilisez {}. La commande peut être simplifiée comme ceci:

find a/folder b/folder -name "*.[ch]" -exec grep -I foobar {} +

Si vous utilisez une version de recherche GNU archaïque, cela devrait toujours fonctionner:

find a/folder b/folder -name "*.[ch]" -exec grep -I foobar {} \;

Oups, ils étaient censés être des citations et non des retours en arrière.
David Kennedy

Les citations seraient inutiles car {}n'ont pas de signification spécifique pour le shell.
jlliagre

A partir des pages de manuel de find: "La chaîne '{}' est remplacée par le nom de fichier actuel en cours de traitement partout où il apparaît dans les arguments de la commande, pas seulement dans les arguments où elle est seule, comme dans certaines versions de find. Les deux les constructions peuvent avoir besoin d'être échappées (avec un '\') ou citées pour les protéger de l'expansion par le shell. "
David Kennedy

1
J'ai en effet lu cela dans la page de manuel mais le fait est qu'il n'y a pas de shell à ma connaissance qui nécessite de citer les accolades. Quel shell utilisez-vous?
jlliagre

frapper. Avec ou sans les guillemets, je reçois quand même l'erreur.
David Kennedy

10

«Argument manquant à -exec» signifie généralement que l'argument à - execmanque son terminateur. Le terminateur doit être soit un argument contenant uniquement le caractère ;(qui doit être cité dans une commande shell, il est donc généralement écrit \;ou ';'), soit deux arguments successifs contenant {}et +.

Stephane Chazelas a identifié que vous utilisez une ancienne version de GNU find qui ne prend pas en charge -exec … {} +uniquement -exec {} \;. Bien que GNU ait été un adopteur tardif -exec … {} +, je recommande que vous obteniez une suite d'outils moins ancienne (comme Cygwin , qui comprend git et bien plus encore, ou GNUwin32 , qui manque de git mais n'a pas le mauvais employé qui essaie -à-utiliser-linux-mais-nous-imposons-vibe windows que Cygwin donne). Cette fonctionnalité a été ajoutée dans la version 4.2.12, il y a plus de 9 ans (c'était la dernière fonctionnalité identifiée pour faire GNUfind POSIX compatible).

Si vous souhaitez vous en tenir à une ancienne recherche GNU, vous pouvez utiliser -print0avec xargs -0pour obtenir une fonctionnalité similaire: exécution de commandes groupées, prise en charge de noms de fichiers arbitraires.

find a/folder b/folder -name '*.c' -o -name '*.h' -print0 | xargs -0 grep -I foobar /dev/null

Citez toujours les caractères génériques sur la findligne de commande. Sinon, si vous exécutez cette commande à partir d'un répertoire contenant des .cfichiers, le caractère non cité *.cserait étendu à la liste des .cfichiers du répertoire actuel.

L'ajout /dev/nullà la grepligne de commande est une astuce pour s'assurer que grep imprimera toujours le nom du fichier, même s'il findarrive de trouver une seule correspondance. Avec GNU find, une autre méthode consiste à passer l'option -H.


1
Qu'entendez-vous par ambiance de mauvais employé essayant d'utiliser Linux mais imposant Windows?
David Kennedy

GNUwin32 ne s'attend pas :(
David Kennedy

Voir mes commentaires sur la question.
G-Man dit `` Réintègre Monica ''

Les citations autour du semi ont fonctionné à partir d'un script package.json.
bvj

2

Si une commande telle que

find a/folder b/folder -name "*.c" -o -name "*.h" -exec grep -I foobar {} +

renvoie une erreur

find: missing argument to -exec

la cause probable est un GNU trop ancien findqui ne prend pas en charge la syntaxe -exec mycommand {} +. Dans ce cas, le remplacement à faible performance doit s'exécuter, -exec mycommand {} \;ce qui exécutera mycommandune fois pour chaque cible trouvée au lieu de collecter plusieurs cibles et d'exécuter lemycommand seule fois.

Cependant, GNU findne prend pas en charge par exemple

find . -type f -and -name "*.ttf" -exec cp {} ~/.fonts +

car GNU findne prend en charge que les combinaisons littérales {} +au lieu de plus génériques {} additional parameters +. Notez qu'il ne peut rien y avoir entre les accolades et le +caractère. Si vous essayez ceci, vous obtiendrez la même erreur:

find: missing argument to -exec

La solution consiste à utiliser une syntaxe {} additional parameters \;qui fonctionne mais qui exécutera la commande une fois pour chaque cible trouvée. Si vous avez besoin de plus de performances avec GNU, findvous devez écrire un script wrapper qui peut ajouter des paramètres supplémentaires aux arguments donnés. Quelque chose comme

#!/bin/bash
exec mycommand "$@" additional parameters

devrait être assez bon. Ou, si vous ne souhaitez pas créer de fichier temporaire, vous pouvez utiliser une ligne pour modifier l'ordre des paramètres comme ceci:

find . -type f -and -name "*.ttf" -exec bash -c 'mycommand "$@" extra arguments' {} +

qui s'exécutera mycommand {list of ttf files} extra arguments. Notez que vous devrez peut-être doubler les caractères spéciaux d'échappement pour le bash après le -cdrapeau.


(1) La partie de ce qui précède qui répond réellement à la question a déjà été donnée par d'autres personnes. (2) Ce que vous décrivez n'est pas une faille ou une déficience de GNU find, mais le comportement correct spécifié par POSIX .
G-Man dit `` Réintègre Monica ''

1
+1 Enfin, quelqu'un qui répond pourquoi les paramètres supplémentaires ne fonctionnent pas! Cela ressemble à une déficience dans la définition POSIX.
Jonathan

Si vous avez GNU, findvous avez probablement GNU cp. Dans ce cas, vous pouvez find ... -exec cp --target-directory ~/.fonts {} +conserver le {}à la fin de la chaîne d'exécution.
roaima

1

find . -type f -perm 0777 -exec chmod 644 {}\;

a obtenu une erreur find: missing argument to ``-exec' .

Ajouter de l'espace entre {}et \corrigé:

find . -type f -perm 0777 -print -exec chmod 644 {} \;


1
Il n'y a pas un tel problème dans la findcommande dans la question à l'étude.
Kusalananda

Dans Question, ce n'est pas, bien, que j'ai compris, mais le problème est le même "trouver: argument manquant à" -exec "", Le problème peut être dû à une raison différente-2, j'ai répondu parce que j'ai vu la même déclaration de problème.
ShreePool

@Kusalananda, bon deuil, le noob a fourni une solution à l'erreur signalée qui est indiquée par le PO dans le titre et le corps de la question.
bvj

@bvj La question porte explicitement sur la +forme de l' -execoption pour find. Cette réponse corrige un problème que l'utilisateur posant la question n'a pas.
Kusalananda

-1

J'ai eu ma part de maux de tête avec la syntaxe exec dans le passé. la plupart du temps, je préfère la syntaxe bash la plus agréable:

for f in `find a/folder b/folder -name "*.[ch]"`; do grep -I foobar $f; done

Il a certaines limites lorsque vous souhaitez traiter les fichiers en tant que groupe, car chacun est évalué en série, mais vous pouvez très bien diriger la sortie ailleurs


1
Bien que cela ait tendance à fonctionner, il est nettement moins utile que la version pure-find car elle ne peut pas gérer correctement les fichiers avec des espaces dans le nom.
Etan Reisner

5
Non, ne fais pas ça. Cela se casse dès que les fichiers contiennent des espaces et d'autres caractères «étranges». C'est également plus complexe et plus lent que find … -exec … \;, donc il n'y a aucune raison de l'utiliser même si vous savez que vos noms de fichiers sont apprivoisés.
Gilles 'SO- arrête d'être méchant'

cela a été utile pour ma situation où j'avais besoin d'exécuter plusieurs lignes de logique en fonction des noms de fichiers (comme supprimer des caractères, créer des répertoires puis déplacer les fichiers). Essayer de trouver de faire plusieurs choses en une execétait trop un casse-tête pour les 5 minutes que je voulais y consacrer. Mes noms de fichiers étaient apprivoisés et cela a résolu mon problème :)
gMale
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.