Por que o comando find -execdir do GNU se comporta de maneira diferente do encontrado pelo BSD?

4

No meu OSX, instalei o GNU find ao lado do padrão BSD find via: brew install findutils .

Tanto quanto eu entendo, o BSD find está seguindo os padrões POSIX e o GNU o torna opcional (de acordo com este post ), o que causa muitas inconsistências no resultado esperado.

Por exemplo:

encontrar o BSD

$ find -L /etc -execdir echo {} ';' | head
etc
AFP.conf
afpovertcp.cfg
aliases
aliases.db
apache2
extra
httpd-autoindex.conf
httpd-dav.conf
httpd-default.conf

encontrar GNU

$ gfind --version
find (GNU findutils) 4.4.2
$ POSIXLY_CORRECT=1 gfind -L /etc -execdir echo {} ';' | head
/etc
/etc/AFP.conf
/etc/afpovertcp.cfg
/etc/aliases
/etc/aliases.db
/etc/apache2
/etc/apache2/extra
/etc/apache2/extra/httpd-autoindex.conf
/etc/apache2/extra/httpd-dav.conf
/etc/apache2/extra/httpd-default.conf
gfind: 'echo' terminated by signal 13
gfind: 'echo' terminated by signal 13
... endless loop here

Observação: estou usando -L acima, pois meu /etc é vinculado a private/etc .

No GNU find manual eu posso ver que eu posso especificar POSIXLY_CORRECT para seguir o padrão POSIX, mas isso não funciona no exemplo acima.

Alguma outra maneira de forçar a mesma saída (por exemplo, padrão POSIX) para o GNU para o exemplo acima?

Além de infinitamente looping, porque o GNU imprime nomes de arquivos relativos e o BSD imprime caminhos completos?

    
por kenorb 18.12.2015 / 13:00

1 resposta

10

Não é um loop infinito , é apenas GNU find reportando que echo morreu de um SIGPIPE (porque a outra extremidade do canal no stdout foi fechada quando head morreu) .

-execdir não é especificado por POSIX. E mesmo para -exec , não há nada em a especificação POSIX que diga que, se o comando for morto por um SIGPIPE, find deve sair.

Então POSIX especificaria -execdir , gfind seria provavelmente mais compatível com POSIX do que seu BSD find (supondo que seu BSD encontre saídas quando seu filho morrer de um SIGPIPE conforme a formulação da sua pergunta sugerir, FreeBSD find não faz em meus testes e executa echo em um loop para cada arquivo (como para o GNU find, não infinito)).

Você pode dizer que, para casos mais comuns, find saindo de um filho morrendo de SIGPIPE seria preferível, mas o comando -exec uted ainda poderia morrer de um SIGPIPE por outras razões que não o pipe em stdout sendo fechado, então sair find para isso seria aceitável.

Com o GNU find , você pode dizer ao find para sair se um comando falhar com:

find . ... \( -exec echo {} \; -o -quit \)

Quanto a se uma implementação de find é permitida ou proibida de relatar crianças morrendo de um sinal no stderr, aqui (com o uso de -execdir ) estamos fora do escopo do POSIX, mas se -exec foi usado no lugar de -execdir , parece que seria um caso em que gfind não está em conformidade.

A especificação para find diz: "o erro padrão deve ser usado apenas para mensagens de diagnóstico" , mas também disponibiliza :

Default Behavior: When this section is listed as "The standard error shall be used only for diagnostic messages.", it means that, unless otherwise stated, the diagnostic messages shall be sent to the standard error only when the exit status indicates that an error occurred and the utility is used as described by this volume of POSIX.1-2008.

O que indicaria que, como find não retorna com um status de saída diferente de zero nesse caso, ele não deve exibir essa mensagem no stderr.

Note que pelo texto, tanto o GNU quanto o FreeBSD find não seriam compatíveis em um caso como:

$ find /dev/null -exec blah \;; echo "$?"
find: 'blah': No such file or directory
0

onde ambos relatam um erro sem definir o status de saída como diferente de zero. É por isso que eu levantei a questão sobre a lista de discussão do austin-group (os caras por trás do POSIX) .

Observe que, se você alterar seu comando para:

(trap '' PIPE; find -L /etc -execdir echo {} \; | head)

echo ainda será executado para todos os arquivos, mas ainda falhará, mas, desta vez, echo está relatando a mensagem de erro.

Agora, sobre filename vs /etc/filename vs ./filename sendo exibido.

Novamente, a opção -execdir não é padrão , não há texto que diga quem está certo e quem está errado. -execdir foi introduzido pelo BSD find e copiado posteriormente pelo GNU find .

O GNU find fez algumas mudanças (melhorias) intencionais sobre ele. Por exemplo, ele pré-anexa nomes de arquivos com ./ nos argumentos transmitidos aos comandos. Isso significa que find . -execdir cmd {} \; não tem problemas com nomes de arquivos que começam com - , por exemplo.

O fato de -L -execdir não passar um caminho de arquivo relativo ao diretório pai é, na verdade, um bug que afeta a versão 4.3.0 a 4.5.8 do GNU find . Foi corrigido em 4.5.9, mas isso está no ramo de desenvolvimento e não houve uma nova versão stable desde (a partir de 2015-12-22, embora um é iminente ).

Mais informações na lista de discussão findutils .

Se tudo o que você deseja é imprimir o nome base de todos os arquivos em /etc portably, basta fazer:

find -L /etc -exec basename {} \;

Ou mais eficientemente:

find -L ///etc | awk -F / '/\/\// && NR>1 {print last}
                          {if (NF > 1) last = $NF
                           else last = last "\n" $NF}
                          END {if (NR) print last}'

que você pode simplificar para

find -L /etc | awk -F / '{print $NF}'

se você puder garantir que os caminhos de arquivo não contenham caracteres de nova linha (IIRC, algumas versões do OS / X possuem esses arquivos em / etc).

GNUly:

find -L /etc -printf '%f\n'

Sobre se:

find -exec echo {} \;

no link ao qual você está se referindo, é POSIX ou não.

Não, como uma chamada de comando, isso não é POSIX. Um script que teria que não seria compatível.

POSIX find exige que pelo menos um caminho seja fornecido, mas deixa o comportamento não especificado se o primeiro argumento de não opção de find começar com - ou for um predicado find (como ! , ou ( ), portanto, o comportamento find do GNU é compatível, portanto, implementações relatam um erro (ou tratam o primeiro argumento como um caminho de arquivo mesmo que ele represente um predicado de localização) ou spray red pintar na sua cara, não há nenhuma razão POSIXLY_CORRECT afetaria o comportamento find lá.

    
por 18.12.2015 / 13:35

Tags