find -exec una función de shell en Linux?

¿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 ?

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"' {} \; 
 find . | while read file; do dosomething "$file"; done 

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.

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.

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.

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.

Para aquellos de ustedes que buscan una función bash que ejecutará un comando dado en todos los archivos en el directorio actual, he comstackdo 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 ).

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 {} \; 

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.

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 

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.

-exec usar -exec completo. ¿Por qué no usar xargs ?

 find . -name