Herramientas de usuario

Herramientas del sitio


notas:programacion:introduccion_a_awk

Uso básico de AWK

Qué es awk

AWK es una herramienta de procesamiento de patrones en líneas de texto. Su utilización estándar es la de filtrar archivos o salida de comandos, tratando las líneas para, por ejemplo, mostrar una determinada información sobre las mismas.

Por ejemplo:

  Mostrar sólo los nombres y los tamaños de los ficheros:
  # ls -l | awk '{ print $8 ":" $5 }'

  Mostrar sólo los nombres y tamaños de ficheros .txt:
  # ls -l | awk '$8 ~ /\.txt/ { print $8 ":" $5 }'

  Imprimir las líneas que tengan más de 4 campos/columnas:
  # awk 'NF > 4 {print}' fichero

Formato de uso

El uso básico de AWK es:

 awk [condicion] { comandos }

Donde:

  • [condicion] representa una condición de matcheo de líneas o parámetros.
  • comandos : una serie de comandos a ejecutar:
    • $0 → Mostrar la línea completa
    • $1-$N → Mostrar los campos (columnas) de la línea especificados.
    • FS → Field Separator (Espacio o TAB por defecto)
    • NF → Número de campos (fields) en la línea actual
    • NR → Número de líneas (records) en el stream/fichero a procesar.
    • OFS → Output Field Separator (” ”).
    • ORS → Output Record Separator (“\n”).
    • RS → Input Record Separator (“\n”).
    • BEGIN → Define sentencias a ejecutar antes de empezar el procesado.
    • END → Define sentencias a ejecutar tras acabar el procesado.
    • length → Longitud de la línea en proceso.
    • FILENAME → Nombre del fichero en procesamiento.
    • ARGC → Número de parámetros de entrada al programa.
    • ARGV → Valor de los parámetros pasados al programa.

Las funciones utilizables en las condiciones y comandos son, entre otras:

  • close(fichero_a_reiniciar_desde_cero)
  • cos(x), sin(x)
  • index()
  • int(num)
  • lenght(string)
  • substr(str,pos,len)
  • tolower()
  • toupper()
  • system(orden_del_sistema_a_ejecutar)
  • printf()

Los operadores soportados por awk son los siguientes:

  • *, /, %, +, -, =, ++, –, +=, -=, *=, /=, %=.

El control de flujo soportado por AWK incluye:

  • if ( expr ) statement
  • if ( expr ) statement else statement
  • while ( expr ) statement
  • do statement while ( expr )
  • for ( opt_expr ; opt_expr ; opt_expr ) statement
  • for ( var in array ) statement
  • continue, break
  • (condicion)? a : b → if(condicion) a else b;

Las operaciones de búsqueda son las siguientes:

  • /cadena/ → Búsqueda de cadena.
  • /^cadena/ → Búsqueda de cadena al principio de la línea.
  • /cadena$/ → Búsqueda de cadena al final de la línea.
  • $N ~ /cadena/ → Búsqueda de cadena en el campo N.
  • $N !~ /cadena/ → Búsqueda de cadena NO en el campo N.
  • /(cadena1)|(cadena2)/ → Búsqueda de cadena1 OR cadena2.
  • /cadena1/,/cadena2>/ → Todas las líneas entre cadena1 y cadena2.

