¿Hay alguna manera de find
ejecutar 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 una manera de conseguir find
's -exec
para ver dosomething
?
$0
.find . -exec bash -c 'dosomething "$0"' {} \;
, manejará espacios (y otros caracteres extraños) en los nombres de archivo ...export -f
funcionará sólo en algunas versiones de bash. No es posix, no crossplatforn,/bin/sh
tendrá un error con élfuente
while read
para un bucle for;for item in $(find . ); do some_function "${item}"; done
La respuesta de Jak anterior es excelente, pero tiene un par de dificultades que se pueden superar fácilmente:
Esto usa nulo como delimitador en lugar de un salto de línea, por lo que los nombres de archivo con saltos de línea funcionarán. También usa la
-r
bandera que deshabilita el escape de la barra invertida, sin que las barras invertidas en los nombres de archivo no funcionen. También se borraIFS
para que no se descarten los espacios en blanco finales potenciales en los nombres.fuente
/bin/bash
pero no funcionará/bin/sh
. Lo que es una lástima.Agregue citas
{}
como se muestra a continuación:Esto corrige cualquier error debido a caracteres especiales devueltos por
find
, por ejemplo, archivos con paréntesis en su nombre.fuente
{}
. Esto se romperá para un nombre de archivo que contenga comillas dobles.touch '"; rm -rf .; echo "I deleted all you files, haha
. Ups-exec bash -c 'echo $0' '{}' \;
Tenga en cuenta que cuando usabash -c
, $ 0 es el primer argumento, no el nombre del script.Resultados de procesamiento a granel
Para una mayor eficiencia, muchas personas utilizan
xargs
para procesar resultados en masa, pero es muy peligroso. Debido a eso, se introdujo un método alternativofind
que ejecuta resultados en masa.Sin embargo,
find
tenga{}
en cuenta que este método puede venir con algunas advertencias como, por ejemplo, un requisito en POSIX para tener al final del comando.find
pasará muchos resultados como argumentos a una sola llamada debash
y elfor
bucle iterará a través de esos argumentos, ejecutando la funcióndosomething
en cada uno de ellos.La solución anterior inicia argumentos en
$1
, por lo que hay un_
(que representa$0
).Procesando resultados uno por uno
Del mismo modo, creo que la respuesta superior aceptada debería corregirse para que sea
Esto no solo es más sensato, porque los argumentos siempre deben comenzar en
$1
, sino que también el uso$0
podría conducir a un comportamiento inesperado si el nombre de archivo devuelto porfind
tiene un significado especial para el shell.fuente
Haga que el script se llame a sí mismo, pasando cada elemento encontrado como argumento:
Cuando ejecuta el script por sí mismo, encuentra lo que está buscando y se llama a sí mismo 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.
fuente
find: ‘myscript.sh’: No such file or directory
si se inicia comobash myscript.sh
...Para aquellos de ustedes que buscan una función bash que ejecute un comando dado en todos los archivos en el directorio actual, he compilado uno de las respuestas anteriores:
Tenga en cuenta que se rompe con nombres de archivos que contienen espacios (ver más abajo).
Como ejemplo, tome esta función:
Digamos que quería cambiar todas las instancias de hello a world en todos los archivos en el directorio actual. Yo lo haría:
Para estar seguro con cualquier símbolo en los nombres de archivo, use:
(pero necesita un
find
que maneje-print0
, por ejemplo, GNUfind
).fuente
Encuentro la manera más fácil de la siguiente manera, repitiendo dos comandos en un solo do
fuente
Como referencia, evito este escenario usando:
Obtenga la salida de find en el archivo de secuencia de comandos actual e itere sobre la salida como desee. Estoy de acuerdo con la respuesta aceptada, pero no quiero exponer la función fuera de mi archivo de script.
fuente
No es posible ejecutar una función de esa manera.
Para superar esto, puede colocar su función en un script de shell y llamar a eso desde
find
Ahora úsalo en buscar como:
fuente
dosomething $1
=>dosomething "$1"
e inicie su archivo correctamente confind . -exec bash dosomething.sh {} \;
Coloque la función en un archivo separado y
find
ejecute eso.Las funciones de shell son internas al shell en el que están definidas;
find
nunca podrá verlos.fuente
Para proporcionar adiciones y aclaraciones a algunas de las otras respuestas, si está utilizando la opción masiva para
exec
oexecdir
(-exec command {} +
), y desea recuperar todos los argumentos posicionales, debe considerar el manejo de$0
conbash -c
. Más concretamente, considere el siguiente comando, que utilizabash -c
como se sugirió anteriormente, y simplemente repite las rutas de archivo que terminan con '.wav' de cada directorio que encuentra:El manual de bash dice:
Aquí,
'check $@'
está la cadena de comando, y_ {}
son los argumentos después de la cadena de comando. Tenga en cuenta que$@
es un parámetro posicional especial en bash que se expande a todos los parámetros posicionales a partir de 1 . También tenga en cuenta que con la-c
opción, el primer argumento se asigna al parámetro posicional$0
. Esto significa que si intenta acceder a todos los parámetros posicionales con$@
, solo obtendrá parámetros a partir de$1
y hacia arriba. Esa es la razón por la cual la respuesta de Dominik tiene el_
, que es un argumento ficticio para completar el parámetro$0
, por lo que todos los argumentos que queremos están disponibles más adelante si usamos la$@
expansión de parámetros, por ejemplo, o el bucle for como en esa respuesta.Por supuesto, similar a la respuesta aceptada,
bash -c 'shell_function $0 $@'
también funcionaría al pasar explícitamente$0
, pero nuevamente, debe tener en cuenta que$@
no funcionará como se esperaba.fuente
No directamente, no. Find se está ejecutando en un proceso separado, no en su shell.
Cree un script de shell que haga el mismo trabajo que su función y encuentre
-exec
eso.fuente
Evitaría usar por
-exec
completo. ¿Por qué no usarxargs
?fuente