Execute um comando onde um arquivo for encontrado

Execute um comando onde um arquivo for encontrado

Como executo um comando onde um arquivo é encontrado?
Considere que tenho um diretório chamado testdirque 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 findencontre 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 fileem cada diretório onde pelo menos um .pdffoi 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, cdaté onde o arquivo existe e executar um comando recursivamente.
Eu sei que findtem um recurso incrível: -execmas 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 fileserá 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 filepor 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 o find.

Responder2

Você pode extrair o diretório do nome do arquivo dirnamee retirá-lo de lá, algo assim:

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

onde o arquivo myscriptcontém o seguinte:

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

Responder3

Com zshvocê poderia usar qualificadores glob para selecionar, por exemplo, apenas .pdfarquivos e viamodificadoressalve os nomes dos diretórios em uma matriz comexclusivoelementos e, em seguida, cdem 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 .pdfs 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 .bkpe 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.

informação relacionada