Ejemplos de selección de columnas

 Mostrar una determinada columna de información:
 # ls -l | awk '{ print $5 }'
 176869
 12
 4096
 4096

 Mostrar varias columnas, así como texto adicional (entre comillas):
 # ls -l | awk '{ print $8 ":" $5 }'
 AEMSolaris7.pdf:176869
 fich1:12
 Desktop:4096
 docs:4096

 Imprimir campos en otro orden:
 # awk '{ print $2, $1 }' fichero

 Imprimir último campo de cada línea:
 # awk '{ print $NF }' fichero

 Imprimir los campos en orden inverso:
 # awk '{ for (i = NF; i > 0; --i) print $i }' fichero

 Imprimir última línea:
 # awk '{line = $0} END {print line}'

 Imprimir primeras N líneas:
 # awk 'NR < 100 {print}' 

 Mostrar las líneas que contienen valores numéricos mayor o menor que uno dado:
 # ls -l | awk '$5 > 1000000 { print $8 ":" $5 }'

 # ls -l | awk '$5 > 1000000 || $5 < 100 { print $8 ":" $5 }'
 fich1:12
 z88dk-src-1.7.tgz:2558227
 (También hay operaciones &&)

 Mostrar la línea con el valor numérico más grande en un campo determinado:
 # awk '$1 > max { max=$1; linea=$0 }; END { print max, linea }' fichero

 Mostrar aquellos ficheros cuya longitud es mayor que 10 caracteres:
 # ls -l | awk 'length($8) > 10 { print NR " " $8 }'
 2 AEMSolaris7.pdf
 10 function_keys.txt
 14 notas_solaris.txt
 19 z88dk-src-1.7.tgz
 (Campo $8 -nombrefichero- > 10 caracteres, y numero de record)

 Mostrar líneas con más o menos de N caracteres:
 # awk 'length > 75' fichero
 # awk 'length < 75' fichero

 Mostrar campos/líneas que cumplan determinadas condiciones entre campos:
 # awk '$2 > $3 {print $3}' fichero
 # awk '$1 > $2 {print length($1)}' fichero

 Mostrar y el número de campos de un fichero además de la línea:
 # awk '{ print NF ":" $0 } ' fichero

 Mostrar y numerar sólo las líneas no vacías (no en blanco):
 # awk 'NF { $0=++a " :" $0 }; { print }'
 
 Imprimir las líneas que tengan más de N campos:
 # awk 'NF > 5 { print $0 }' fichero

 Mostrar el número de línea de cada fichero de una lista iniciando 
 desde cero la cuenta de líneas al empezar cada fichero:
 # awk '{print FNR "\t:" $0}' *.txt

 Mostrar el número de línea de cada fichero de una lista sin resetear
 la cuenta de líneas al empezar cada nuevo fichero:
 # awk '{print FNR "\t:" $0}' *.txt

Matcheo/Sustitución de cadenas

 Mostrar las líneas que contengan una determinada cadena
 # awk '/cadena/ { print }' fichero

 Mostrar las líneas que NO contengan una determinada cadena
 # awk '! /cadena/ { print }' fichero

 # ls -l | awk '/4096/ { print $8 ":" $5 }'
   Desktop:4096
   docs:4096

 Mostrar todas las líneas que aparezcan entre 2 cadenas:
 # awk '/cadena_inicio/, /cadena_fin/' fichero

 Comparaciones exactas de cadenas:
 # awk '$1 == "fred" { print $3 }' fichero

 Líneas que contengan cualquier numero en punto flotante:
 # awk '/[0-9]+\.[0-9]*/ { print }' fichero

 Busqueda de cadenas en un campo determinado
 # awk '$5 ~ /root/ { print $3 }' fichero

 # ls -l | awk '$8 ~ /txt/ { print $8 ":" $5 }'
 apuntes.txt:9342
 function_keys.txt:2252
 notas_solaris.txt:57081
 (Nota, con ~ hemos buscado sólo /txt/ en el campo $8)

 Sustituir cadena1 por cadena2:
 # awk '{ gsub(/cadena1/,"cadena2"); print }' fichero

 Sustituir 1 por 2 sólo en las líneas que contengan "cadena3".
 # awk '/cadena3/ { gsub(/1/, "2") }; { print }' fichero

 Sustituir una cadena en las líneas que no contengan "cadena3".
 # awk '!/cadena3/ { gsub(/1/, "2") }; { print }' fichero

 Sustituir una cadena u otra:
 # awk '{ gsub(/cadena1|cadena2/, "nueva"); print}' fichero

