encontre com -execdir

15

Quando eu corro findcom -execdirque eu não obter os resultados que eu estava esperando.

Por exemplo:

mkdir -p a/b/c
find . -type d -execdir touch foo \;
$ tree a
a
├── b
   ├── c
   └── foo
└── foo

O diretório cnão contém um fooarquivo. Como faço findpara visitar e fazer algo localmente em cada diretório?

Marcus Junius Brutus
fonte

Respostas:

18

Para cada arquivo correspondente (ou seja, todo diretório), findalterna para o diretório que o contém (ou seja, seu diretório pai) e executa o comando especificado. Como o comando não usa o nome da correspondência, nunca atuará em todos os diretórios. Para esta árvore de diretórios específica, você está fazendo

(cd . && touch foo)        # because ./a matches
(cd ./a && touch foo)      # because ./a/b matches
(cd ./a/b && touch foo)    # because ./a/b/c matches

Para criar um arquivo em cada diretório, você pode simplesmente usar em -execvez de -execdir, desde que sua implementação de findpermita {}dentro de um argumento (a maioria faz, e em particular eu acho que todos):

find . -type d -exec touch {}/foo +

Para a portabilidade do POSIX, você precisaria fazer a montagem do nome do diretório e do nome da base do arquivo manualmente.

find . -type d -exec sh -c 'touch "$0/foo"' {} \;

ou (um pouco mais rápido)

find . -type d -exec sh -c 'for d; do touch "$d/foo"; done' _ {} +

Como alternativa, você pode usar a correspondência curinga recursiva do bash. Observe que (ao contrário do recurso correspondente em ksh e zsh e ao contrário do seu findcomando) o bash se repete sob links simbólicos para diretórios.

shopt -s globstar
for d in **/*/; do touch -- "$d/foo"; done

Uma solução zsh:

touch ./**/(e\''REPLY+=foo'\')
Gilles 'SO- parar de ser mau'
fonte
FYI: man bashestados em "-c": argumentos após command_string são atribuídos a parâmetros posicionais que começam com $ 0, no entanto "for d" irá iterar através de parâmetros posicionais começando com $ 1. "_" é um texto atribuído a $ 0 e não será usado.
Chad Skeeters
3

O comando é executado em todos os diretórios que contêm um arquivo correspondente. Como cnão contém um diretório, ele não corresponde e, portanto, não será executado lá.

A solução é adicionar o nome do diretório ao argumento execdir, assim:

find . -type d -execdir touch {}/foo \;
Jenny D
fonte
2

A partir de man file

   -execdir command {} +
          Like  -exec,  but  the  specified  command is run from the subdirectory containing the matched file

Seu diretório correspondente cvive no bdiretório, e é daí que o exec é executado. Funcionaria como esperado, se você estiver procurando por arquivos em vez de diretórios.

Você provavelmente poderia conseguir o que deseja enviando os diretórios, xargspois será fornecida a lista completa de diretórios.

Matt
fonte