¿Cómo usar `find -exec` para ejecutar el comando en el directorio del archivo encontrado (no en el directorio actual)?

15

Digamos que estoy en un directorio que tiene algunos subdirectorios, dir1, dir2, y dir3. Cada uno de estos directorios tiene un archivo fooy me gustaría ejecutar el mismo comando en cada foouno de los directorios y ejecutar ese comando desde ese directorio.

Si lo hiciera "a mano", se vería así:

cd dir1
(execute on foo)
cd ../dir2
(execute on foo)
cd ../dir3
(execute on foo)

Es imperativo que el comando se ejecute desde cada uno de los directorios . fooes un script de programación por lotes (para HTCondor, si le interesa saber) y debe ejecutarse desde cada subdirectorio para que la salida de las ejecuciones iniciadas por los scripts de programación termine en cada subdirectorio.

La pregunta " Buscar un archivo y ejecutar un comando en el directorio del archivo ", por lo que puedo decir, no responde a mi pregunta. La primera respuesta a esa pregunta es más una solución alternativa que no funcionará en mi caso, y la segunda respuesta no tiene una explicación suficiente para que yo sepa cómo usarla.

Estrella neutrón
fuente
@roaima, explique cómo es un duplicado. La primera respuesta de esa pregunta no me ayuda, es más una solución, y la segunda respuesta no tiene ningún sentido para mí. Necesita más explicaciones para saber cómo usarlo.
NeutronStar

Respuestas:

23

Suponiendo que su findsoporte es compatible, use la -execdiropción en lugar de-exec

find * -name 'foo' -execdir pwd \;

Si no es así, proporcione detalles de su plataforma y / o distribución (según corresponda).

roaima
fuente
Cuando comienzas a presionar "find: La ruta relativa './node_modules/.bin' está incluida en la variable de entorno PATH": askubuntu.com/questions/621132/…
Ciro Santilli 冠状 病毒 审查 六四 事件 法轮功
Lo siento si puedo escribirlo así, pero -execdir (en Ubuntu) es una mierda, porque no te da {}, sino el padre de {}.
uav
1
@uav sin conocer tu caso de uso, no puedo ayudarte. Pero en respuesta a su whinge la documentación indica claramente " Me gusta -exec, pero el comando especificado se ejecuta desde el subdirectorio que contiene el archivo coincidente ".
Roaima
Sí, es un caso especial si está buscando -type d (= directorio) y luego es subóptimo.
uav
Sin conocer su caso de uso, no puedo ayudarlo.
roaima
3

Suponiendo que sepa exactamente en qué directorios ejecutar su comando,

for dir in dir1 dir2 dir3; do
    ( cd "$dir" && somecommand foo )
done

o, recorriendo los fooarchivos,

for foo in */foo; do
  ( cd "${foo%/*}" && somecommand foo )
done

La subshell evita cdque afecte al directorio de trabajo del resto del script. La ${foo%/*}sustitución de parámetros se expande al nombre del directorio donde foovive el archivo (eliminando todo después del último /en el valor de $foo).

Usando el estándar findpara hacer lo mismo (en el caso de que los fooarchivos puedan vivir en el fondo de una estructura de directorios):

find . -type f -name foo -exec sh -c '
    for foo do
        ( cd "${foo%/*}" && somecommand foo )
    done' sh {} +

En palabras: encuentre todos los archivos regulares llamados "foo" en cualquier lugar del directorio actual o debajo y asigne sus nombres de ruta a este script de shell en lotes. El script de shell iterará sobre los nombres de ruta dados, cambiará el directorio a la parte del directorio de cada nombre de ruta y, si eso tiene éxito, se ejecutará somecommand foo.

Para una solución que usa el no estándar -execdir, vea la respuesta de roaima . Su respuesta se adaptó a mi ejemplo:

find . -type f -name foo -execdir somecommand foo ';'
Kusalananda
fuente