Explicar el comando awk

Hoy estaba buscando un comando en línea para imprimir las dos líneas siguientes después de un patrón y encontré un comando awk que no puedo entender.

$ /usr/xpg4/bin/awk '_&&_--;/PATTERN/{_=2}' input 

¿Alguien puede explicarlo?

Consulte https://stackoverflow.com/a/17914105/1745001 para obtener la respuesta que se duplicó aquí.

_ se está utilizando aquí como un nombre de variable (válido pero obviamente confuso). Si lo reescribes como:

 awk 'x && x--; /PATTERN/ { x=2 }' input 

entonces es un poco más fácil de analizar. Siempre que /PATTERN/ coincida, la variable se establece en 2 (y esa línea no se genera) – esa es la segunda mitad. La primera parte se dispara cuando x no es cero, y disminuye x así como también imprime la línea actual (la acción predeterminada, ya que esa cláusula no especifica una acción).

El resultado final es imprimir las dos líneas inmediatamente después de cualquier coincidencia del patrón, siempre que ninguna de esas líneas coincida con el patrón.

Simplemente coloque el comando imprime un número de líneas después de una expresión de expresión regular dada que no incluye la línea coincidente.

El número de líneas se especifica en el bloque {_=2} y la variable _ se establece en 2 si la línea coincide con PATTERN . Cada línea que se lee después de una línea coincidente causa _ que disminuya. Puede leer _&&_-- como si _ mayor que cero y luego menos uno de ella, esto sucede para cada línea después de una coincidencia hasta que _ llegue a cero. Es bastante simple cuando reemplaza la variable _ con un nombre más sensible como n .

Una demostración simple debería dejarlo en claro (imprima las 2 líneas que siguen cualquier línea que coincida con foo ):

 $ cat file foo 1 2 3 foo a b c $ awk 'n && n--;/foo/{n=2}' file 1 2 a b 

Entonces n solo es verdadero cuando se establece en 2 después de hacer coincidir una línea con foo entonces disminuye n e imprime la línea actual. Debido a que awk tiene una evaluación de cortocircuito, n solo disminuye cuando n es verdadero (n> 0), por lo que los únicos valores posibles en este caso para n son 2,1 o 0.

Awk tiene la siguiente condition{block} estructura condition{block} y cuando se evalúa una condición True, se ejecuta el bloque para el registro actual. Si no proporciona un locking, awk usa el bloque predeterminado {print $0} entonces n && n--; es una condición sin un bloque que solo se evalúa como Verdadero para n líneas después de la coincidencia de expresión regular. El punto y coma simplemente delimita la condición n&&n-- para las condiciones /foo/ hace explícito que la condición no tiene bloque.

Para imprimir las dos líneas siguientes al partido, incluida la coincidencia, haría:

 $ awk '/foo/{n=3} n && n--' file foo 1 2 foo a b 

Extra extra: el hecho de que se use la ruta completa de /usr/xpg4/bin/awk me dice que este código está destinado a una máquina Solaris ya que /usr/bin/awk está totalmente roto y debe evitarse a toda costa.

Maravillosamente oscuro. Se actualizará cuando el tiempo lo permita.

_ se está utilizando como un nombre de variable. El && es un operador lógico que tiene 2 acciones verdaderas que se ejecutan juntas. Una vez que el valor de _ se reduce a cero, la segunda mitad de && es falsa y no se genera ninguna salida.

 print -- " xxxxx yyyy PATTERN zzz aa bbb ccc ddd" | awk '_&&_--;/PATTERN/{_=2}' 

salida

 zzz aa 

la versión de depuración

 print -- " xxxxx yyyy PATTERN zzz aa bbb ccc ddd" | awk '_&&_--;{print "_="_;print _&&_};/PATTERN/{_=2;print "_="_ }' 

salida

 _= 0 _= 0 _= 0 _= 0 _=2 zzz _=1 1 aa _=0 0 _=0 0 _=0 0 _=0 0 

Explicación

awk expressions tiene la siguiente forma:

 condition action; NEXT_EXPRESSION 

Si la condición es verdadera acción (s) se ejecutará. Además, si la condición es verdadera pero la acción se ha omitido, awk ejecutará print (la acción predeterminada).

Tiene dos expresiones en su código que se ejecutarán en cada línea de entrada:

 _&&_-- ; /PATTERN/{_=2} 

Ambos están separados por a ; . Como dije, la print acción predeterminada ocurrirá si se omite la acción, es lo mismo que :

 _&&_-- {print}; /PATTERN/ {_=2} 

En su ejemplo, _ es un nombre de variable, que se inicializa por 0 en la primera línea de entrada, antes de su primer uso, automáticamente por awk.

La primera condición sería (0) && (0) .. Lo que hace que la condición sea falsa, ya que 0 && 0 evalúa como false y awk no se imprime.

Si se encuentra el patrón, _ se establecerá en 2 que hace que la primera condición sea (2) && (2) en la siguiente línea y (1) && (1) en la siguiente línea después de que esa línea se decrementa después de la la condición ha sido evaluada. Ambos están evaluando a true y awk imprimirá esas líneas.

Sin embargo, buen rompecabezas;)