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").