Filtrado / Eliminación de información

 Filtrar las líneas en blanco (numero campos ==0):
 # cat file.txt | awk {' if (NF != 0) print $0 '}

 Contar número de líneas donde la columna 3 sea mayor que la 1:
 # awk '$3 > $1 {print i + "1"; i++}' fichero

 Eliminar campo 2 de cada línea:
 # awk '{$2 = ""; print}' fichero

 Eliminar líneas duplicadas aunque sean no consecutivas:lines.
 # awk '!temp_array[$0]++' fichero

 (Se basa en utilizar un array de tipo hash/diccionario temporal donde
 las líneas que aún no han aparecido valen 0, y las que han aparecido !=0)

 Saltar 1000 Líneas de un fichero:
 # awk '{if ( NR > 1000 ) { print $0 }}' fichero

 Saltar líneas < 10 y > 20:
 # awk '(NR >= 0) && (NR <= 20) { print $0 }'

Cálculos de tamaños / longitudes

 Imprimir el número de líneas que contienen una cadena:
 # awk '/cadena/ {nlines = nlines + 1} END {print nlines}' fichero
  
 Sumar todos los tamaños de ficheros de un ls -l, o con una condición:
 # ls -l | awk '{ sum += $5 } END { print sum }'
 3660106
 # ls -l | awk ' $3 == "sromero" { sum += $5 } END { print sum }'
 3660106

 Contar número de líneas del fichero:
 # awk 'END {print NR}' infile

 Contar el número de líneas vacías de un fichero:
 # awk 'BEGIN { x=0 } /^$/ {x=x+1} END { print "Lineas vacias:", x }' fichero
 
 NOTA: Expandido para leerlo mejor:
    BEGIN { x=0 } 
    /^$/  { x=x+1 } 
    END   { print "Lineas vacias:", x } 

 Contar el número de palabras / campos en un fichero:
 # awk '{ total = total + NF }; END { print total+0 }' fichero

 Contar el número total de líneas que contienen una cadena:
 # awk '/cadena/ { total++ }; END { print total+0 }' fichero

 Imprimir con formato:
 yes | head -10 | awk '{printf("%2.0f", NR)}'

 Calcular la suma de todos los campos de cada línea
 # awk '{suma=0; for (i=1; i<=NF; i++) suma=suma+$i; print suma}' fichero

 Calcular la suma y la media de todas las primeras columnas del fichero:
 # awk '{ suma += $1 } END { print "suma:", s, " media:", s/NR }

Cambio de IFS (Field Separator)

 Sacar campos 1 y 3 de /etc/passwd: 
 # awk -F":" '{ print $1 "\t" $3 }' /etc/passwd

 Sacar datos de un fichero CSV separado por comas:
 # awk -F"," '$1=="Nombre" { print $2 }' fichero.csv

Otros

 Tabular líneas con 3 espacios:
 # awk '{ sub(/^/, "   "); print }'

 Obtener 1 números aleatorio:
 # awk '{print rand()}'

 Generar 40 número aleatorio (0-100) sustituyendo la línea por el número:
 # yes | head -40 | awk '{ print int(101*rand())}'

 Generar 40 números aleatorios sólo con awk:
 # awk 'BEGIN { for (i = 1; i <= 40; i++) print int(101 * rand()) }'

 Reemplazar cada campo por su valor absoluto:
 # awk '{ for (i=1; i<=NF; i=i+1) if ($i<0) $i=-$i print}' fichero

 Definición y utilización de funciones propias (sólo nawk):
 # awk '{for (field=1; field<=NF; ++field) 
        {print EsPositivo($field)}};

     function EsPositivo(n) {
       if (n<0) return 0
       else     return 1 }'
      
 Partir un mbox en ficheros individuales (Ben Okopnik en Linux Gazzette #175).
 # awk '{if (/^From /) f=sprintf("%%03d",++a);print>>f}' mail_file
notas/programacion/introduccion_a_awk.txt · Última modificación: 2013/11/06 18:19 por cayu