Como usar o `find -exec` para executar o comando no diretório do arquivo encontrado (não no diretório atual)?

15

Vamos dizer que eu estou em um diretório que tem alguns subdiretórios, dir1, dir2, e dir3. Cada um desses diretórios possui um arquivo fooe eu gostaria de executar o mesmo comando em cada fooum dos diretórios e executar esse comando de dentro desse diretório.

Se eu o fizesse "manualmente", seria algo como isto:

cd dir1
(execute on foo)
cd ../dir2
(execute on foo)
cd ../dir3
(execute on foo)

É imperativo que o comando seja executado em cada um dos diretórios . fooé um script de agendamento em lote (para HTCondor, se você quiser saber) e deve ser executado em cada subdiretório para que a saída das execuções iniciadas pelos scripts de agendamento termine em cada subdiretório.

A pergunta " Encontre um arquivo e execute um comando no diretório do arquivo ", até onde sei, não responde à minha pergunta. A primeira resposta a essa pergunta é mais uma solução alternativa que não funcionará no meu caso, e a segunda resposta não tem explicação suficiente para que eu saiba como usá-la.

Estrêla de Neutróns
fonte
@roaima, por favor, explique como é uma duplicata. A primeira resposta dessa pergunta não me ajuda, é mais uma solução, e a segunda resposta não faz nenhum sentido para mim. Precisa de mais explicações para eu saber como usá-lo.
NeutronStar

Respostas:

23

Supondo que você o findsuporte, use a -execdiropção em vez de-exec

find * -name 'foo' -execdir pwd \;

Caso contrário, forneça detalhes da sua plataforma e / ou distribuição (conforme apropriado).

roaima
fonte
Quando você começar a bater "encontrar: O caminho' ./node_modules/.bin' parente está incluído na variável de ambiente PATH,": askubuntu.com/questions/621132/...
Ciro Santilli冠状病毒审查六四事件法轮功
Desculpe se eu posso escrever assim, mas -execdir (no Ubuntu) é uma merda, porque não dá a você {}, mas é o pai {}.
uav 13/05/19
1
@ uav sem conhecer seu caso de uso, não posso ajudá-lo. Mas, em resposta à sua reclamação, a documentação afirma claramente " Como -exec, mas o comando especificado é executado no subdiretório que contém o arquivo correspondente ".
roaima 13/05/19
Sim, certo, é um caso especial se você estiver procurando por -type d (= directory) e, em seguida, não for o ideal.
uav 13/05/19
Sem conhecer seu caso de uso, não posso ajudá-lo.
roaima 13/05/19
3

Supondo que você saiba exatamente em quais diretórios executar seu comando,

for dir in dir1 dir2 dir3; do
    ( cd "$dir" && somecommand foo )
done

ou, repetindo os fooarquivos,

for foo in */foo; do
  ( cd "${foo%/*}" && somecommand foo )
done

O subshell impede cdque isso afete o diretório de trabalho do restante do script. A ${foo%/*}substituição de parâmetro se expande para o nome do diretório em que o fooarquivo está (removendo tudo após o último /no valor de $foo).

Usando o padrão findpara fazer a mesma coisa (no caso em que os fooarquivos podem estar no fundo de uma estrutura de diretórios):

find . -type f -name foo -exec sh -c '
    for foo do
        ( cd "${foo%/*}" && somecommand foo )
    done' sh {} +

Em palavras: encontre todos os arquivos regulares chamados "foo" em qualquer lugar do diretório atual ou abaixo e atribua seus nomes de caminho para esse script de shell em lotes. O script de shell deve percorrer os nomes de caminho fornecidos, alterar o diretório para a parte do diretório de cada nome de caminho e, se for bem-sucedido, executar somecommand foo.

Para uma solução que usa fora do padrão -execdir, consulte a resposta da roaima . Sua resposta se adaptou ao meu exemplo:

find . -type f -name foo -execdir somecommand foo ';'
Kusalananda
fonte