find-exec una función de shell en Linux?
bash bsd (12)
¿Hay alguna manera de hacer que find
ejecute una función que defino en el shell? Por ejemplo:
dosomething () {
echo "doing something with $1"
}
find . -exec dosomething {} /;
El resultado de eso es:
find: dosomething: No such file or directory
¿Hay alguna manera de obtener find
-s -exec
para ver dos dosomething
?
Resultados de procesamiento a granel
Para una mayor eficiencia, muchas personas usan xargs
para procesar los resultados de forma masiva, pero es muy peligroso. Debido a eso, se introdujo un método alternativo en find
que ejecuta los resultados de forma masiva.
Sin embargo, tenga en cuenta que este método puede tener algunas advertencias, como por ejemplo, un requisito en POSIX: find
para tener {}
al final del comando.
export -f dosomething
find . -exec bash -c ''for f; do dosomething "$f"; done'' _ {} +
find
pasará muchos resultados como argumentos a una sola llamada de bash
y el -loop itera a través de esos argumentos, ejecutando la función dosomething
en cada uno de ellos.
La solución anterior inicia argumentos en $1
, que es por lo que hay un _
(que representa $0
).
Resultados de procesamiento uno a uno
De la misma manera, creo que la respuesta superior aceptada debe corregirse para ser
export -f dosomething
find . -exec bash -c ''dosomething "$1"'' _ {} /;
Esto no solo es más sensato, porque los argumentos siempre deberían comenzar en $1
, pero también usar $0
podría llevar a un comportamiento inesperado si el nombre del archivo devuelto por find
tiene un significado especial para el shell.
Agrega citas en {}
como se muestra a continuación:
export -f dosomething
find . -exec bash -c ''dosomething "{}"'' /;
Esto corrige cualquier error debido a caracteres especiales devueltos por find
, por ejemplo, archivos con paréntesis en su nombre.
Como solo el shell sabe cómo ejecutar funciones de shell, debe ejecutar un shell para ejecutar una función. También debe marcar su función para exportar con export -f
; de lo contrario, la subshell no los heredará:
export -f dosomething
find . -exec bash -c ''dosomething "$0"'' {} /;
Encuentro la manera más fácil de seguir, repitiendo dos comandos en solo hacer
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
Haga que el script se llame a sí mismo, pasando cada elemento encontrado como argumento:
#!/bin/bash
if [ ! $1 == "" ] ; then
echo "doing something with $1"
exit 0
fi
find . -exec $0 {} /;
exit 0
Cuando ejecuta el script por sí mismo, encuentra lo que está buscando y se llama pasando cada resultado de búsqueda como argumento. Cuando el script se ejecuta con un argumento, ejecuta los comandos en el argumento y luego sale.
La respuesta de Jak anterior es excelente, pero tiene un par de trampas que se superan fácilmente:
find . -print0 | while IFS= read -r -d '''' file; do dosomething "$file"; done
Esto utiliza null como un delimitador en lugar de un salto de línea, por lo que los nombres de archivo con avances de línea funcionarán. También usa el indicador -r
que desactiva el escape de barra invertida, sin que las barras invertidas en nombres de archivo no funcionen. También borra IFS
para que no se descarten los espacios en blanco posteriores potenciales en los nombres.
No directamente, no. Find se está ejecutando en un proceso separado, no en su caparazón.
Cree un script de shell que -exec
el mismo trabajo que su función y encuentre can -exec
eso.
No es posible ejecutar una función de esa manera.
Para superar esto, puede colocar su función en un script de shell y llamarlo desde find
# dosomething.sh
dosomething () {
echo "doing something with $1"
}
dosomething $1
Ahora úsalo en find como:
find . -exec dosomething.sh {} /;
Para aquellos de ustedes que buscan una función bash que ejecutará un comando dado en todos los archivos en el directorio actual, he compilado una de las respuestas anteriores:
toall(){
find . -type f | while read file; do "$1" "$file"; done
}
Tenga en cuenta que se rompe con nombres de archivos que contienen espacios (ver a continuación).
Como ejemplo, toma esta función:
world(){
sed -i ''s_hello_world_g'' "$1"
}
Digamos que quería cambiar todas las instancias de hello a world en todos los archivos en el directorio actual. Yo lo haría:
toall world
Para estar seguro con cualquier símbolo en los nombres de archivo, use:
toall(){
find . -type f -print0 | while IFS= read -r -d '''' file; do "$1" "$file"; done
}
(pero necesita un find
que maneja -print0
por ejemplo, GNU find
).
Ponga la función en un archivo separado y obtenga el resultado para ejecutar eso.
Las funciones de shell son internas al shell en el que están definidas; find
nunca podrá verlos.
-exec
usar -exec
completo. ¿Por qué no usar xargs
?
find . -name <script/command you''re searching for> | xargs bash -c
find . | while read file; do dosomething "$file"; done