trouver-exec une fonction shell sous Linux?

Est-il un moyen d'obtenir find pour exécuter une fonction que j'définir dans le shell? Par exemple:

dosomething () {
  echo "doing something with "
}
find . -exec dosomething {} ;

Le résultat est:

find: dosomething: No such file or directory

y a-t-il un moyen d'obtenir find 's -exec pour voir dosomething ?

143
demandé sur jww 2010-12-01 08:25:34

12 réponses

puisque seul le shell sait exécuter des fonctions 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 tréfoncier ne les héritera pas:

export -f dosomething
find . -exec bash -c 'dosomething ""151900920""' {} \;
197
répondu Adam Rosenfield 2013-02-22 05:13:58
find . | while read file; do dosomething "$file"; done
83
répondu Jac 2011-12-13 12:39:32

ajouter les guillemets {} comme suit:

export -f dosomething
find . -exec bash -c 'dosomething "{}"' \;

ceci corrige toute erreur due aux caractères spéciaux retournés par find , par exemple les fichiers avec des parenthèses dans leur nom.

17
répondu Wagner 2011-12-16 02:29:20

la réponse de Jak's ci-dessus est grande, mais a un couple d'écueils qui sont facilement surmontés:

find . -print0 | while IFS= read -r -d '' file; do dosomething "$file"; done

cela utilise null comme délimiteur au lieu d'un linefeed, donc les noms de fichiers avec linefeeds fonctionneront. Il utilise également le drapeau -r qui désactive backslash échappant, sans lui backslash dans les noms de fichiers ne fonctionnera pas. Il efface également IFS de sorte que les espaces blancs potentiels traînants dans les noms ne sont pas écartés.

12
répondu pajamian 2014-10-13 21:55:22

fait que le script s'appelle lui-même, en passant chaque élément trouvé comme argument:

#!/bin/bash

if [ !  == "" ] ; then
   echo "doing something with "
   exit 0
fi

find . -exec "151900920" {} \;

exit 0

quand vous exécutez le script par lui-même, il trouve ce que vous cherchez et s'appelle lui-même passant chaque résultat de find comme argument. Quand le script est lancé avec un argument, il exécute les commandes sur l'argument et puis sort.

8
répondu Mike Maready 2014-08-22 18:10:38

résultats du traitement en vrac

pour une efficacité accrue, beaucoup de gens utilisent xargs pour traiter les résultats en vrac, mais il est très dangereux. En raison de cela, il y avait une méthode alternative introduite dans find qui exécute les résultats en vrac.

noter cependant que cette méthode pourrait venir avec quelques 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 comme arguments à un seul appel de bash et la boucle for itère à travers ces arguments, exécutant la fonction dosomething sur chacun de ceux-ci.

la solution ci-dessus commence les arguments à , c'est pourquoi il y a un _ (qui représente " 1519120920" ).

les résultats de Traitement un par un

de la même manière, je je pense que la réponse la plus acceptée devrait être corrigée pour être

export -f dosomething
find . -exec bash -c 'dosomething ""' _ {} \;

ce n'est pas seulement plus sain, car les arguments devraient toujours commencer par , mais aussi utiliser " 1519120920 " pourrait conduire à un comportement inattendu si le nom de fichier retourné par find a une signification spéciale pour le shell.

6
répondu Dominik 2016-11-08 18:33:00

pour ceux d'entre vous qui cherchent une fonction bash qui exécutera une commande donnée sur tous les fichiers du répertoire courant, j'en ai compilé une à partir des réponses ci-dessus:

toall(){
    find . -type f | while read file; do "" "$file"; done
}

notez qu'il casse avec des noms de fichiers contenant des espaces (voir ci-dessous).

à titre d'exemple, prenez cette fonction:

world(){
    sed -i 's_hello_world_g' ""
}

dire que je voulais changer toutes les instances de hello to world dans tous les fichiers dans le courant répertoire. Je ferais:

toall world

pour être sûr avec n'importe quel symbole dans les noms de fichiers, utilisez:

toall(){
    find . -type f -print0 | while IFS= read -r -d '' file; do "" "$file"; done
}

(mais vous avez besoin d'un find qui gère -print0 par exemple, GNU find ).

2
répondu Jason Basanese 2017-04-09 17:54:51

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 de find

# dosomething.sh
dosomething () {
  echo "doing something with "
}
dosomething 

utilisez-le maintenant dans find as:

find . -exec dosomething.sh {} \;
1
répondu codaddict 2010-12-01 05:29:00

place la fonction dans un fichier séparé et obtient find pour l'exécuter.

les fonctions Shell sont internes au shell dans lequel elles sont définies; find ne sera jamais capable de les voir.

1
répondu Angus 2010-12-01 05:29:14

je trouve la voie la plus facile comme suit, en répétant deux commandes en une seule do

func_one () {
  echo "first thing with "
}

func_two () {
  echo "second thing with "
}

find . -type f | while read file; do func_one $file; func_two $file; done
1
répondu edib 2017-07-07 09:12:02

Pas directement, non. Find est exécuté 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 cela.

0
répondu Laurence Gonsalves 2010-12-01 05:27:57

je voudrais éviter d'utiliser -exec tout à fait. Pourquoi ne pas utiliser xargs ?

find . -name <script/command you're searching for> | xargs bash -c
-4
répondu Barry 2014-04-11 22:16:21