
Como executo um comando onde um arquivo é encontrado?
Considere que tenho um diretório chamado testdir
que contém o seguinte:
$ 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
Agora quero realizar uma ação (executar um comando) onde find
encontre um determinado arquivo/tipo de arquivo. Por exemplo, deixe-me encontrar *.pdf
:
$ find . -name '*.pdf'
./testdir/dir3/doc2.pdf
./testdir/dir5/doc5.pdf
./testdir/dir1/doc1.pdf
Agora, suponha que eu queira executar um comando (por exemplo, say touch file
) onde o comando acima encontra arquivo(s). Em outras palavras, quero criar um arquivo nomeado file
em cada diretório onde pelo menos um .pdf
foi encontrado para obter:
$ 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
Como faço esse trabalho?
Pode ser para cada vez que o arquivo for encontrado, cd
até onde o arquivo existe e executar um comando recursivamente.
Eu sei que find
tem um recurso incrível: -exec
mas não consigo fazê-lo funcionar.
Este é apenas um exemplo para ter uma ideia do que quero fazer. Em termos gerais: como executar um comando onde os arquivos são encontrados (por find
) recursivamente?
Responder1
Se você executar este comando, ele touch file
será executado, potencialmente várias vezes, a partir do diretório no qual o comando foi iniciado:
find -name '*.pdf' -exec touch file \;
Por outro lado, se você executar esta variante, cada instância do comando será executada no diretório do arquivo de destino:
find -name '*.pdf' -execdir touch file \;
Em ambos os casos, você pode ver isso em ação substituindo the touch file
por echo {}
e/ou pwd
.
Da página de manual:
-execdir command ;
-execdir command {} +
Semelhante ao
-exec
, mas o comando especificado é executado no subdiretório que contém o arquivo correspondente, que normalmente não é o diretório no qual você iniciou ofind
.
Responder2
Você pode extrair o diretório do nome do arquivo dirname
e retirá-lo de lá, algo assim:
find . -name "*.pdf" -type f -exec bash myscript {} \;
onde o arquivo myscript
contém o seguinte:
dir=$(dirname "$1")
cd "$dir"
touch file
Responder3
Com zsh
você poderia usar qualificadores glob para selecionar, por exemplo, apenas .pdf
arquivos e viamodificadoressalve os nomes dos diretórios em uma matriz comexclusivoelementos e, em seguida, cd
em cada um desses diretórios e execute seu comando. Desta forma você está executando apenas o seu comandouma vezem cada diretório, independentemente do número de .pdf
s encontrados nesse diretório:
dirlist=(**/*.pdf(.:a:h))
for d in ${(u)dirlist[@]}
(cd $d && touch file)
ou
typeset -U dirlist
dirlist=(**/*.pdf(.:a:h))
for d in ${dirlist}
(cd $d && touch file)
Você pode ainda combinar modificadores e qualificadores, por exemplo, para globar arquivos regulares (ocultos e não ocultos) com a extensão .bkp
e salvar nomes de diretórios exclusivos em uma matriz:
dirlist=(**/*.bkp(D.:a:h))
Responder4
Não procure mais do que entrar:
https://bitbucket.org/eradman/entr
O que você pode fazer é deixar o entr monitorar um diretório especificado. Quando find localizar o arquivo, toque em um arquivo chamado, digamos, triggerfile.txt nesse diretório e deixe entr assumir o controle.