la repetición awk {n} no funciona

18

Estoy tratando de imprimir las líneas usando el símbolo de repetición {n} pero no funciona. Por. Por ejemplo, quiero imprimir todas las líneas cuya longitud es de 4 caracteres.

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

El código anterior no está imprimiendo eso. ¿Cómo solucionarlo para que pueda usar el símbolo de repetición? Sé la alternativa como awk '/^....$/' test_datayawk 'length ==3 ' test_data

Forever Learner
fuente
3
¿Qué distribución estás usando? Cual awk?
terdon
1
$ awk --version GNU Awk 3.1.7 $ cat / etc / redhat-release Red Hat Enterprise Linux Server versión 6.7 (Santiago)
Forever Learner
2
Yo diría awk '/^.{4}+$/{print}' <<<$'foods\nbaarsz\nfooo' que coincida exactamente con 4 caracteres. Además, como mencionaste, awk 'length($0) == 4' test_dataes compatible con casi todas las awkversiones.
Valentin Bajrami
44
Hacer awk --re-interval '/^.{4}$/' test_data o awk --posix '/^.{4}$/' test_datatrabajar?
Steeldriver
Gracias conductor de acero. Esto resolvió mi problema. Votado Gracias de nuevo :)
Forever Learner

Respuestas:

19

De acuerdo con la Guía del usuario de GNU Awk: Historial de características , se agregó soporte para operadores de rango de expresión regular en la versión 3.0, pero inicialmente requería la opción de línea de comando explícita

Nuevas opciones de línea de comandos:

  • Nuevas opciones de línea de comandos:
    • La opción --lint-old para advertir sobre construcciones que no están disponibles en la versión original Unix de la versión 7 de awk (ver V7 / SVR3.1).
    • La opción -m de BWK awk. (Brian todavía estaba en los Laboratorios Bell en ese momento.) Esto fue retirado más tarde de su awk y de su gawk.
    • La opción --re-interval para proporcionar expresiones de intervalo en expresiones regulares (consulte Operadores de expresiones regulares).
    • La opción --tradicional se agregó como un mejor nombre para --compat (ver Opciones).

En gawk4.0

Las expresiones de intervalo se convirtieron en parte de las expresiones regulares predeterminadas

Como está utilizando gawk3.x, deberá usar

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

o

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

o (gracias @ StéphaneChazelas) si desea una solución que sea portátil, use

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

(ya que --posixo --re-intervalcausaría un error en otras awkimplementaciones).

conductor de acero
fuente
Gracias Steeldriver, por su tiempo y ayuda. Votado y aceptado como respuesta
Forever Learner
44
Es mejor usarlo, POSIXLY_CORRECT=anything awk '/^.{4}/'ya que hace que el código portátil ( --posixao--re-interval podría causar un error en otras awkimplementaciones).
Stéphane Chazelas
Hola Stéphane Chazelas, cuando emití el comando $ POSIXLY_CORRECT = anything awk '/^.{4}/' test_data, imprimió todas las líneas. Entonces me di cuenta de que no hay un último dólar después de las repeticiones. Gracias por tus aportes. Votar su comentario y solución. Lo siento, lo entendí mal en primer lugar debido a la omisión de $ después de la repetición.
Forever Learner
20

ERE ( expresiones regulares extendidas como las utilizadas por awko egrep) inicialmente no tenían {x,y}. Se introdujo por primera vez en BRE (como lo usa grepo sed), pero con la \{x,y\}sintaxis que no rompió la portabilidad hacia atrás.

Pero cuando se agregó a ERE con esa {x,y}sintaxis, rompió la portabilidad hacia atrás ya que un foo{2}RE coincidía con algo diferente antes.

Entonces, algunas implementaciones decidieron no hacerlo. Usted encontrará que /bin/awk, /bin/nawky/bin/egrep en Solaris todavía no lo respeta (debe usar /usr/xpg4/bin/awko /usr/xpg4/bin/grep -E). Lo mismo para awky nawken FreeBSD (basado en el awkmantenido por Brian Kernighan (el ken awk)).

Para GNUawk , hasta hace relativamente poco (versión 4.0), tenía que llamarlo POSIXLY_CORRECT=anything awk '/^.{4}$/'para que lo honrara. mawkTodavía no lo honra .

Tenga en cuenta que ese operador es solo azúcar sintáctico. .{3,5}siempre se puede escribir, ....?.?por ejemplo (aunque, por supuesto, {3,5}es mucho más legible, y el equivalente a (foo.{5,9}bar){123,456}sería mucho peor).

Stéphane Chazelas
fuente
Gracias de nuevo Stéphane Chazelas. Lo siento, lo malo, no pude comprender tu respuesta inicialmente. Muchas gracias y votado.
Forever Learner
6

Esto funciona como se esperaba con GNU awk (gawk):

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

Pero falla con mawk que está más cerca de POSIX awky, AFAIK, es el predeterminado en los sistemas Ubuntu:

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

Entonces, una solución simple sería usar en gawklugar de awk. La {n}notación no es parte de la sintaxis POSIX BRE (expresión regular básica). Es por esogrep también falla aquí:

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

Sin embargo, es parte de ERE (expresiones regulares extendidas):

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

No sé qué sabor regex utiliza mawkPOSIX awk, pero supongo que es BRE. Usan una versión anterior de ERE según la respuesta de Stéphane . En cualquier caso, aparentemente está utilizando una versión awkque no implementa ERE o su entrada no tiene líneas con exactamente 4 caracteres. Esto podría suceder debido a espacios en blanco que no ve o glifos unicode, por ejemplo.

terdon
fuente
Hola terdon, quiero imprimir las líneas de 4 caracteres. No son los primeros cuatro caracteres de una línea. Por ejemplo, $ grep -E '^. {4} $' test_data, funcionará pero no funciona con awk
Forever Learner
@CppLearner sí, eso es lo que estoy haciendo aquí. ¿Qué quieres decir?
terdon
@CppLearner, la solución de @terdon solo imprime líneas de 4 caracteres de longitud. Pero si realmente solo le interesa la longitud de la línea, debe usar la length($0)que sea más eficiente que las expresiones regulares.
Stephen Kitt
Hola terdon, la solución de Steeldriver es lo que estaba buscando. Gracias por tu tiempo. Hola Stephen Kitt: Como mencioné en el problema, ya utilicé la longitud como alternativa, estaba más interesado en saber por qué la repetición de expresiones regulares {n} no funciona a partir del comentario de steeldriver. Llegué a saber que necesito usar la opción de --re-intervalo o --posix. Gracias por tu tiempo.
Forever Learner
1
mawkno está realmente más cerca de POSIX awk, y no usa BRE. Utiliza ERE pero sin el {x,y}operador.
Stéphane Chazelas