stringtranslate.com

AWK

AWK ( / ɔː k / [4] ) es un lenguaje de dominio específico diseñado para el procesamiento de texto y normalmente utilizado como herramienta de extracción de datos e informes. Al igual que sed y grep , es un filtro [4] y es una característica estándar de la mayoría de los sistemas operativos tipo Unix .

El lenguaje AWK es un lenguaje de secuencias de comandos basado en datos que consta de un conjunto de acciones que se deben realizar contra flujos de datos textuales (ya sea ejecutados directamente en archivos o utilizados como parte de una canalización ) con el fin de extraer o transformar texto, como producir texto formateado. informes. El lenguaje utiliza ampliamente el tipo de datos de cadena , matrices asociativas (es decir, matrices indexadas por cadenas clave) y expresiones regulares . Si bien AWK tiene un dominio de aplicación previsto limitado y fue diseñado especialmente para admitir programas de una sola línea , el lenguaje es Turing completo , e incluso los primeros usuarios de AWK de Bell Labs a menudo escribían grandes programas AWK bien estructurados. [5]

AWK fue creado en Bell Labs en la década de 1970, [6] y su nombre se deriva de los apellidos de sus autores: Alfred Aho (autor de egrep ), Peter Weinberger (que trabajó en pequeñas bases de datos relacionales) y Brian Kernighan . El acrónimo se pronuncia igual que el nombre de la especie de ave auk , que se ilustra en la portada de The AWK Programming Language . [7] Cuando se escribe en letras minúsculas, como awk, se refiere al programa Unix o Plan 9 que ejecuta scripts escritos en el lenguaje de programación AWK.

Historia

Según Brian Kernighan, uno de los objetivos de AWK era tener una herramienta que pudiera manipular fácilmente tanto números como cadenas. AWK también se inspiró en el lenguaje de programación de Marc Rochkind que se usaba para buscar patrones en los datos de entrada y se implementó usando yacc . [8]

Como una de las primeras herramientas que apareció en la versión 7 de Unix , AWK agregó funciones computacionales a una canalización de Unix además del shell Bourne , el único lenguaje de scripting disponible en un entorno Unix estándar. Es una de las utilidades obligatorias de la Especificación Única UNIX , [9] y es requerida por la especificación Base Estándar de Linux . [10]

En 1983, AWK era una de varias herramientas UNIX disponibles para el sistema operativo UNOS de Charles River Data Systems bajo la licencia de Bell Laboratories . [11]

AWK fue revisado y ampliado significativamente entre 1985 y 1988, lo que dio como resultado la implementación GNU AWK escrita por Paul Rubin, Jay Fenlason y Richard Stallman , lanzada en 1988. [12] GNU AWK puede ser la versión más implementada [13] porque se incluye con los paquetes de Linux basados ​​en GNU. GNU AWK ha sido mantenido únicamente por Arnold Robbins desde 1994. [12] La fuente nawk (Nuevo AWK) de Brian Kernighan se publicó por primera vez en 1993 sin publicidad y públicamente desde finales de los años 1990; Muchos sistemas BSD lo utilizan para evitar la licencia GPL. [12]

AWK fue precedido por sed (1974). Ambos fueron diseñados para el procesamiento de textos. Comparten el paradigma orientado a líneas y basado en datos, y son particularmente adecuados para escribir programas de una sola línea , debido al bucle principal implícito y las variables de línea actuales. El poder y la concisión de los primeros programas AWK (en particular el poderoso manejo de expresiones regulares y la concisión debido a variables implícitas, que facilitan las frases ingeniosas) junto con las limitaciones de AWK en ese momento, fueron inspiraciones importantes para el lenguaje Perl (1987). En la década de 1990, Perl se hizo muy popular, compitiendo con AWK en el nicho de los lenguajes de procesamiento de textos Unix.

Estructura de los programas AWK

AWK lee la entrada línea por línea. Se escanea una línea para cada patrón en el programa y, para cada patrón que coincide, se ejecuta la acción asociada.

—Alfred  V. Aho [14]

Un programa AWK es una serie de pares de acciones de patrón, escritos como:

condición  {  acción  } condición  {  acción  } ...

