Existe-t-il un moyen d'obtenir find
pour 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
Existe-t-il un moyen d’obtenir le -exec
de find
pour voir dosomething
?
Puisque seul le shell sait comment exécuter les fonctions du shell, vous devez exécuter un shell pour exécuter une fonction. Vous devez également marquer votre fonction pour l'exportation avec export -f
, sinon le sous-shell ne les héritera pas:
export -f dosomething
find . -exec bash -c 'dosomething "$0"' {} \;
find . | while read file; do dosomething "$file"; done
Ajoutez des guillemets dans {}
comme indiqué ci-dessous:
export -f dosomething
find . -exec bash -c 'dosomething "{}"' \;
Ceci corrige toute erreur due aux caractères spéciaux renvoyés par find
, , Par exemple des fichiers avec des parenthèses dans leur nom.
La réponse de Jak ci-dessus est excellente, mais présente quelques pièges faciles à surmonter:
find . -print0 | while IFS= read -r -d '' file; do dosomething "$file"; done
Ceci utilise null comme délimiteur au lieu d'un saut de ligne, les noms de fichiers avec sauts de ligne fonctionneront. Il utilise également l'indicateur -r
qui désactive l'échappement de barre oblique inversée. Sans barres obliques inverses dans les noms de fichiers, cela ne fonctionnera pas. Il efface également IFS
de sorte que les espaces blancs de fin éventuels dans les noms ne soient pas ignorés.
Demandez au script de s’appeler lui-même, en passant chaque élément trouvé en argument:
#!/bin/bash
if [ ! $1 == "" ] ; then
echo "doing something with $1"
exit 0
fi
find . -exec $0 {} \;
exit 0
Lorsque vous exécutez le script seul, il trouve ce que vous recherchez et s’appelle lui-même en transmettant chaque résultat de recherche comme argument. Lorsque le script est exécuté avec un argument, il exécute les commandes de l'argument, puis se ferme.
Pour une efficacité accrue, de nombreuses personnes utilisent xargs
pour traiter les résultats en bloc, mais cela est très dangereux. À cause de cela, une autre méthode introduite dans find
qui exécute les résultats en bloc.
Notez cependant que cette méthode peut être assortie de certaines mises en garde, comme par exemple une exigence dans POSIX -find
d’avoir {}
à la fin de la commande.
export -f dosomething
find . -exec bash -c 'for f; do dosomething "$f"; done' _ {} +
find
transmettra de nombreux résultats en tant qu'arguments à un seul appel de bash
et la for
- boucle itérera à travers ces arguments, en exécutant la fonction dosomething
sur chacun de ceux-ci.
La solution ci-dessus commence les arguments à $1
, raison pour laquelle il existe un _
(qui représente $0
).
De même, je pense que la réponse la plus acceptée devrait être corrigée pour être
export -f dosomething
find . -exec bash -c 'dosomething "$1"' _ {} \;
Cela est non seulement plus sain, car les arguments doivent toujours commencer par $1
, mais l'utilisation de $0
pourrait également entraîner un comportement inattendu si le nom du fichier renvoyé par find
avait une signification particulière pour le shell.
Pour ceux d'entre vous qui recherchent une fonction bash qui exécutera une commande donnée sur tous les fichiers du répertoire courant, j'ai compilé une des réponses ci-dessus:
toall(){
find . -type f | while read file; do "$1" "$file"; done
}
Notez que cela rompt avec les noms de fichiers contenant des espaces (voir ci-dessous).
A titre d'exemple, prenons cette fonction:
world(){
sed -i 's_hello_world_g' "$1"
}
Disons que je voulais changer toutes les occurrences de hello to world dans tous les fichiers du répertoire actuel. Je ferais:
toall world
Pour être en sécurité avec les symboles figurant dans les noms de fichiers, utilisez:
toall(){
find . -type f -print0 | while IFS= read -r -d '' file; do "$1" "$file"; done
}
(mais vous avez besoin d’une find
qui gère -print0
, par exemple, GNU find
).
Je trouve le moyen le plus simple de suivre en répétant deux commandes en une seule
func_one () {
echo "first thing with $1"
}
func_two () {
echo "second thing with $1"
}
find . -type f | while read file; do func_one $file; func_two $file; done
Il n'est pas possible d'exécuter une fonction de cette façon.
Pour résoudre ce problème, vous pouvez placer votre fonction dans un script shell et l’appeler à partir de find
# dosomething.sh
dosomething () {
echo "doing something with $1"
}
dosomething $1
Maintenant, utilisez-le dans find comme:
find . -exec dosomething.sh {} \;
Placez la fonction dans un fichier séparé et obtenez find
pour l'exécuter.
Les fonctions du shell sont internes au shell dans lequel elles ont été définies; find
ne pourra jamais les voir.
Pas directement, non. Find s’exécute dans un processus séparé, pas dans votre shell.
Créez un script Shell faisant le même travail que votre fonction et trouvez peut -exec
that.
Pour référence, j'évite ce scénario en utilisant:
for i in $(find $dir -type f -name "$name" -exec ls {} \;); do
_script_function_call $i;
done;
Obtenez la sortie de find 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.