Comenzando con awk

AWK por ejemplos

AWK es un lenguaje de manipulación de cadenas, utilizado principalmente en sistemas UNIX. La idea detrás de AWK era crear un lenguaje versátil para usar al trabajar con archivos, que no fuera demasiado complejo de entender.

AWK tiene algunas otras variantes, pero el concepto principal es el mismo, solo que con características adicionales. Estas otras variantes son NAWK y GAWK. GAWK contiene todas las funciones de ambos, mientras que NAWK está un paso por encima de AWK, por así decirlo.

La forma más sencilla de pensar en AWK es considerar que tiene 2 partes principales. El patrón y la acción.

Probablemente el ejemplo más básico de AWK: (Ver también: Hello World)

BEGIN {print "START"}
      {print        }
END   {print "STOP" }

Aquí, las palabras clave BEGIN y END son el patrón, mientras que la acción está dentro de {}. Este ejemplo sería inútil, pero solo se necesitarían cambios menores para convertirlo en una función útil.

BEGIN {print "File\tAuthor"}
      {print $8, "\t", $3}
END {print " - DONE - "}

Aquí, \t representa un carácter de tabulación y se usa para nivelar los límites de la línea de salida. $8 y $3 son similares al uso que se ve en Shell Scripts, pero en lugar de usar los argumentos 3 y 8, usa la columna 3 y 8 de la línea de entrada.

Entonces, este ejemplo imprimiría: Autor del archivo en la línea superior, mientras que la segunda línea tiene que ver con las rutas del archivo. $8 es el nombre del archivo, $3 es el propietario (Al mirar la ruta del directorio, esto será más claro). Finalmente, la línea inferior se imprimiría, como era de esperar - HECHO -

El crédito por el ejemplo anterior va a http://www.grymoire.com/Unix/Awk.html

Archivo de referencia

monedas.txt de Greg Goebel:

gold     1    1986  USA                 American Eagle
gold     1    1908  Austria-Hungary     Franz Josef 100 Korona
silver  10    1981  USA                 ingot
gold     1    1984  Switzerland         ingot
gold     1    1979  RSA                 Krugerrand
gold     0.5  1981  RSA                 Krugerrand
gold     0.1  1986  PRC                 Panda
silver   1    1986  USA                 Liberty dollar
gold     0.25 1986  USA                 Liberty 5-dollar piece
silver   0.5  1986  USA                 Liberty 50-cent piece
silver   1    1987  USA                 Constitution dollar
gold     0.25 1987  USA                 Constitution 5-dollar piece
gold     1    1988  Canada              Maple Leaf

teoría mínima

Awk general de una sola línea:

awk <awk program> <file>

o:

<shell-command> | awk <awk program> 

<shell-command> y <file> se tratan como awk input.

<programa awk> es un código que sigue esta plantilla (comillas simples, no dobles):

'BEGIN   {<init actions>};
 <cond1> {<program actions>};
 <cond2> {<program actions>};
 ...
 END  {<final actions>}'

dónde:

  • La condición <condX> suele ser una expresión regular /re/, que debe coincidir con las líneas de entrada awk;
  • <* acciones> son secuencias de declaraciones, similares a los comandos de shell, equipados con construcciones tipo C.

`` se procesa de acuerdo con las siguientes reglas:
  1. BEGIN ... y END ... son opcionales y se ejecutan antes o después de procesar las líneas de entrada de awk.
  2. Para cada línea en la entrada awk, si la condición <condN> es carne, entonces se ejecuta el bloque <acciones del programa> relacionado.
  3. {<acciones del programa>} por defecto es {print $0}.

Condiciones se puede combinar con operadores lógicos estándar:

    /gold/ || /USA/ && !/1986/

donde && tiene precedencia sobre ||;

La instrucción imprimir. La instrucción print item1 item2 imprime elementos en STDOUT. Los elementos pueden ser variables (X, $0), cadenas (“hola”) o números. item1, item2 se cotejan con el valor de la variable OFS; ¡item1 item2 están dañados! Use item1 " " item2 para espacios o printf para más funciones.

