
¿Cómo ejecuto un comando donde se encuentra un archivo?
Considere que tengo un directorio llamado testdir
que 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 find
encuentre 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 file
en cada directorio donde se encontró al menos uno .pdf
para 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, cd
hasta donde exista el archivo y ejecute un comando de forma recursiva.
Sé que find
tiene una característica increíble, -exec
pero 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 file
con 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 dirname
y tomarlo desde allí, algo como esto:
find . -name "*.pdf" -type f -exec bash myscript {} \;
donde el archivo myscript
contiene lo siguiente:
dir=$(dirname "$1")
cd "$dir"
touch file
Respuesta3
Con zsh
usted podría usar calificadores globales para seleccionar, por ejemplo, solo .pdf
archivos y mediantemodificadoresguarde los nombres de los directorios en una matriz conúnicoelementos y luego cd
en 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 .pdf
mensajes 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 .bkp
y 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.