donde la condición suele ser una expresión y la acción es una serie de comandos. La entrada se divide en registros, donde de forma predeterminada los registros están separados por caracteres de nueva línea para que la entrada se divida en líneas. El programa prueba cada registro con cada una de las condiciones por turno y ejecuta la acción para cada expresión que sea verdadera. Se puede omitir la condición o la acción. La condición por defecto coincide con todos los registros. La acción predeterminada es imprimir el registro. Esta es la misma estructura de patrón-acción que sed.

Además de una expresión AWK simple, como foo == 1o /^foo/, la condición puede ser BEGINo ENDhacer que la acción se ejecute antes o después de que se hayan leído todos los registros, o patrón1, patrón2 que coincide con el rango de registros que comienzan con un registro que coincide con patrón1 hasta incluyendo el registro que coincide con el patrón2 antes de intentar nuevamente compararlo con el patrón1 en las líneas siguientes.

Además de los operadores lógicos y aritméticos normales, las expresiones AWK incluyen el operador de tilde, ~que compara una expresión regular con una cadena. Como azúcar sintáctico útil , /regexp/ sin usar el operador de tilde coincide con el registro actual; esta sintaxis deriva de sed , que a su vez la heredó del editor ed , donde /se utiliza para realizar búsquedas. Esta sintaxis de uso de barras como delimitadores de expresiones regulares fue adoptada posteriormente por Perl y ECMAScript , y ahora es común. Perl también adoptó el operador de tilde.

Comandos

Los comandos AWK son declaraciones que sustituyen a la acción en los ejemplos anteriores. Los comandos AWK pueden incluir llamadas a funciones, asignaciones de variables, cálculos o cualquier combinación de los mismos. AWK contiene soporte integrado para muchas funciones; Los distintos sabores de AWK proporcionan muchos más. Además, algunas versiones admiten la inclusión de bibliotecas vinculadas dinámicamente , que también pueden proporcionar más funciones.

El comando de impresión

El comando de impresión se utiliza para generar texto. El texto de salida siempre termina con una cadena predefinida llamada separador de registros de salida (ORS) cuyo valor predeterminado es una nueva línea. La forma más simple de este comando es:

print
Esto muestra el contenido del registro actual. En AWK, los registros se dividen en campos y estos se pueden mostrar por separado:
print $1
Muestra el primer campo del registro actual.
print $1, $3
Muestra el primer y tercer campo del registro actual, separados por una cadena predefinida llamada separador de campo de salida (OFS) cuyo valor predeterminado es un carácter de espacio único.

Aunque estos campos ( $X ) pueden tener parecido con variables (el símbolo $ indica variables en los shells habituales de Unix y en Perl ), en realidad se refieren a los campos del registro actual. Un caso especial, $0 , se refiere al registro completo. De hecho, los comandos " print" y " print $0" son idénticos en funcionalidad.

El comando de impresión también puede mostrar los resultados de cálculos y/o llamadas a funciones:

/regex_pattern/  {  # Acciones a realizar en caso de que el registro (línea) coincida con el regex_pattern anterior  print  3 + 2  print  foobar ( 3 )  print  foobar ( variable )  print  sin ( 3 - 2 ) }

La salida se puede enviar a un archivo:

/regex_pattern/  {  # Acciones a realizar en caso de que el registro (línea) coincida con el regex_pattern anterior  print  "expresión"  >  "nombre de archivo" }

o a través de una tubería :

/regex_pattern/  {  # Acciones a realizar en caso de que el registro (línea) coincida con el regex_pattern anterior  print  "expresión"  |  "dominio" }

Variables incorporadas

Las variables integradas de Awk incluyen las variables de campo: $1, $2, $3, etc. ($0 representa el registro completo). Contienen el texto o los valores en los campos de texto individuales de un registro.

Otras variables incluyen:

Variables y sintaxis

Los nombres de las variables pueden utilizar cualquiera de los caracteres [A-Za-z0-9_], a excepción de las palabras clave del idioma. Los operadores + - * / representan suma, resta, multiplicación y división, respectivamente. Para la concatenación de cadenas , simplemente coloque dos variables (o constantes de cadena) una al lado de la otra. Es opcional utilizar un espacio intermedio si se trata de constantes de cadena, pero dos nombres de variables colocados uno al lado del otro requieren un espacio intermedio. Las comillas dobles delimitan las constantes de cadena. Las declaraciones no necesitan terminar con punto y coma. Finalmente, se pueden agregar comentarios a los programas usando # como primer carácter en una línea, o detrás de un comando o secuencia de comandos.

Funciones definidas por el usuario

En un formato similar a C , las definiciones de funciones constan de la palabra clave function, el nombre de la función, los nombres de los argumentos y el cuerpo de la función. A continuación se muestra un ejemplo de una función.

función  add_tres  ( número )  {  devolver  número  +  3 }

Esta declaración se puede invocar de la siguiente manera:

( patrón )  {  imprimir  add_tres ( 36 )  # Salidas '''39''' }

Las funciones pueden tener variables que se encuentran en el ámbito local. Los nombres de estos se agregan al final de la lista de argumentos, aunque sus valores deben omitirse al llamar a la función. Es una convención agregar algunos espacios en blanco en la lista de argumentos antes de las variables locales, para indicar dónde terminan los parámetros y comienzan las variables locales.

Ejemplos

¡Hola Mundo!

Aquí está el habitual "¡Hola, mundo!" programa escrito en AWK:

BEGIN  {  print  "¡Hola mundo!"  salida }

Imprimir líneas de más de 80 caracteres

Imprima todas las líneas de más de 80 caracteres. La acción predeterminada es imprimir la línea actual.

longitud ( $ 0 )  >  80

contar palabras

Cuente las palabras en la entrada e imprima el número de líneas, palabras y caracteres (como wc ):

{  palabras  +=  caracteres NF  += longitud + 1 # agregue uno para tener en cuenta el carácter de nueva línea al final de cada registro (línea) } FIN { imprimir NR , palabras , caracteres }           

Como no existe un patrón para la primera línea del programa, cada línea de entrada coincide de forma predeterminada, por lo que las acciones de incremento se ejecutan para cada línea. words += NFes una abreviatura de words = words + NF.

Sumar la última palabra

{  s  +=  $ NF  } FIN  {  imprimir  s  +  0  }

s se incrementa en el valor numérico de $NF , que es la última palabra de la línea según lo definido por el separador de campo de AWK (por defecto, espacio en blanco). NF es el número de campos en la línea actual, por ejemplo, 4. Dado que $4 es el valor del cuarto campo, $NF es el valor del último campo en la línea independientemente de cuántos campos tenga esta línea o si tiene más. o menos campos que las líneas circundantes. $ es en realidad un operador unario con la precedencia de operador más alta . (Si la línea no tiene campos, entonces NF es 0, $0 es la línea completa, que en este caso está vacía aparte de posibles espacios en blanco, por lo que tiene el valor numérico 0).

Al final de la entrada, el patrón FINAL coincide, por lo que se imprime s . Sin embargo, dado que es posible que no haya ninguna línea de entrada, en cuyo caso nunca se ha asignado ningún valor a s , por defecto será una cadena vacía. Agregar cero a una variable es un modismo de AWK para convertirla de una cadena a un valor numérico. (Concatenar una cadena vacía es forzar de un número a una cadena, por ejemplo, s "" . Tenga en cuenta que no hay ningún operador para concatenar cadenas, simplemente se colocan adyacentes). Con la coerción, el programa imprime "0" en una entrada vacía , sin él, se imprime una línea vacía.

Haga coincidir una variedad de líneas de entrada

NR  %  4  ==  1 ,  NR  %  4  ==  3  {  printf  "%6d %s\n" ,  NR ,  $ 0  }

La declaración de acción imprime cada línea numerada. La función printf emula el printf estándar de C y funciona de manera similar al comando de impresión descrito anteriormente. El patrón a coincidir, sin embargo, funciona de la siguiente manera: NR es el número de registros, generalmente líneas de entrada, que AWK ha leído hasta ahora, es decir, el número de línea actual, comenzando en 1 para la primera línea de entrada. % es el operador de módulo . NR % 4 == 1 es cierto para las líneas de entrada 1.ª, 5.ª, 9.ª, etc. Del mismo modo, NR % 4 == 3 es cierto para las líneas de entrada 3.ª, 7.ª, 11.ª, etc. El patrón de rango es falso hasta que la primera parte coincide, en la línea 1, y luego permanece verdadero hasta el momento en que coincide la segunda parte, en la línea 3. Luego permanece falso hasta que la primera parte vuelve a coincidir en la línea 5.

Por lo tanto, el programa imprime las líneas 1,2,3, omite la línea 4, luego la 5,6,7, y así sucesivamente. Para cada línea, imprime el número de línea (en un campo de 6 caracteres de ancho) y luego el contenido de la línea. Por ejemplo, cuando se ejecuta en esta entrada:

RomaFlorenciaMilánNápolesTurínVenecia

El programa anterior imprime:

 1 Roma 2 Florencia 3 Milán 5 Turín 6 Venecia

Imprimir la parte inicial o final de un archivo

Como caso especial, cuando la primera parte de un patrón de rango es constantemente verdadera, por ejemplo 1 , el rango comenzará al principio de la entrada. De manera similar, si la segunda parte es constantemente falsa, por ejemplo 0 , el rango continuará hasta el final de la entrada. Por ejemplo,

 /^--cortar aquí--$/ ,  0

imprime líneas de entrada desde la primera línea que coincide con la expresión regular ^--cut here--$ , es decir, una línea que contiene solo la frase "--cut here--", hasta el final.

Calcular frecuencias de palabras

Frecuencia de palabras usando matrices asociativas :

BEGIN  {  FS = "[^a-zA-Z]+" } {  para  ( i = 1 ;  i <= NF ;  i ++ )  palabras [ tolower ( $ i )] ++ } FIN  {  para  ( i  en  palabras )  imprimir  i ,  palabras [ i ] }

El bloque BEGIN establece el separador de campo en cualquier secuencia de caracteres no alfabéticos. Los separadores pueden ser expresiones regulares. Después de eso, llegamos a una acción simple, que realiza la acción en cada línea de entrada. En este caso, por cada campo de la línea, sumamos uno al número de veces que aparece esa palabra, primero convertida a minúsculas. Finalmente, en el bloque FIN, imprimimos las palabras con sus frecuencias. La línea

para (yo en palabras)

crea un bucle que recorre la matriz palabras , estableciendo i en cada subíndice de la matriz. Esto es diferente de la mayoría de los lenguajes, donde dicho bucle recorre cada valor de la matriz. Así, el bucle imprime cada palabra seguida de su recuento de frecuencia. tolowerfue una adición al One True awk (ver más abajo) realizada después de la publicación del libro.

Coincidir patrón desde la línea de comando

Este programa se puede representar de varias formas. El primero usa el shell Bourne para crear un script de shell que hace todo. Es el más corto de estos métodos:

#!/bin/shpatrón = " $1 " shift
awk '/' " $patrón " '/ { print FILENAME ":" $0 }' " $@ "  

El $patterncomando awk no está protegido por comillas simples, por lo que el shell expande la variable, pero debe colocarse entre comillas dobles para manejar adecuadamente los patrones que contienen espacios. Un patrón por sí solo, de la forma habitual, comprueba si toda la línea ( $0) coincide. FILENAMEcontiene el nombre del archivo actual. awk no tiene ningún operador de concatenación explícito; dos cadenas adyacentes las concatenan. $0se expande a la línea de entrada original sin cambios.

Hay formas alternativas de escribir esto. Este script de shell accede al entorno directamente desde awk:

#!/bin/shpatrón de exportación = " $1 " shift
awk '$0 ~ ENTORNO["patrón"] { print FILENAME ":" $0 }' " $@ "   

Este es un script de shell que utiliza ENVIRON, una matriz introducida en una versión más reciente de One True awk después de la publicación del libro. El subíndice de ENVIRONes el nombre de una variable de entorno; su resultado es el valor de la variable. Esto es como la función getenv en varias bibliotecas estándar y POSIX . El script de shell crea una variable de entorno patternque contiene el primer argumento, luego descarta ese argumento y awk busca el patrón en cada archivo.

~comprueba si su operando izquierdo coincide con su operando derecho; !~es su inversa. Una expresión regular es solo una cadena y se puede almacenar en variables.

La siguiente forma utiliza la asignación de variables en la línea de comandos, en la que un argumento de awk puede verse como una asignación a una variable:

#!/bin/shpatrón = " $1 " shift
awk '$0 ~ patrón { print FILENAME ":" $0 }' "patrón= $patrón " " $@ "   

O puede utilizar la opción de línea de comando -v var=value (por ejemplo, awk -v patrón="$pattern" ... ).

Finalmente, esto está escrito en awk puro, sin ayuda de un shell o sin la necesidad de saber demasiado sobre la implementación del script awk (como lo hace la asignación de variables en la línea de comando), pero es un poco largo:

BEGIN  {  patrón  =  ARGV [ 1 ]  for  ( i  =  1 ;  i  <  ARGC ;  i ++ )  # eliminar el primer argumento  ARGV [ i ]  =  ARGV [ i  +  1 ]  ARGC --  if  ( ARGC  ==  1 )  {  # el el patrón era lo único, así que fuerce la lectura desde la entrada estándar (usada por el libro)  ARGC  =  2  ARGV [ 1 ]  =  "-"  } } $ 0  ~  patrón  {  print  FILENAME  ":"  $ 0  }

Es BEGINnecesario no sólo para extraer el primer argumento, sino también para evitar que se interprete como un nombre de archivo una vez BEGINfinalizado el bloque. ARGC, siempre se garantiza que el número de argumentos sea ≥1, al igual ARGV[0]que el nombre del comando que ejecutó el script, generalmente la cadena "awk". ARGV[ARGC]es la cadena vacía, "". #inicia un comentario que se expande hasta el final de la línea.

Tenga en cuenta el ifbloque. awk solo verifica si debe leer la entrada estándar antes de ejecutar el comando. Esto significa que

awk 'progreso'

¡Solo funciona porque el hecho de que no haya nombres de archivos solo se verifica antes de progejecutarlo! Si lo establece explícitamente ARGCen 1 para que no haya argumentos, awk simplemente se cerrará porque considera que no hay más archivos de entrada. Por lo tanto, debe decir explícitamente que se lea desde la entrada estándar con el nombre de archivo especial -.

Scripts AWK autónomos

En sistemas operativos tipo Unix, se pueden construir scripts AWK autónomos utilizando la sintaxis shebang .

Por ejemplo, un script que envía el contenido de un archivo determinado a la salida estándar se puede crear creando un archivo print.awkcon el siguiente nombre:

#!/usr/bin/awk -f {  imprimir  $ 0  }

Se puede invocar con:./print.awk <filename>

Le -fdice a awk que el argumento que sigue es el archivo desde el cual leer el programa AWK, que es el mismo indicador que se usa en sed. Dado que a menudo se utilizan para frases ingeniosas, ambos programas ejecutan de forma predeterminada un programa proporcionado como argumento de línea de comandos, en lugar de un archivo separado.

Versiones e implementaciones

AWK fue escrito originalmente en 1977 y distribuido con la Versión 7 de Unix .

En 1985, sus autores comenzaron a ampliar el lenguaje, sobre todo añadiendo funciones definidas por el usuario. El lenguaje se describe en el libro The AWK Programming Language , publicado en 1988, y su implementación estuvo disponible en las versiones de UNIX System V. Para evitar confusiones con la versión anterior incompatible, esta versión a veces se denominaba "nueva awk" o nawk . Esta implementación se lanzó bajo una licencia de software libre en 1996 y Brian Kernighan aún la mantiene (consulte los enlaces externos a continuación). [ cita necesaria ]

Se incluían versiones antiguas de Unix, como UNIX/32Vawkcc , que convertían AWK a C. Kernighan escribió un programa para convertir awk a C++; se desconoce su estado. [dieciséis]

Libros

Ver también

Referencias

  1. ^ Stutz, Michael (19 de septiembre de 2006). "Comience con GAWK: fundamentos del lenguaje AWK" (PDF) . desarrolladorWorks . IBM . Archivado (PDF) desde el original el 27 de abril de 2015 . Consultado el 29 de enero de 2015 . [AWK] a menudo se denomina lenguaje basado en datos: las declaraciones del programa describen los datos de entrada que deben coincidir y procesarse en lugar de una secuencia de pasos del programa.
  2. ^ Andreas J. Pilavakis (1989). Taller UNIX . Educación Superior Internacional Macmillan. pag. 196.
  3. ^ Arnold Robbins (2015). Programación Awk eficaz: procesamiento de texto universal y coincidencia de patrones (4ª ed.). Medios O'Reilly. pag. 560.
  4. ^ ab James W. Livingston (2 de mayo de 1988). "El gran programa awk no es ningún pensamiento descabellado". Revisión Digital . pag. 91.
  5. ^ Raymond, Eric S. "Aplicación de minilenguajes". El arte de la programación Unix . Estudio de caso: awk. Archivado desde el original el 30 de julio de 2008 . Consultado el 11 de mayo de 2010 . El lenguaje de acción awk está completo en Turing y puede leer y escribir archivos.
  6. ^ Ah, Alfred V .; Kernighan, Brian W .; Weinberger, Peter J. (1 de septiembre de 1978). Awk: un lenguaje de procesamiento y escaneo de patrones (segunda edición) (Informe técnico). Manual de la séptima edición de Unix, volumen 2. Bell Telephone Laboratories, Inc. Consultado el 1 de febrero de 2020 .
  7. ^ ab Aho, Alfred V.; Kernighan, Brian W.; Weinberger, Peter J. (1988). El lenguaje de programación AWK. Compañía editorial Addison-Wesley. ISBN 9780201079814. Consultado el 16 de mayo de 2015 .
  8. ^ "Especial de UNIX: profesores Kernighan y Brailsford". Informático . 30 de septiembre de 2015. Archivado desde el original el 22 de noviembre de 2021.
  9. ^ "La especificación única de UNIX, versión 3, tabla de interfaz de utilidades". Archivado desde el original el 5 de enero de 2018 . Consultado el 18 de diciembre de 2005 .
  10. ^ "Capítulo 15. Comandos y utilidades". Especificación básica básica estándar de Linux 4.0 (informe técnico). Fundación Linux. 2008. Archivado desde el original el 16 de octubre de 2019 . Consultado el 1 de febrero de 2020 .
  11. ^ La guía privilegiada del universo (PDF) . Charles River Data Systems, Inc. 1983. pág. 13.
  12. ^ abc Robbins, Arnold (marzo de 2014). "El Proyecto GNU y yo: 27 años con GNU AWK" (PDF) . skeeve.com . Archivado (PDF) desde el original el 6 de octubre de 2014 . Consultado el 4 de octubre de 2014 .
  13. ^ Dougherty, Dale; Robbins, Arnold (1997). sed y awk (2ª ed.). Sebastopol, CA: O'Reilly. pag. 221.ISBN 1-565-92225-5.
  14. ^ Hamilton, Naomi (30 de mayo de 2008). "La AZ de los lenguajes de programación: AWK". Mundo de la informática . Archivado desde el original el 1 de febrero de 2020 . Consultado el 12 de diciembre de 2008 .
  15. ^ ab "Registros (Guía del usuario de GNU Awk)". Archivado desde el original el 14 de junio de 2020 . Consultado el 23 de mayo de 2020 .
  16. ^ Kernighan, Brian W. (24 al 25 de abril de 1991). Un traductor de AWK a C++ (PDF) . Conferencia Usenix C++. Washington DC. págs. 217-228. Archivado (PDF) desde el original el 22 de junio de 2020 . Consultado el 1 de febrero de 2020 .
  17. ^ "Registro de trabajo de FreeBSD para importar BWK awk al núcleo de FreeBSD". 16 de mayo de 2005. Archivado desde el original el 8 de septiembre de 2013 . Consultado el 20 de septiembre de 2006 .
  18. ^ "Procesamiento CSV con gawk (usando la extensión gawk-csv)". gawkextlib . 2018. Archivado desde el original el 25 de marzo de 2020.
  19. ^ James K. Lawless (1 de mayo de 1997). "Examen del compilador TAWK". Diario del Dr. Dobb . Archivado desde el original el 21 de febrero de 2020 . Consultado el 21 de febrero de 2020 .
  20. ^ "Jawk en SourceForge". Archivado desde el original el 27 de mayo de 2007 . Consultado el 23 de agosto de 2006 .
  21. ^ "Página de inicio de xgawk". Archivado desde el original el 18 de abril de 2013 . Consultado el 7 de mayo de 2013 .
  22. ^ "QSEAWK en GitHub". GitHub . Archivado desde el original el 11 de junio de 2018 . Consultado el 6 de septiembre de 2017 .
  23. ^ "CLAWK en GitHub". GitHub . Archivado desde el original el 25 de agosto de 2021 . Consultado el 1 de junio de 2021 .

Otras lecturas

enlaces externos