Variables no necesita $, es decir: print myVar; Las siguientes variables especiales están integradas en awk:

  • FS: actúa como separador de campos para dividir líneas de entrada awk en campos. Puedo ser un solo carácter, FS="c"; una cadena nula, FS="" (entonces cada carácter individual se convierte en un campo separado); una expresión regular sin barras, FS="re"; FS=" " representa series de espacios y tabuladores y es el valor predeterminado.
  • NF: el número de campos a leer;
  • $1, $2, …: 1er campo, 2do campo. etc. de la línea de entrada actual,
  • $0: línea de entrada actual;
  • NR: número de línea de venta actual.
  • OFS: cadena para cotejar los campos cuando se imprimen.
  • ORS: separador de registro de salida, por defecto una nueva línea.
  • RS: Separador de línea de entrada (registro). El valor predeterminado es nueva línea. Establecer como FS.
  • IGNORECASE: afecta a FS y RS cuando son expresiones regulares;

Ejemplos

Filtra las líneas por expresión regular gold y cuéntalas:

# awk 'BEGIN {print "Coins"} /gold/{i++; print $0}  END {print i " lines out of " NR}' coins.txt
Coins
gold     1    1986  USA                 American Eagle      
gold     1    1908  Austria-Hungary     Franz Josef 100 Korona 
gold     1    1984  Switzerland         ingot 
gold     1    1979  RSA                 Krugerrand 
gold     0.5  1981  RSA                 Krugerrand 
gold     0.1  1986  PRC                 Panda                       
gold     0.25 1986  USA                 Liberty 5-dollar piece
gold     0.25 1987  USA                 Constitution 5-dollar piece
gold     1    1988  Canada              Maple Leaf
9 lines out of 13

Acción y condición print $0 predeterminadas basadas en la variable interna awk NR:

# awk 'BEGIN {print "First 3 coins"} NR<4' coins.txt
First 3 coins                                                  
gold     1    1986  USA                 American Eagle         
gold     1    1908  Austria-Hungary     Franz Josef 100 Korona 
silver  10    1981  USA                 ingot
Formateo con estilo C `printf`:
# awk '{printf ("%s \t %3.2f\n", $1, $2)}' coins.txt
gold     1.00                                      
gold     1.00                                      
silver   10.00                                     
gold     1.00                                      
gold     1.00                                      
gold     0.50                                      
gold     0.10                                      
silver   1.00                                      
gold     0.25                                      
silver   0.50                                      
silver   1.00                                      
gold     0.25                                      
gold     1.00

Ejemplos de condiciones

awk 'NR % 6'            # prints all lines except those divisible by 6
awk 'NR > 5'            # prints from line 6 onwards (like tail -n +6, or sed '1,5d')
awk '$2 == "foo"'       # prints lines where the second field is "foo"
awk '$2 ~ /re/'         # prints lines where the 2nd field mateches the regex /re/
awk 'NF >= 6'           # prints lines with 6 or more fields
awk '/foo/ && !/bar/'   # prints lines that match /foo/ but not /bar/
awk '/foo/ || /bar/'    # prints lines that match /foo/ or /bar/ (like grep -e 'foo' -e 'bar')
awk '/foo/,/bar/'       # prints from line matching /foo/ to line matching /bar/, inclusive
awk 'NF'                # prints only nonempty lines (or: removes empty lines, where NF==0)
awk 'NF--'              # removes last field and prints the line

Al agregar una acción {...}, se puede imprimir un campo específico, en lugar de la línea completa, por ejemplo:

awk '$2 ~ /re/{print $3 " " $4}'

imprime el tercer y cuarto campo de líneas donde el segundo campo coincide con la expresión regular /re/.

Algunas funciones de cadena

Función substr():

# awk '{print substr($3,3) " " substr($4,1,3)}' 
86 USA                                            
08 Aus                                            
81 USA                                            
84 Swi                                            
79 RSA                                            
81 RSA                                            
86 PRC                                            
86 USA                                            
86 USA                                            
86 USA                                            
87 USA                                            
87 USA                                            
88 Can                                            

