Je suis sur Solaris 10 et j'ai testé les éléments suivants avec ksh (88), bash (3.00) et zsh (4.2.1).
Le code suivant ne donne aucun résultat:
function foo {
echo "Hello World"
}
find somedir -exec foo \;
La recherche correspond à plusieurs fichiers (comme indiqué en remplaçant -exec ...
par -print
), et la fonction fonctionne parfaitement lorsqu'elle est appelée en dehors de l' find
appel.
Voici ce que dit la man find
page -exec
:
-exec, commande True si la commande exécutée renvoie un valeur zéro comme état de sortie. La fin de la commande doit être ponctuée par un échappé point-virgule (;). Un argument de commande {} est remplacé par le chemin d'accès actuel. Si la le dernier argument de -exec est {} et vous spécifiez + plutôt que le point-virgule (;), la commande est invoquée moins de fois, avec {} remplacé par des groupes de chemins d'accès. Si toute invocation de la commande renvoie un valeur non nulle comme état de sortie, rechercher renvoie un état de sortie différent de zéro.
Je pourrais probablement m'en tirer en faisant quelque chose comme ça:
for f in $(find somedir); do
foo
done
Mais j'ai peur de traiter des problèmes de séparateur de champs.
Est-il possible d'appeler une fonction shell (définie dans le même script, ne nous soucions pas des problèmes de portée) à partir d'un find ... -exec ...
appel?
Je l' ai essayé avec les deux /usr/bin/find
et /bin/find
et a obtenu le même résultat.
export -f foo
PATH
. Alternativement, utilisezsh -c '...'
et définissez ET exécutez la fonction dans le...
bit. Il peut être utile de comprendre les différences entre les fonctions et les scripts .Réponses:
A
function
est local à un shell, vous devezfind -exec
donc générer un shell et avoir cette fonction définie dans ce shell avant de pouvoir l'utiliser. Quelque chose comme:bash
permet d'exporter des fonctions via l'environnement avecexport -f
, donc vous pouvez faire (en bash):ksh88
doittypeset -fx
exporter la fonction (pas via l'environnement), mais qui ne peut être utilisée que par des scripts she-bang moins exécutés parksh
, donc pas avecksh -c
.Une autre option consiste à faire:
Autrement dit, utilisez
typeset -f
pour vider la définition de lafoo
fonction à l'intérieur du script en ligne. Notez que si vousfoo
utilisez d'autres fonctions, vous devrez également les vider.la source
ksh
oubash
dans la-exec
commande? Je comprends le premier, mais pas le deuxième.bash -c 'some-code' a b c
,$0
isa
,$1
isb
..., donc si vous voulez l'$@
être,a, b, c
vous devez insérer quelque chose avant. Parce que$0
est également utilisé lors de l'affichage des messages d'erreur, c'est une bonne idée d'utiliser le nom du shell, ou quelque chose qui a du sens dans ce contexte.Ce n'est pas toujours applicable, mais quand c'est le cas, c'est une solution simple. Définissez l'
globstar
option (set -o globstar
dans ksh93,shopt -s globstar
dans bash ≥4; elle est activée par défaut dans zsh). Utilisez ensuite**/
pour faire correspondre le répertoire en cours et ses sous-répertoires de manière récursive.Par exemple, au lieu de
find . -name '*.txt' -exec somecommand {} \;
, vous pouvez exécuterAu lieu de
find . -type d -exec somecommand {} \;
, vous pouvez exécuterAu lieu de
find . -newer somefile -exec somecommand {} \;
, vous pouvez exécuterLorsque
**/
ne fonctionne pas pour vous (parce que votre shell ne l'a pas ou parce que vous avez besoin d'unefind
option qui n'a pas d'analogue de shell), définissez la fonction dans l'find -exec
argument .la source
globstar
option sur la version de ksh (ksh88
) que j'utilise.dtksh
(ksh93 avec quelques extensions X11), mais une ancienne version et peut-être une partie d'un package facultatif où CDE est facultatif.find
fait qu'il exclut les fichiers de points et ne descend pas dans les répertoires de points et qu'il trie la liste des fichiers (qui peuvent tous deux être des adresses en zsh via des qualificatifs de remplacement). Aussi, par**/*
opposition à./**/*
, les noms de fichiers peuvent commencer par-
.Utilisez \ 0 comme délimiteur et lisez les noms de fichiers dans le processus en cours à partir d'une commande générée, comme ceci:
Que se passe t-il ici:
read -d ''
lit jusqu'au prochain \ 0 octet, vous n'avez donc pas à vous soucier des caractères étranges dans les noms de fichiers.-print0
utilise \ 0 pour terminer chaque nom de fichier généré au lieu de \ n.cmd2 < <(cmd1)
est le même quecmd1 | cmd2
sauf que cmd2 est exécuté dans le shell principal et non dans un sous-shell./dev/null
pour s'assurer qu'il ne lit pas accidentellement depuis le tube.$filename
est cité afin que le shell n'essaye pas de diviser un nom de fichier contenant des espaces.Maintenant,
read -d
et<(...)
sont en zsh, bash et ksh 93u, mais je ne suis pas sûr des versions précédentes de ksh.la source
si vous voulez qu'un processus enfant, généré à partir de votre script, utilise une fonction shell prédéfinie, vous devez l'exporter avec
export -f <function>
REMARQUE:
export -f
est spécifique à bashcar seul un shell peut exécuter des fonctions shell :
EDIT: essentiellement votre script devrait ressembler à ceci:
la source
export -f
est une erreur de syntaxe dansksh
, et imprime la définition de la fonction à l'écran danszsh
. Dans tousksh
,zsh
etbash
cela ne résout pas le problème.find / -exec /bin/bash -c 'function' \;
bash
. Merci!{}
dans le code shell! Cela signifie que le nom du fichier est interprété comme un code shell, il est donc très dangereux