Por que o 'find' no Linux pula os resultados esperados quando '-o' é usado?

6

Por que no Linux (Debian 8)

touch 1.cpp 1.h
find . -name "*.cpp" -o -name "*.h" -exec echo {} \;

produz apenas 1.h enquanto

find . -name "*.cpp" -o -name "*.h"

produz ambos? É um bug ou um recurso?

    
por mastan 02.09.2015 / 12:21

4 respostas

1

Acho que, uma vez que você usou o operador -or , é necessário mantê-lo consistente para evitar uma ordem ambígua de operações lógicas quando houver várias condições conectadas usando OR lógico.

Parece que a parte -exec está agrupada com o segundo -name "*.h" .

Portanto, para que funcione corretamente, adicione os colchetes conforme abaixo:

find . '(' -name '*.cpp' -o -name '*.h' ')' -exec echo {} ';'

Remember: The parentheses must be quoted or escaped with a backslash to prevent them from being interpreted as special shell characters.

Como alternativa, combine algumas extensões em uma usando -regex :

find . ! -regex ".*\.\(cpp\|h\)" -exec echo {} \;
    
por 02.09.2015 / 12:41
1

Tente envolver seus critérios de pesquisa com colchetes como:

find . \( -name "*.cpp" -o -name "*.h" \) -exec echo {} \;
    
por 02.09.2015 / 12:41
1

Nem É a sintaxe das opções que está "errada". find é avaliado sequencialmente. Portanto, ele avalia a primeira expressão ( -name "*.cpp" ) e, em seguida, encontra um sinalizador -o . Se a primeira expressão for verdadeira, find não continuará avaliando a segunda ( -name "*.h" -exec echo {} \; ), em vez disso, não fará nada. Você vê, a parte inteira depois de -o é uma expressão. Portanto, isso é executado apenas para arquivos que correspondem à segunda expressão. É por isso que você vê apenas o arquivo 1.h , que transmite apenas a segunda expressão. Veja a localização do manual:

   expr1 -o expr2
          Or; expr2 is not evaluated if expr1 is true.

Por que isso é útil? Considere o seguinte:

find /path -exec test_file_for_something {} -print \; -o -name "xyz" -exec ls -l {} \;

Nesta instrução de localização, o arquivo é dado a test_file_for_something como um parâmetro. Agora, dependendo do código de retorno dos comandos, a primeira expressão é verdadeira (então -print é executada e termina aí) ou false (então a segunda expressão após a avaliação do -o é avaliada). E se essa for verdadeira (o nome é xyz ), então -exec é executado.

Para o seu problema, você pode usar isso para agrupar os elementos como uma expressão :

find . \( -name "*.cpp" -o -name "*.h" \) -exec echo {} \;
    
por 02.09.2015 / 13:03
0

Essa é a maneira como o find funciona com seus operadores.

Veja link seção OPERADORES

OPERATORS

Listed in order of decreasing precedence: ( expr ) Force precedence. Since parentheses are special to the shell, you will normally need to quote them. Many of the examples in this manual page use backslashes for this purpose: '(...)' instead of '(...)'. ! expr True if expr is false. This character will also usually need protection from interpretation by the shell.

-not expr Same as ! expr, but not POSIX compliant. expr1 expr2 Two expressions in a row are taken to be joined with an implied "and"; expr2 is not evaluated if expr1 is false. expr1 -a expr2 Same as expr1 expr2. expr1 -and expr2 Same as expr1 expr2, but not POSIX compliant. expr1 -o expr2 Or; expr2 is not evaluated if expr1 is true. expr1 -or expr2 Same as expr1 -o expr2, but not POSIX compliant. expr1 , expr2 List; both expr1 and expr2 are always evaluated. The value of expr1 is discarded; the value of the list is the value of expr2. The comma operator can be useful for searching for several different types of thing, but traversing the filesystem hierarchy only once. The -fprintf action can be used to list the various matched items into several different output files.

Isso deve fornecer o resultado desejado:

find . \( -name '*.cpp' -o -name '*.h' \) -exec echo {} \;

Seu comando está fazendo isso (o comando não funciona, apenas para mostrar a lógica):

find . -name '*.cpp' (-o -name '*.h' -exec echo {} \;)

    
por 02.09.2015 / 12:43

Tags