Confusão sobre a diferença na saída do GNU / macOS grep ao usar -o

6

Por que o BSD grep no macOS produz apenas a primeira palavra aqui:

$ echo "once upon a time" | grep -o "[a-z]*"
once

mas todas as palavras aqui:

$ echo "once upon a time" | grep -o "[a-z][a-z]*"
once
upon
a
time

Ou usando expressões regulares estendidas:

$ echo "once upon a time" | grep -E -o "[a-z]*"
once

$ echo "once upon a time" | grep -E -o "[a-z]+"
once
upon
a
time

O GNU grep produzirá resultados idênticos para [a-z]+ (ou [a-z][a-z]* ) e [a-z]* :

$ echo "once upon a time" | ggrep -E -o "[a-z]*"
once
upon
a
time

$ echo "once upon a time" | ggrep -E -o "[a-z]+"
once
upon
a
time
    
por ch48h2o 07.03.2018 / 20:41

1 resposta

3

Coletando os pensamentos da seção de comentários, parece que isso se resume a como grep implementações diferentes decidiram lidar com correspondências vazias, e as expressões [a-z]* correspondem à cadeia vazia.

A opção -o não é definida pelo POSIX, então, como uma implementação lida com ela é deixada para os desenvolvedores.

O GNU grep obviamente joga fora as correspondências vazias, por exemplo, a correspondência da string vazia após once ao usar [a-z]* , e continua a processar a entrada do próximo caractere em diante.

O BSD grep , parece estar acertando o jogo vazio e decide que, por qualquer motivo, é o suficiente e pára por aí.

Stéphane menciona que a versão ast-open de grep entra em um loop infinito na correspondência vazia de [a-z]* após once e não passa desse ponto na sequência.

O OpenBSD grep parece ser diferente do macOS e do FreeBSD grep , pois a adição do sinal -w (que exige que as correspondências sejam delimitadas por limites de palavras) faz com que [a-z]* retorne cada palavra separadamente.

ilkkachu faz a observação de que -o com um padrão que permite corresponder uma cadeia vazia em algum sentido é confuso (ou possivelmente, pelo menos, ambíguo). Todos os jogos vazios devem ser impressos? Na verdade, existem infinitas correspondências depois de cada palavra na string dada.

A fonte do OpenBSD para grep (que exibe o mesmo comportamento de grep no macOS) contém ( src/usr.bin/grep/util.c ):

               if (r == 0) {
                        c = 1;
                        if (oflag && pmatch.rm_so != pmatch.rm_eo)
                                goto print;
                        break;
                }
        }
        if (oflag)
                return c;
print:

Isso basicamente diz, se o padrão corresponder ( r == 0 ) e se estivermos usando -o ( oflag ), e se o deslocamento inicial da coincidência for o mesmo que o deslocamento final da correspondência ( pmatch.rm_so == pmatch.rm_eo , ou seja uma partida vazia), o resultado da correspondência é não impresso e a correspondência nessa linha específica de entrada termina ( return c com c == 1 para "correspondência encontrada").

    
por 07.03.2018 / 22:55