awk repetition {n} não está funcionando

16

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

 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_data e awk 'length ==3 ' test_data

    
por Forever Learner 29.03.2017 / 14:04

3 respostas

18

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

Novas opções de linha de comando:

  • New command-line options:
    • The --lint-old option to warn about constructs that are not available in the original Version 7 Unix version of awk (see V7/SVR3.1).
    • The -m option from BWK awk. (Brian was still at Bell Laboratories at the time.) This was later removed from both his awk and from gawk.
    • The --re-interval option to provide interval expressions in regexps (see Regexp Operators).
    • The --traditional option was added as a better name for --compat (see Options).

Em gawk 4.0,

Interval expressions became part of default regular expressions

Como você está usando gawk 3.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}$/'

(porque --posix ou --re-interval causaria um erro em outras implementações awk ).

    
por 29.03.2017 / 14:30
19

EREs ( expressões regulares estendidas usadas por awk ou egrep ) inicialmente não tinham {x,y} . Foi introduzido pela primeira vez em BREs (como usado por grep ou sed ), mas com a sintaxe \{x,y\} que não quebrou a portabilidade para trás.

Mas quando foi adicionado a EREs com a sintaxe {x,y} , ele quebrou a portabilidade para trás, já que foo{2} RE estava combinando com algo diferente antes.

Algumas implementações optaram por não fazê-lo. Você verá que /bin/awk , /bin/nawk e /bin/egrep no Solaris ainda não o respeitam (você precisa usar /usr/xpg4/bin/awk ou /usr/xpg4/bin/grep -E ). Mesmo para awk e nawk no FreeBSD (baseado em o awk mantido por Brian Kernighan (o k em awk )).

Para o GNU awk , até há relativamente pouco tempo (versão 4.0), você tinha que chamá-lo com POSIXLY_CORRECT=anything awk '/^.{4}$/' para homenagear. mawk ainda não o respeita .

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

    
por 29.03.2017 / 14:21
6

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

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

Mas falha com mawk , que está mais próximo de POSIX awk e, AFAIK, é o padrão nos sistemas Ubuntu:

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

Portanto, uma solução simples seria usar gawk em vez de awk . A notação {n} não faz parte da sintaxe POSIX BRE (expressão regular básica). É por isso que grep també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

Eu não sei qual sabor de regex é usado por mawk ou POSIX awk , mas eu acho que é BRE . Eles usam uma versão mais antiga do ERE de acordo com a resposta do Stéphane . De qualquer forma, ou você está aparentemente usando uma versão de awk que não implementa ERE ou sua entrada não possui nenhuma linha com exatamente 4 caracteres. Isso pode acontecer por causa do espaço em branco que você não vê ou unicode glifos, por exemplo.

    
por 29.03.2017 / 14:12