Y a-t-il un moyen d'obtenir find
exécuter une fonction que je définis dans le shell? Par exemple:
dosomething () {
echo "doing something with $1"
}
find . -exec dosomething {} \;
Le résultat est:
find: dosomething: No such file or directory
Y at - il un moyen de find
« s -exec
pour voir dosomething
?
$0
.find . -exec bash -c 'dosomething "$0"' {} \;
il gérera les espaces (et autres caractères étranges) dans les noms de fichiers ...export -f
ne fonctionnera que dans certaines versions de bash. Ce n'est pas posix, pas crossplatforn,/bin/sh
aura une erreur avec luila source
while read
pour une boucle for;for item in $(find . ); do some_function "${item}"; done
La réponse de Jak ci-dessus est excellente mais comporte quelques écueils faciles à surmonter:
Cela utilise null comme délimiteur au lieu d'un saut de ligne, donc les noms de fichiers avec des sauts de ligne fonctionneront. Il utilise également l'
-r
indicateur qui désactive l'échappement de la barre oblique inverse, sans cela, les barres obliques inverses dans les noms de fichiers ne fonctionneront pas. Il efface également deIFS
sorte que les espaces blancs de fin potentiels dans les noms ne soient pas ignorés.la source
/bin/bash
mais ne fonctionnera pas/bin/sh
. C'est dommage.Ajoutez des citations
{}
comme indiqué ci-dessous:Cela corrige toute erreur due à des caractères spéciaux renvoyés par
find
, par exemple, des fichiers avec des parenthèses dans leur nom.la source
{}
. Cela va casser pour un nom de fichier contenant des guillemets doubles.touch '"; rm -rf .; echo "I deleted all you files, haha
. Oups.-exec bash -c 'echo $0' '{}' \;
Notez que lors de l'utilisationbash -c
, $ 0 est le premier argument, pas le nom du script.Traitement des résultats en masse
Pour une efficacité accrue, de nombreuses personnes utilisent
xargs
pour traiter les résultats en vrac, mais c'est très dangereux. Pour cette raison, une autre méthode a été introduite dansfind
exécuter les résultats en masse.Notez cependant que cette méthode peut être accompagnée de quelques mises en garde comme par exemple une exigence dans POSIX-
find
à avoir{}
à la fin de la commande.find
passera de nombreux résultats en tant qu'arguments à un seul appel debash
et lefor
-loop parcourt ces arguments, exécutant la fonctiondosomething
sur chacun de ceux-ci.La solution ci-dessus commence les arguments à
$1
, c'est pourquoi il y a un_
(qui représente$0
).Traitement des résultats un par un
De la même manière, je pense que la première réponse acceptée doit être corrigée pour être
Ce n'est pas seulement plus sain, car les arguments doivent toujours commencer à
$1
, mais l'utilisation$0
peut également conduire à un comportement inattendu si le nom de fichier renvoyé parfind
a une signification particulière pour le shell.la source
Faites appeler le script lui-même, en passant chaque élément trouvé en argument:
Lorsque vous exécutez le script seul, il trouve ce que vous recherchez et s'appelle lui-même en passant chaque résultat de la recherche comme argument. Lorsque le script est exécuté avec un argument, il exécute les commandes sur l'argument puis se ferme.
la source
find: ‘myscript.sh’: No such file or directory
si commencé en tant quebash myscript.sh
...Pour ceux d'entre vous qui recherchent une fonction bash qui exécutera une commande donnée sur tous les fichiers du répertoire actuel, j'en ai compilé une à partir des réponses ci-dessus:
Notez qu'il rompt avec les noms de fichiers contenant des espaces (voir ci-dessous).
À titre d'exemple, prenez cette fonction:
Disons que je voulais changer toutes les instances de hello en monde dans tous les fichiers du répertoire actuel. Je ferais:
Pour être sûr de tous les symboles dans les noms de fichiers, utilisez:
(mais vous avez besoin d'un
find
qui gère-print0
par exemple GNUfind
).la source
Je trouve le moyen le plus simple comme suit, en répétant deux commandes en une seule opération
la source
Pour référence, j'évite ce scénario en utilisant:
Obtenez la sortie de la recherche dans le fichier de script actuel et parcourez la sortie comme vous le souhaitez. Je suis d'accord avec la réponse acceptée, mais je ne veux pas exposer la fonction en dehors de mon fichier de script.
la source
Il n'est pas possible d'exécuter une fonction de cette façon.
Pour surmonter cela, vous pouvez placer votre fonction dans un script shell et l'appeler depuis
find
Maintenant, utilisez-le dans find comme:
la source
dosomething $1
=>dosomething "$1"
et démarrer correctement votre fichier avecfind . -exec bash dosomething.sh {} \;
Mettez la fonction dans un fichier séparé et obtenez
find
exécutez-le.Les fonctions du shell sont internes au shell dans lequel elles sont définies;
find
ne pourra jamais les voir.la source
Pour apporter des ajouts et des clarifications à certaines des autres réponses, si vous utilisez l'option bulk pour
exec
ouexecdir
(-exec command {} +
) et que vous souhaitez récupérer tous les arguments de position, vous devez envisager la gestion de$0
withbash -c
. Plus concrètement, considérez la commande ci-dessous, qui utilisebash -c
comme suggéré ci-dessus, et fait simplement écho aux chemins de fichiers se terminant par '.wav' de chaque répertoire qu'il trouve:Le manuel bash dit:
Voici
'check $@'
la chaîne de commande et_ {}
les arguments après la chaîne de commande. Notez qu'il$@
s'agit d'un paramètre de position spécial dans bash qui s'étend à tous les paramètres de position à partir de 1 . Notez également qu'avec l'-c
option, le premier argument est affecté au paramètre positionnel$0
. Cela signifie que si vous essayez d'accéder à tous les paramètres de position avec$@
, vous n'obtiendrez que les paramètres commençant par$1
et plus. C'est la raison pour laquelle la réponse de Dominik a le_
, qui est un argument factice pour remplir le paramètre$0
, donc tous les arguments que nous voulons sont disponibles plus tard si nous utilisons l'$@
expansion des paramètres par exemple, ou la boucle for comme dans cette réponse.Bien sûr, similaire à la réponse acceptée,
bash -c 'shell_function $0 $@'
cela fonctionnerait également en passant explicitement$0
, mais encore une fois, vous devez garder à l'esprit que$@
cela ne fonctionnera pas comme prévu.la source
Pas directement, non. Find s'exécute dans un processus séparé, pas dans votre shell.
Créez un script shell qui fait le même travail que votre fonction et trouvez
-exec
-le.la source
J'éviterais
-exec
complètement d' utiliser . Pourquoi ne pas l'utiliserxargs
?la source