Estoy en Solaris 10 y he probado lo siguiente con ksh (88), bash (3.00) y zsh (4.2.1).
El siguiente código no produce ningún resultado:
function foo {
echo "Hello World"
}
find somedir -exec foo \;
El hallazgo coincide con varios archivos (como se muestra al reemplazar -exec ...
con -print
), y la función funciona perfectamente cuando se llama fuera de la find
llamada.
Esto es lo que man find
dice la página -exec
:
-exec comando True si el comando ejecutado devuelve un valor cero como estado de salida. El fin de el comando debe ser puntuado por un escape punto y coma (;). Un argumento de comando {} es reemplazado por la ruta actual. Si el El último argumento para -exec es {} y usted especifique + en lugar del punto y coma (;), el comando se invoca menos veces, con {} reemplazado por grupos de nombres de ruta. Si cualquier invocación del comando devuelve un valor distinto de cero como estado de salida, buscar devuelve un estado de salida distinto de cero.
Probablemente podría escapar haciendo algo como esto:
for f in $(find somedir); do
foo
done
Pero tengo miedo de lidiar con los problemas de separación de campos.
¿Es posible llamar a una función de shell (definida en el mismo script, no nos molestemos con problemas de alcance) desde una find ... -exec ...
llamada?
Lo he probado con ambos /usr/bin/find
y /bin/find
y obtuve el mismo resultado.
export -f foo
PATH
. Alternativamente, usesh -c '...'
y ambos definan Y ejecuten la función en el...
bit. Puede ser útil comprender las diferencias entre funciones y scripts .Respuestas:
A
function
es local para un shell, por lo que necesitaríafind -exec
generar un shell y tener esa función definida en ese shell antes de poder usarlo. Algo como:bash
permite exportar funciones a través del entornoexport -f
, por lo que puede hacer (en bash):ksh88
tienetypeset -fx
que exportar la función (no a través del entorno), pero eso solo puede ser usado por scripts de she-bang less ejecutados porksh
, así que no conksh -c
.Otra opción es hacer:
Es decir, use
typeset -f
para volcar la definición de lafoo
función dentro del script en línea. Tenga en cuenta que sifoo
usa otras funciones, también deberá volcarlas.fuente
ksh
obash
en el-exec
comando? Entiendo la primera, pero no la segunda ocurrencia.bash -c 'some-code' a b c
,$0
isa
,$1
isb
..., así que si quieres$@
serlo,a, b, c
debes insertar algo antes. Debido a$0
que también se usa cuando se muestran mensajes de error, es una buena idea usar el nombre del shell, o algo que tenga sentido en ese contexto.Esto no siempre es aplicable, pero cuando lo es, es una solución simple. Establezca la
globstar
opción (set -o globstar
en ksh93,shopt -s globstar
en bash ≥4; está activada por defecto en zsh). Luego, use**/
para hacer coincidir el directorio actual y sus subdirectorios de forma recursiva.Por ejemplo, en lugar de
find . -name '*.txt' -exec somecommand {} \;
, puedes ejecutarEn lugar de
find . -type d -exec somecommand {} \;
, puedes correrEn lugar de
find . -newer somefile -exec somecommand {} \;
, puedes correrCuando
**/
no funcione para usted (porque su shell no lo tiene o porque necesita unafind
opción que no tenga un análogo de shell), defina la función en elfind -exec
argumento .fuente
globstar
opción en la versión de ksh (ksh88
) que estoy usando.dtksh
(ksh93 con algunas extensiones X11), pero una versión anterior y posiblemente parte de un paquete opcional donde CDE es opcional.find
que excluye los archivos de puntos y no desciende en dotdirs y que clasifica la lista de archivos (los cuales pueden ser direcciones en zsh a través de calificadores de globbing). También**/*
en lugar de./**/*
, los nombres de archivo pueden comenzar con-
.Use \ 0 como delimitador y lea los nombres de archivo en el proceso actual desde un comando generado, de esta manera:
Que está pasando aqui:
read -d ''
lee hasta el siguiente \ 0 byte, por lo que no tiene que preocuparse por caracteres extraños en los nombres de archivo.-print0
usa \ 0 para terminar cada nombre de archivo generado en lugar de \ n.cmd2 < <(cmd1)
es lo mismo quecmd1 | cmd2
excepto que cmd2 se ejecuta en el shell principal y no en un subshell./dev/null
para garantizar que no se lea accidentalmente desde la tubería.$filename
se cita para que el shell no intente dividir un nombre de archivo que contiene espacios en blanco.Ahora,
read -d
y<(...)
están en zsh, bash y ksh 93u, pero no estoy seguro de las versiones anteriores de ksh.fuente
si desea un proceso secundario, generado a partir de su script, para usar una función de shell predefinida, debe exportarlo con
export -f <function>
NOTA:
export -f
es bash específicoya que solo un shell puede ejecutar funciones de shell :
EDITAR: esencialmente su script debería parecerse a esto:
fuente
export -f
es un error de sintaxisksh
e imprime la definición de la función en la pantallazsh
. En totalksh
,zsh
ybash
, no resuelve el problema.find / -exec /bin/bash -c 'function' \;
bash
. ¡Gracias!{}
en el código de shell! Eso significa que el nombre del archivo se interpreta como código shell también lo es muy peligroso