O comando Find retorna resultados diferentes quando -print0 é adicionado

4

Ao fazer uma pesquisa como find -type d , adicionar o argumento -print0 logo após o comando find, como find -print0 -type d , faz com que a pesquisa retorne mais resultados do que sem ela.

    
por sa289 14.06.2015 / 04:22

3 respostas

10

Se você entender os operadores && e || no shell (e também em C, C ++ e linguagens derivadas), então você entende -a e -o em find .

Para refrescar sua memória:

No shell,

command1  &&  command2

executa command1 e, se ele ( command1 ) for bem-sucedido, ele (o shell) executa command2 .

command1  ||  command2

executa command1 e, se ele ( command1 ) falhar, ele (o shell) executa command2 .

Nas linguagens compiláveis,

expr1  &&  expr2

avalia expr1 . Se ( expr1 ) for avaliado como falso (zero), ele retorna isso como o valor da expressão geral. Caso contrário (se expr1 for avaliado como um valor verdadeiro (diferente de zero)), ele avalia expr2 e retorna isso como o valor da expressão geral.

expr1  ||  expr2

avalia expr1 . Se ( expr1 ) for avaliado como um valor verdadeiro (diferente de zero), ele retorna isso como o valor da expressão geral. Caso contrário (se expr1 for avaliado como falso (zero)) ele avalia expr2 e retorna isso como o valor da expressão geral.

    This is known as “short-circuit evaluation”, in that it allows the evaluation of a Boolean expression without evaluating terms whose values are not needed to determine the overall value of the expression.

Citações de encontrar (1)

GNU find searches the directory tree rooted at each given file name by evaluating the given expression from left to right, according to the rules of precedence (see section OPERATORS), until the outcome is known (the left hand side is false for and operations, true for or), at which point find moves on to the next file name.
            ⋮

EXPRESSIONS

The expression is made up of … tests (which return a true or false value), and actions (which have side effects and return a true or false value), all separated by operators.  -and is assumed where the operator is omitted.
                    ⋮
    The subsection on ACTIONS states that -print, like
    most of the actions, always returns a value of true.

OPERADORES


expr1 expr2
expr1 -a expr2
expr1 i> -e expr2 ⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅ ⋅⋅⋅⋅⋅⋅⋅⋅⋅ não compatível com POSIX
    E; expr2 não é avaliado se expr1 for falso.
expr1 -o expr2
expr1 ou expr2 ⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅ ⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅ não compatível com POSIX
    Ou; expr2 não é avaliado se expr1 for verdadeiro.

A especificação de grupo aberto para find tem coisas semelhantes a dizer:

The find utility shall recursively descend the directory hierarchy …, evaluating a Boolean expression composed of the primaries described in the OPERANDS section for each file encountered.
            ⋮

OPERANDS

            ⋮
-print
    The primary shall always evaluate as true; it shall cause the current pathname to be written to standard output.
            ⋮
The primaries can be combined using the following operators (in order of decreasing precedence):
            ⋮

expression [-a] expression
    Conjunction of primaries; the AND operator is implied by the juxtaposition of two primaries or made explicit by the optional -a operator.  The second expression shall not be evaluated if the first expression is false.
expression  -o  expression
    Alternation of primaries; the OR operator.  The second expression shall not be evaluated if the first expression is true.

Ambos os documentos dizem: “Se nenhuma expressão estiver presente, -print será usada como expressão.”

---------------- TL; DR ----------------

Então,

find -type d

é equivalente a

find -type d -print

que é equivalente a

find -type d -a -print

o que significa,

  • para cada arquivo,
    • avalie o teste -type d .
    • Se for verdade (ou seja, se o "arquivo" atual for um diretório), avalie (execute) a ação -print .

Considerando que ,

find -print -type d

é equivalente a

find -print -a -type d

o que significa,

  • para cada arquivo,
    • avaliar (executar) a ação -print (isto é, isso acontece para todos os arquivos ) .
    • Se for verdadeiro (que -print sempre é), avalie o -type d test.
    • E, como esse é o fim do comando, o resultado do teste -type d é ignorado.

Então você tem isso.

    
por 14.06.2015 / 10:32
9

A ordem de encontrar argumentos é importante. O comando precisa ser construído como find -type d -print0 e, em seguida, funcionará conforme o esperado. Eu apenas pensei em postar isso caso seja útil para alguém.

    
por 14.06.2015 / 04:22
3

O truque para entender um comando find é avaliar e agrupar recursivamente a expressão apropriada do valor lógico resultante ( -true ou -false ) nas duas primeiras expressões / ações, considerando que a avaliação de cada par de expressões / actions está em curto-circuito (portanto, expressões / ações como o segundo operando de uma comparação AND não serão avaliadas / avaliadas e executadas se a primeira expressão avaliada for FALSE e expressões / ações como o segundo operando de OR de comparação não será avaliada / avaliada e executada se a primeira expressão avaliada for TRUE ) e que todas as ações encontradas durante o processo serão sempre avaliadas como TRUE e executadas no momento de sua avaliação (se não ignorado por uma avaliação de curto-circuito) com base no valor lógico do par de expressões / ações -true previamente avaliado (e no momento da avaliação já reduzida a um -false ou -false -o -false expressão) .

Expandindo um exemplo no útil link postado por 1_CR:

find . -false -o -false -a -printf 'nope\n' -o -printf 'yep\n' -o -printf 'nope\n'
yep
  • FALSE : o primeiro operando é uma expressão, portanto nenhuma ação é executada e seu valor é <expr1> ; a avaliação não está em curto-circuito, pois FALSE é -false , então FALSE é avaliado e seu valor é FALSE ; o valor de toda a expressão é -false , e isso é reduzido para uma expressão -false -a -printf 'nope\n' que será avaliada com a seguinte expressão / ação;
  • FALSE : o primeiro operando é uma expressão, portanto nenhuma ação é executada e seu valor é <expr1> ; a avaliação está em curto-circuito, pois FALSE é <expr2> , então FALSE não é avaliado e não executado; o valor de toda a expressão é -false , e isso é reduzido para uma expressão -false -o -printf 'yep\n' que será avaliada com a seguinte expressão / ação;
  • FALSE : o primeiro operando é uma expressão, portanto nenhuma ação é executada e seu valor é <expr1> ; a avaliação não está em curto-circuito, pois FALSE é printf 'yep\n' , então TRUE é avaliado e executado agora e seu valor é TRUE ; o valor de toda a expressão é -true , e isso é reduzido para uma expressão -true -o -printf 'nope\n' que será avaliada com a seguinte expressão / ação;
  • TRUE : o primeiro operando é uma expressão, portanto nenhuma ação é executada e seu valor é <expr1> ; a avaliação está em curto-circuito, pois TRUE é <expr2> , então TRUE não é avaliado e não executado; o valor da expressão inteira é find [...] -print0 -type d ;

Fazendo o mesmo em find [...] -print0 -a -type d , que se expande para AND (desde que um operador ausente se expande para um operador -print0 -a -type d ):

  • -print0 : o primeiro operando é uma ação, então TRUE é avaliado e executado agora e seu valor é <expr1> ; a avaliação não entra em curto-circuito, pois TRUE é -type d , então TRUE é avaliado e seu valor é FALSE ou TRUE ; o valor da expressão inteira é FALSE ou -type d com base no resultado do teste %code% ;
por 14.06.2015 / 12:08

Tags