Ejecutar un comando donde se encuentra un archivo

Ejecutar un comando donde se encuentra un archivo

¿Cómo ejecuto un comando donde se encuentra un archivo?
Considere que tengo un directorio llamado testdirque contiene lo siguiente:

$ ls -R testdir/
testdir/:
dir1  dir2  dir3  dir4  dir5

testdir/dir1:
doc1.pdf

testdir/dir2:
file1.txt

testdir/dir3:
doc2.pdf

testdir/dir4:
file2.txt

testdir/dir5:
doc5.pdf

Ahora quiero realizar una acción (ejecutar un comando) donde findencuentre un determinado archivo/tipo de archivo. Por ejemplo déjame encontrar *.pdf:

$ find . -name '*.pdf'
./testdir/dir3/doc2.pdf
./testdir/dir5/doc5.pdf
./testdir/dir1/doc1.pdf

Ahora supongamos que quiero ejecutar un comando (por ejemplo, digamos touch file) donde el comando anterior encuentra archivos. En otras palabras, quiero crear un archivo nombrado fileen cada directorio donde se encontró al menos uno .pdfpara obtener:

$ ls -R testdir/
testdir/:
dir1  dir2  dir3  dir4  dir5

testdir/dir1:
doc1.pdf  file

testdir/dir2:
file1.txt

testdir/dir3:
doc2.pdf  file

testdir/dir4:
file2.txt

testdir/dir5:
doc5.pdf  file

¿Cómo logro tal trabajo?
Puede ser para cada vez que se encuentre un archivo, cdhasta donde exista el archivo y ejecute un comando de forma recursiva.
Sé que findtiene una característica increíble, -execpero no puedo hacer que funcione.


Este es sólo un ejemplo para tener una idea de lo que quiero hacer. En términos generales: ¿Cómo ejecutar un comando donde los archivos se encuentran (por find) de forma recursiva?

Respuesta1

Si ejecuta este comando touch file, se ejecutará, potencialmente varias veces, desde el directorio en el que se inició el comando:

find -name '*.pdf' -exec touch file \;

Por otro lado, si ejecuta esta variante, cada instancia del comando se ejecutará en el directorio del archivo de destino:

find -name '*.pdf' -execdir touch file \;

En ambos casos, puedes ver esto en acción sustituyendo el touch filecon o echo {}y/o pwd.


Desde la página de manual:

-execdir command ;
-execdir command {} +

    Me gusta -exec, pero el comando especificado se ejecuta desde el subdirectorio que contiene el archivo coincidente, que normalmente no es el directorio en el que inició find.

Respuesta2

Puedes extraer el directorio del nombre del archivo dirnamey tomarlo desde allí, algo como esto:

find . -name "*.pdf" -type f -exec bash myscript {} \;

donde el archivo myscriptcontiene lo siguiente:

dir=$(dirname "$1")
cd "$dir"
touch file

Respuesta3

Con zshusted podría usar calificadores globales para seleccionar, por ejemplo, solo .pdfarchivos y mediantemodificadoresguarde los nombres de los directorios en una matriz conúnicoelementos y luego cden cada uno de esos directorios y ejecute su comando. De esta manera estás ejecutando solo tu comandouna vezen cada directorio, independientemente del número de .pdfmensajes de correo electrónico que se encontraron en ese directorio:

dirlist=(**/*.pdf(.:a:h))
for d in ${(u)dirlist[@]}
  (cd $d && touch file)

o

typeset -U dirlist
dirlist=(**/*.pdf(.:a:h))
for d in ${dirlist}
  (cd $d && touch file)

Puede combinar además modificadores y calificadores, por ejemplo, agrupar archivos normales (ocultos y no ocultos) con la extensión .bkpy guardar nombres de directorio únicos en una matriz:

dirlist=(**/*.bkp(D.:a:h))

Respuesta4

No busques más que entrar:

https://bitbucket.org/eradman/entr

Lo que puedes hacer es dejar que entr mire un directorio específico. Cuando buscar localice el archivo, toque un archivo llamado, digamos, triggerfile.txt en ese directorio y deje que entr se haga cargo.

información relacionada