Exec nous permet de passer tous les arguments à la fois avec {} +
ou de les passer un par un avec{} \;
Maintenant, disons que je veux renommer tous les fichiers jpeg , pas de problème en faisant ceci:
find . \( -name '*.jpg' -o -name '*.jpeg' \) -exec mv '{}' '{}'.new \;
Mais si j'ai besoin de rediriger la sortie, '{}'
n'est pas accessible après la redirection.
find . \( -name '*.jpg' -o -name '*.jpeg' \) -exec cjpeg -quality 80 '{}' > optimized_'{}' \;
Ça ne marcherait pas. Je devrais utiliser une boucle for, stockant la sortie de find dans une variable avant de l'utiliser. Admettons-le, c'est lourd.
for f in `find . \( -name '*.jpg' -o -name '*.jpeg' \)`; do cjpeg -quality 80 $f > optimized_$f; done;
Alors, y a-t-il une meilleure façon?
>
manquant dans le troisième exemple de code?{}
apparaît dans une chaîne plus longue car ces chaînes ne sont généralement pas développées.find
, une fois, et appliquée à lafind
commande elle-même. Le{}
n'a pas de signification particulière dans ce contexte. La redirection n'est pas un argumentfind
et ne fait certainement pas partie de la-exec
clause.Réponses:
Vous pouvez utiliser
bash -c
dans lafind -exec
commande et utiliser le paramètre positionnel avec la commande bash:De cette façon
{}
est fourni avec$1
.L'
sh
avant le{}
dit au shell interne son "nom", la chaîne utilisée ici est utilisée par exemple dans les messages d'erreur. Ceci est discuté plus dans cette réponse sur stackoverflow .la source
Vous avez une réponse ( https://unix.stackexchange.com/a/481687/4778 ), mais voici pourquoi.
La redirection
>
, ainsi que les tuyaux|
et l'$
expansion, sont tous effectués par le shell avant l'exécution de la commande. Par conséquent, stdout est redirigé versoptimized_{}
, avant lefind
démarrage.la source
La redirection doit être citée pour éviter que le shell actuel ne l'interprète.
Mais le citer évitera également la sortie de la commande à rediriger.
La solution connue à cela est d'appeler un shell:
Dans ce cas, la redirection (
>
) est citée sur le shell actuel et fonctionne correctement à l'intérieur du shell appelé. Lecalled_shell
est utilisé comme$0
paramètre (le nom) du shell enfant (sh
).Cela fonctionne bien si un suffixe est ajouté au nom du fichier, mais pas si vous utilisez un préfixe. Pour qu'un préfixe fonctionne, vous devez à la fois supprimer le préfixe
./
qui trouve les noms de fichiers avec${1#./}
et utiliser l'-execdir
option.Vous pouvez (ou non) à utiliser l'
-iname
option de sorte que les fichiers nommés*.JPG
ou*.JpG
ou d' autres variations sont également inclus.Et, vous pouvez (ou non) également appeler le shell une fois par répertoire au lieu d'une fois par fichier en ajoutant un loop (
for f do … ; done
) et un+
à la fin:Et, enfin, comme il
cjpeg
est possible d'écrire directement dans un fichier, la redirection pourrait être évitée comme:la source
cjpeg
a une option qui vous permet d'écrire dans un fichier nommé, plutôt que sur une sortie standard. Si votre version defind
prend en charge l'-execdir
option, vous pouvez en profiter pour rendre la redirection inutile.Remarque: cela suppose en fait la version BSD de
find
, qui semble./
supprimer le début du nom de fichier lors de l'extension{}
. (Ou à l'inverse, GNUfind
ajoute./
au nom. Il n'y a pas de norme pour dire quel comportement est "correct".)la source
find
supports-execdir
, vous pouvez utiliser cela au lieu de-exec
. Il provoque l'exécution de la commande dans le répertoire où le fichier a été trouvé et{}
deviendra à laaa.jpg
place de./t2/aa.jpg
.cjpeg: can't open optimized_./aa.jpg
.find
et BSDfind
. (Les dangers de l'utilisation d'extensions non standard.)./
semble plus sujet aux erreurs. Une solution raisonnable est proposée dans cette réponse .Créez un script cjq80:
Rendez-le exécutable
Et utilisez-le dans -exec:
la source