Executa um comando onde um arquivo é encontrado

7

Como executo um comando onde um arquivo é encontrado?
Considere que eu 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 executar uma ação (executar um comando) em que find encontre um determinado tipo de arquivo / 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, digamos touch file ) onde o comando acima encontra o (s) arquivo (s). Em outras palavras, eu quero criar um arquivo chamado file em cada diretório em que pelo menos um .pdf foi encontrado para que eu tenha:

$ 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 eu realizo esse trabalho?
Pode ser para cada arquivo de tempo localizado, cd para onde o arquivo existe e executar um comando recursivamente.
Eu sei que find tem um recurso incrível: -exec , mas não consigo fazer isso funcionar.

Este é apenas um exemplo para se ter uma ideia do que eu quero fazer. De modo geral: Como executar um comando onde os arquivos são encontrados (por find ) recursivamente?

    
por Pandya 30.10.2015 / 15:58

4 respostas

11

Se você executar este comando, seu touch file será executado, possivelmente 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 essa 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 touch file por echo {} e / ou pwd .

Da página de manual:

-execdir command ;
-execdir command {} +

    Like -exec, but the specified command is run from the subdirectory containing the matched file, which is not normally the directory in which you started find.
    
por 30.10.2015 / 18:01
2

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

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

em que o arquivo myscript contém o seguinte:

dir=$(dirname "$1")
cd "$dir"
touch file
    
por 30.10.2015 / 16:10
2

Com zsh , você pode usar qualificadores glob para selecionar, e. somente .pdf arquivos e modificadores salvam os nomes de diretório em uma matriz com exclusivo e, em seguida, cd em cada um desses diretórios e execute seu comando. Dessa forma, você está executando o comando somente uma vez em cada diretório, independentemente do número de .pdf s que foram 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 combinar mais 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))
    
por 30.10.2015 / 21:30
0

Não procure mais do que entr:

link

O que você pode fazer é deixar entr assistir a um diretório especificado. Quando encontrar localiza o arquivo, toque em um arquivo chamado digamos, triggerfile.txt nesse diretório e deixe o entr assumir.

    
por 04.11.2015 / 07:20