a repetição do awk {n} não está funcionando

18

Estou tentando imprimir as linhas usando o símbolo de repetição {n}, mas ele não está funcionando. Para. por exemplo, eu quero imprimir todas as linhas cujo comprimento é de 4 caracteres

 awk '/^.{4}$/' test_data

O código acima não está imprimindo isso. Como corrigi-lo para que eu possa usar o símbolo de repetição? Eu sei a alternativa como awk '/^....$/' test_dataeawk 'length ==3 ' test_data

Forever Learner
fonte
3
Que distribuição você está usando? Qual awk?
terdon
11
$ awk --version GNU Awk 3.1.7 $ cat / etc / redhat-release Servidor Red Hat Enterprise Linux Server versão 6.7 (Santiago)
Forever Learner
2
Eu diria awk '/^.{4}+$/{print}' <<<$'foods\nbaarsz\nfooo' para combinar exatamente 4 caracteres. Além disso, como você mencionou, awk 'length($0) == 4' test_dataé compatível com quase todas as awkversões.
Valentin Bajrami 29/03
4
Faz awk --re-interval '/^.{4}$/' test_data ou awk --posix '/^.{4}$/' test_datatrabalha?
steeldriver
Obrigado steeldriver. Isso resolveu meu problema. Votado. Obrigado novamente :)
Forever Learner

Respostas:

19

De acordo com o Guia do Usuário do GNU Awk: Histórico de recursos , o suporte para operadores de intervalo de expressão regular foi adicionado na versão 3.0, mas inicialmente exigia a opção explícita da linha de comando

Novas opções de linha de comando:

  • Novas opções de linha de comando:
    • A opção --lint-old para avisar sobre construções que não estão disponíveis na versão original do awk Versão 7 do Unk (consulte V7 / SVR3.1).
    • A opção -m do BWK awk. (Brian ainda estava no Bell Laboratories na época.) Isso foi removido mais tarde do awk e do gawk.
    • A opção --re-interval para fornecer expressões de intervalo em regexps (consulte Operadores de Regexp).
    • A opção --traditional foi adicionada como um nome melhor para --compat (consulte Opções).

Em gawk4.0,

Expressões de intervalo passaram a fazer parte das expressões regulares padrão

Como você está usando o gawk3.x, você precisará usar

awk --re-interval '/^.{4}$/'

ou

awk --posix '/^.{4}$/'

ou (obrigado @ StéphaneChazelas) se você quiser uma solução portátil, use

POSIXLY_CORRECT=anything awk '/^.{4}$/'

(desde --posixou --re-intervalcausaria um erro em outras awkimplementações).

chave de aço
fonte
Obrigado steeldriver, pelo seu tempo e ajuda. Upvoted e aceito como uma resposta
para sempre Learner
4
É melhor usar, POSIXLY_CORRECT=anything awk '/^.{4}/'pois isso cria código portátil (a --posixou --re-intervalcausaria um erro em outras awkimplementações).
Stéphane Chazelas 29/03/2017
Olá, Stéphane Chazelas, quando emiti o comando $ POSIXLY_CORRECT = awk '/^.{4}/' test_data, ele imprimiu todas as linhas. Então eu percebi que não há último dólar depois de repetições. Obrigado por suas contribuições. Voto positivo em seu comentário e solução. Desculpe, eu entendi errado em primeiro lugar devido à omissão do $ após repetição.
Forever Learner
20

EREs ( expressões regulares estendidas como usadas por awkou egrep) inicialmente não possuíam {x,y}. Foi introduzido pela primeira vez em BREs (conforme usado por grepou sed), mas com a \{x,y\}sintaxe que não quebrava a portabilidade reversa.

Mas quando foi adicionado aos EREs com essa {x,y}sintaxe, ele quebrou a portabilidade reversa, pois um foo{2}ER estava correspondendo a algo diferente antes.

Portanto, algumas implementações optaram por não fazer isso. Você verá que /bin/awk, /bin/nawke /bin/egrepno Solaris ainda não honrá-lo (você precisa usar /usr/xpg4/bin/awkou /usr/xpg4/bin/grep -E). Mesmo para awke nawkno FreeBSD (com base no awkmantido por Brian Kernighan (o kno awk)).

Para o GNUawk , até relativamente recentemente (versão 4.0), você precisava chamá- POSIXLY_CORRECT=anything awk '/^.{4}$/'lo para honrá-lo. mawkainda não o honra .

Observe que esse operador é apenas açúcar sintático. .{3,5}sempre pode ser escrito, ....?.?por exemplo (embora, {3,5}é claro, seja muito mais legível e o equivalente a (foo.{5,9}bar){123,456}seja muito pior).

Stéphane Chazelas
fonte
Mais uma vez obrigado Stéphane Chazelas. Desculpe, meu mal, não consegui compreender sua resposta inicialmente. Muito obrigado e votado.
Forever Learner
6

Isso funciona como esperado com o GNU awk(gawk):

$ printf 'abcd\nabc\nabcde\n' | gawk '/^.{4}$/'
abcd

Mas falha com o mawkque está mais próximo do POSIX awke, AFAIK, é o padrão nos sistemas Ubuntu:

$ printf 'abcd\nabc\nabcde\n' | mawk '/^.{4}$/'
$ ## prints nothing

Portanto, uma solução simples seria usar em gawkvez de awk. A {n}notação não faz parte da sintaxe POSIX BRE (expressão regular básica). É por isso que greptambém falha aqui:

$ printf 'abcd\nabc\nabcde\n' | grep '^.{4}$'
$

No entanto, faz parte do ERE (expressões regulares estendidas):

$ printf 'abcd\nabc\nabcde\n' | grep -E '^.{4}$'
abcd

Não sei qual tipo de expressão regular é usado pelo mawkPOSIX awk, mas acho que é BRE. Eles usam uma versão mais antiga do ERE de acordo com a resposta de Stéphane . De qualquer forma, aparentemente você está usando uma versão awkque não implementa ERE ou sua entrada não possui linhas com exatamente 4 caracteres. Isso pode acontecer devido ao espaço em branco que você não vê ou unicode glifos, por exemplo.

terdon
fonte
Olá Terdon, quero imprimir as linhas com 4 caracteres. Não são os quatro primeiros caracteres de uma linha. Por exemplo, $ grep -E '^. {4} $' test_data, funcionará, mas o mesmo não está funcionando com o awk
Forever Learner
@CppLearner sim, é o que estou fazendo aqui. O que você quer dizer?
terdon
@CppLearner, a solução da @ terdon imprime apenas linhas com 4 caracteres. Mas se você estiver realmente interessado apenas no comprimento da linha, use apenas o length($0)que é mais eficiente do que as expressões regulares.
Stephen Kitt
Olá, Terdon, a solução da steeldriver é o que eu estava procurando. Obrigado pelo seu tempo. Olá, Stephen Kitt, Como mencionei no problema, eu já usei o comprimento como alternativa, estava mais interessado em saber por que o regex de repetição {n} não está funcionando no comentário do steeldriver. Eu soube que precisava usar a opção de --re-interval ou --posix. Obrigado pelo seu tempo.
Forever Learner
11
mawknão está realmente mais perto do POSIX awke não usa BREs. Ele usa EREs, mas sem o {x,y}operador.
Stéphane Chazelas