Jessaye dexécuter la commande suivante:
find a/folder b/folder -name *.c -o -name *.h -exec grep -I foobar "{}" +
Ceci renvoie une erreur:
find: missing argument to -exec
Je ne peux « pas voir ce qui ne va pas avec cette commande, car elle semble correspondre à la page de manuel :
-exec command {} +
Cette variante de loption -exec exécute la commande spécifiée sur les fichiers sélectionnés, mais la ligne de commande est construite en ajoutant chaque nom de fichier sélectionné à la fin; le nombre total dappels de la commande sera bien inférieur au nombre de fichiers correspondants. La ligne de commande est construite à peu près de la même manière que xargs construit son 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.
Jai 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 "{}" \+
Commentaires
Réponse
Il y a eu plusieurs problèmes avec vos tentatives, y compris des rétroprojecteurs utilisés à la place des guillemets (supprimés lors des modifications ultérieures de la question), des guillemets manquants là où ils sont nécessaires, des guillemets supplémentaires là où ils sont inutiles, des parenthèses manquantes pour le groupe -o
, et différentes implémentations de find
utilisées (voir les commentaires et le chat pour plus de détails).
Quoi quil en soit, la commande peut être simplifiée comme ceci:
find a/folder b/folder -name "*.[ch]" -exec grep -I foobar {} +
ou, 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 {} \;
Commentaires
- Oups, ils étaient censés être des guillemets et non des backticks.
- Les citations seraient inutiles car
{}
na pas de signification spécifique pour le shell. - À partir des pages de manuel de recherche: » La chaîne ‘ { } ‘ est remplacé par le nom de fichier en cours de traitement partout où il apparaît dans les arguments de la commande, pas seulement dans les arguments où il est seul, comme dans certaines versions de find. Ces deux constructions peuvent avoir besoin dêtre échappées (avec un ‘ \ ‘) ou entre guillemets pour les protéger de lexpansion par le shell. »
- Jai bien lu cela dans la page de manuel mais le fait est quil ny a pas de shell que je ‘ connais cela nécessite de citer les accolades. Quel shell utilisez-vous?
- bash. Avec ou sans les guillemets, jobtiens lerreur de toute façon.
Réponse
« argument manquant à -exec
« signifie généralement que largument de – exec
na pas de terminateur. Le terminateur doit être soit un argument contenant uniquement le caractère ;
(qui doit être entre guillemets dans une commande shell, il est donc généralement écrit \;
ou ";"
), ou deux arguments successifs contenant {}
et +
.
Stéphane 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é lun des derniers à adopter -exec … {} +
, je vous recommande de vous procurer une suite doutils moins ancienne (telle que Cygwin , qui inclut git et bien plus encore, ou GNUwin32 , qui manque de git mais na pas le mauvais-employé-essayant-dutiliser-linux -but-we-impos-windows que donne Cygwin). 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 à faire GNU find
Compatible POSIX).
Si vous souhaitez vous en tenir à une ancienne recherche GNU, vous pouvez utiliser -print0
avec xargs -0
pour obtenir une fonctionnalité similaire: exécution de commandes groupées, prenant en charge les 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 find
ligne de commande. Sinon, si vous exécutez cette commande à partir dun répertoire contenant des fichiers .c
, les fichiers *.c
sans guillemets d être étendu à la liste des fichiers .c
dans le répertoire actuel.
Ajout de /dev/null
au grep
la ligne de commande est une astuce pour sassurer que grep affichera toujours le nom du fichier, même si find
trouve une seule correspondance. Avec GNU find, une autre méthode consiste à passer loption -H
.
Commentaires
- Que faites-vous signifie par mauvais-employé-essayant-dutiliser-linux-mais-nous-imposons-la vibration que donne cygwin?
- GNUwin32 ne ‘ pas 🙁
- Voir mes commentaires sur la question.
- Les guillemets autour du semi ont fonctionné à partir dun script package.json.
Réponse
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 trop ancienne GNU find
qui ne prend pas en charge la syntaxe -exec mycommand {} +
. Dans ce cas, le remplacement de faibles performances consiste à exécuter -exec mycommand {} \;
qui exécutera mycommand
une fois pour chaque cible trouvée au lieu de collecter plusieurs cibles et exécuter le mycommand
une seule fois.
Cependant, GNU find
doe ne prend pas en charge par exemple
find . -type f -and -name "*.ttf" -exec cp {} ~/.fonts +
car GNU find
ne prend en charge que les combinaisons littérales {} +
au lieu de {} additional parameters +
plus génériques. Notez quil 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 de contournement consiste à utiliser la syntaxe {} additional parameters \;
qui fonctionne mais exécutera la commande une fois pour chaque cible trouvée. Si vous avez besoin de plus de performances avec GNU find
, vous 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 suffire. Ou, si vous ne souhaitez pas créer de fichier temporaire, vous pouvez utiliser une ligne pour changer lordre des paramètres comme celui-ci:
find . -type f -and -name "*.ttf" -exec bash -c "mycommand "$@" extra arguments" {} +
qui 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 lindicateur -c
.
Commentaires
- (1) La partie de ce qui précède qui répond réellement à la question a déjà été donnée par dautres personnes. (2) Ce que vous décrivez nest pas une faille ou une carence dans GNU
find
, mais le comportement correct spécifié par POSIX . - +1 Enfin, quelquun qui répond pourquoi les paramètres supplémentaires ne fonctionnent pas ‘! Cela semble être une lacune dans la définition POSIX.
- Si vous ‘ vous GNU
find
vous ‘ jai probablement GNUcp
. Dans ce cas, vous pouvezfind ... -exec cp --target-directory ~/.fonts {} +
conserver le{}
à la fin de la chaîne dexécution.
Réponse
find . -type f -perm 0777 -exec chmod 644 {}\;
a obtenu une erreur find: missing argument to ``-exec"
.
Lajout despace entre {}
et \
a corrigé le problème:
find . -type f -perm 0777 -print -exec chmod 644 {} \;
Commentaires
- Ce problème nexiste pas dans le
find
dans la question en question. - Dans Question ce nest pas, très bien, que jai compris, mais le problème est le même » find: argument manquant à « -exec ‘ « , Le problème peut survenir pour une raison différente-2, jai répondu parce que jai vu la même déclaration de problème.
- @Kusalananda bon chagrin, le noob a fourni une solution à lerreur signalée qui est indiquée par le PO dans le titre et le corps de la question.
- @bvj La question traite explicitement avec la forme
+
de loption-exec
àfind
. Cette réponse corrige un problème que lutilisateur qui pose la question na pas.
Réponse
Jai eu mon part de maux de tête avec la syntaxe exec dans le passé. la plupart du temps maintenant, je préfère la meilleure syntaxe bash:
for f in `find a/folder b/folder -name "*.[ch]"`; do grep -I foobar $f; done
Il y a quelques limitations lorsque vous voulez traiter les fichiers comme un groupe, car chacun est évalué en série, mais vous pouvez diriger la sortie ailleurs très bien
Commentaires
- 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.
- Non, ‘ ne faites pas cela. Cela sarrête dès que les fichiers contiennent des espaces et dautres caractères «bizarres». Cest également plus complexe et plus lent que
find … -exec … \;
, donc il ny a ‘ aucune raison de lutiliser même si vous savez que vos noms de fichiers sont apprivoiser. - cela a été utile dans ma situation où je devais exécuter plusieurs lignes de logique basées sur les noms de fichiers (comme supprimer des caractères, créer des répertoires, puis déplacer les fichiers). Essayer dobtenir find pour faire plusieurs choses en un seul
exec
était trop difficile pour les 5 minutes que je voulais y consacrer. Mes noms de fichiers étaient apprivoisés et cela a résolu mon problème 🙂
+
à la fin?find a/folder b/folder -name *.c -o -name *.h -exec grep -I foobar '{}' \+
find
. Bien que la variante-exec cmd {} +
soit POSIX et soit disponible depuis les années 80, GNU find la seulement ajoutée (relativement) récemment (2005). Que vous ditfind --version
?-exec {} +
a été ajouté dans la version 4.2.12 en 2005. Dans les anciennes découvertes GNU, vous pouvez utiliser le-print0 | xargs -r0
(non-POSIX) pour obtenir quelque chose similaire.4.1
date de 1994.-name
les arguments doivent être entre guillemets:-name "*.c" -o -name "*.h"
. Cest vrai, même si cela na aucun rapport avec lerreur-exec
. Vous remarquerez que toutes les autres réponses mettent les jokers entre guillemets, bien que seul Gilles le mentionne. … (Suite)-name "*.[ch]"
sans explication. Cela présente les avantages de simplifier la ligne de commande et, en particulier, déliminer les-o
. Il est difficile de trouver des expressions impliquant-o
. Le vôtre est faux; si votre commande est corrigée de manière à ne pas afficher derreur (comme dans la réponse de Gilles), elle exécuteragrep
uniquement sur le.h
des dossiers. Vous devez faire'(' -name '*.c' -o -name '*.h' ')'
.