Comportamentos diferentes entre find -exec e canalização através de xargs

Comportamentos diferentes entre find -exec e canalização através de xargs

Eu queria executar recursivamente chmod go+wem uma pasta específica, incluindo arquivos ocultos, e primeiro tentei

find . -name ".*" -o -name "*" -exec chmod go+w {} \;

mas descobri que isso não estava afetando os arquivos ocultos. Para me verificar, corri apenas

find . -name ".*" -o -name "*"

e os arquivos ocultos foram listados. Também notei que se eu excluísse a -o -name "*"parte, ele faria chmod nos arquivos ocultos (mas excluiria os não ocultos, é claro). Minha última tentativa foi usar xargs

find . -name ".*" -o -name "*" | xargs chmod go+w

que finalmente funcionou como esperado. O que estou fazendo de errado no primeiro trecho?

Servidor Red Hat Enterprise Linux versão 6.8 (Santiago)

GNU bash, versão 4.3.42(1)-release (x86_64-unknown-linux-gnu)

Responder1

A solução é vincular os dois testes de nome com parênteses.

Para ilustrar isso, vamos considerar um diretório com três arquivos regulares:

$ ls -a
.  ..  .hidden1  .hidden2  not_hidden

Agora, vamos ao comando original:

$ find . -name ".*" -o -name "*" -exec echo Found {} \;
Found ./not_hidden

Somente o arquivo não oculto é encontrado.

A seguir, vamos adicionar parênteses para agrupar os dois testes de nome:

$ find . \( -name ".*" -o -name "*" \) -exec echo Found {} \;
Found .
Found ./not_hidden
Found ./.hidden1
Found ./.hidden2

Todos os arquivos foram encontrados.

A solução é usar parênteses.

Mais detalhes

No comando original, não há operador entre -name "*"e -exec ... \;. Conseqüentemente, findassume o operador padrão que é lógico e. Como a ligação lógica-e é mais rígida que a lógica-ou ( -o), isso significa que o comando é interpretado como:

find . \( -name ".*" \) -o \( -name "*" -exec echo Found {} \; \)

Isso significa que execserá executado somente se a primeira namecondição não corresponder.

Para obter mais informações, consulte oOPERADORESseção em man find.

O que acontece sem-exec

Vamos tentar usar um simples -print:

$ find . -name ".*" -o -name "*" -print
./not_hidden

Como você pode ver, -printvinculado ao -name "*"com o lógico implícito e como acima.

Mas considere o que acontece sem nenhuma ação especificada:

$ find . -name ".*" -o -name "*"
.
./not_hidden
./.hidden1
./.hidden2

Aqui, todos os arquivos foram encontrados. A razão é que, nesta versão, -oé oapenasoperador.

informação relacionada