match(s, r [, arr]) devuelve la posición en s donde aparece la expresión regular r y establece los valores de RSTART y RLENGTH. Si se proporciona el argumento arr, devuelve la matriz arr donde los elementos se establecen en la subexpresión entre paréntesis coincidente. Las coincidencias del elemento 0’th de arr se establecen en la coincidencia de expresión regular completa. También las expresiones arr[n, "start"] y arr[n, "longitud"] proporcionan la posición inicial y la longitud de cada subcadena coincidente.

Más funciones de cadena:

sub(/regexp/, "newstring"[, target])
gsub(/regexp/, "newstring"[, target])
toupper("string")
tolower("string")

Declaraciones

Una declaración simple suele ser cualquiera de las siguientes:

variable = expression 
print [ expression-list ] 
printf format [ , expression-list ] 
next # skip remaining patterns on this input line
exit # skip the rest of the input

Si stat1 y stat2 son sentencias, las siguientes también son sentencias:

{stat}

{stat1;  stat2}

{stat1 
stat2}

if ( conditional ) statement [ else statement ]

Las siguientes construcciones estándar tipo C son declaraciones:

if ( conditional ) statement [ else statement ]
while ( conditional ) statement
for ( expression ; conditional ; expression ) statement
break    # usual C meaning 
continue # usual C meaning 

Un bucle de estilo C para imprimir el elemento de descripción de longitud variable, comenzando con el campo 4:

# awk '{out=""; for(i=4;i<=NF;i++){out=out" "$i}; print out}' coins.txt
USA American Eagle                    
Austria-Hungary Franz Josef 100 Korona
USA ingot                             
Switzerland ingot                     
RSA Krugerrand                        
RSA Krugerrand                        
PRC Panda                             
USA Liberty dollar                    
USA Liberty 5-dollar piece            
USA Liberty 50-cent piece             
USA Constitution dollar               
USA Constitution 5-dollar piece       
Canada Maple Leaf

Tenga en cuenta que i se inicializa en 0.

Si se aplicaron condiciones y cálculos a campos numéricos:

# awk '/gold/ {if($3<1980) print $0 "$" 425*$2}' coins.txt    
gold     1    1908  Austria-Hungary     Franz Josef 100 Korona      $425
gold     1    1979  RSA                 Krugerrand                  $425   

Script ejecutable AWK

#!/usr/bin/gawk -f
# This is a comment
(pattern) {action}
...

Pasar variables de shell

# var="hello"
# awk -v x="$var" 'BEGIN {print x}'
hello

Hola Mundo

El ejemplo de Hello world es tan simple como:

awk 'BEGIN {print "Hello world"}'

El programa awk más básico consta de un valor verdadero (típicamente 1) y hace que awk repita su entrada:

$ date | awk '1'
Mon Jul 25 11:12:05 CEST 2016

Dado que “hola mundo” también es un valor real, también podría decir:

$ date | awk '"hello world"'
Mon Jul 25 11:12:05 CEST 2016

Sin embargo, su intención se vuelve mucho más clara si escribe

$ date | awk '{print}'
Mon Jul 25 11:12:05 CEST 2016

en cambio.

Cómo ejecutar programas AWK

Si el programa es corto, puede incluirlo en el comando que ejecuta awk:

awk -F: '{print $1, $2}' /etc/passwd

En este ejemplo, al usar el interruptor de línea de comando -F:, le recomendamos a awk que use : como delimitador de campos de entrada. es lo mismo que

awk 'BEGIN{FS=":"}{print $1,$2}' file

Alternativamente, podemos guardar todo el código awk en un archivo awk y llamar a este programa awk así:

awk -f 'program.awk' input-file1 input-file2 ...

program.awk puede ser cualquier programa multilínea, es decir:

# file print_fields.awk
BEGIN {print "this is a header"; FS=":"}
{print $1, $2}
END {print "that was it"}

Y luego ejecutarlo con:

awk -f print_fields.awk /etc/passwd   #-f advises awk which program file to load

O más generalmente:

awk -f program-file input-file1 input-file2 ...

La ventaja de tener el programa en un archivo separado es que puede escribir el programa con la identificación correcta para que tenga sentido, puede incluir comentarios con #, etc.