PreguntasFrecuentes


¿Cómo muestro un rango de campos?

Desde [[RangoDeCampos-español?]], editar:


¿Cómo muestro el último campo de un registro?

Desde [[UltimoCampo-español?]], editar:


¿Cómo muestro un apóstrofo?

Desde MostrarApostrofos-español, editar:

Esta pregunta es tan frecuente que merece su propia respuesta. Y aunque pareciera que esto es una limitación del awk, en realidad casi siempre es culpa de la forma en como se utilizan los caracteres de citado (comillas y apóstrofos) en el shell.

En resumen

Use la secuencia de escape en base ocho ('\047') o printf ('print "%c", 39'). No use las secuencias de escape hexadecimales ('\x27') dado que podrían reaccionar negativamente con el texto lindante, dependiendo de la implementación de awk usada.

En detalle

Para mostrar el texto "dijo '¡Hola mundo!' y entonces devolvió 0", uno puede correr los siguientes programas:

BEGIN {
	print "dijo '¡Hola mundo!' y entonces devolvió 0"
	exit 0
}

Sin embargo, cuando uno intenta realizar algo similar en la consola:

awk 'BEGIN{print "dijo '¡Hola mundo!' y entonces devolvió 0";exit 0}'

...el shell se queja, dado a que intenta interpretar "¡Hola mundo!" como una cadena de parámetros para ser insertados entre dos textos agrupados con apóstrofos.

Lo primero que uno podría pensar, es agrupar el fragmento del programa en comillas en lugar de apóstrofos, pero podría dar problemas con los strings literales de awk y con el operador para referenciar campos "$", a menos que se escapen adecuadamente con contrabarras los caracteres como $, ", \, (entre otros), ofuscando bastante más el código.

Secuencias de escape hexadecimales

Desafortunadamente, la siguiente solución más obvia - especificar caracteres en hexa - parece funcionar al principio:

awk 'BEGIN{print "dijo \x27¡Hola mundo!\x27 y entonces devolvió 0";exit 0}'

...pero esto no siempre funciona. Pruebe por ejemplo el siguiente fragmento de código en gawk, mawk y en el awk de busybox y compare los resultados:

awk 'BEGIN{print "\x27foo!\x27"}'

Notese que mientras mawk y el awk del busybox dan los resultados esperados, gawk devuelve un caracter multibyte. En el párrafo 3 de la sección "Rationale" del Open Group Base Specifications issue 6 (en inglés), y reiterado en el manual de GNU awk en section 2.2 ("Secuencias de escape") (en inglés)), la notación hexadecimal '\xHH' es ambigua porque permite especificar más de dos bytes hexadecimales sucesivos. Desafortunadamente el comportamiento preciso cuando se dan más de dos bytes, depende de la implementación.

Secuencias de escape en base ocho

Por suerte siempre podemos recurrir a los cuchillos de piedra y pieles de osos: las secuencias de escape octales deben obligatoriamente tener ancho fijo.

awk 'BEGIN{print "\047foo!\047"}'

Usos y abusos de printf

O simplemente podríamos usar printf:

awk 'BEGIN{printf "%cfoo!%c\n", 39, 39}'

...pero entonces tendríamos que empezar a contar los parámetros para asegurarnos que todas las secuencias de cape tienen un número correspondiente. gawk tiene como característica una extensión de printf que permite reusar los argumentos de acuerdo a la posición especificada en la cadena de formato:

awk 'BEGIN{printf "%1$cfoo!%1$c\n", 39}'

...pero el beneficio de esto es mínimo en comparación a lo sucio termina quedando, así que mejor pretendamos no haber dicho nada.

Concatenación explícita

There is also the old fallback of putting a single quote character in its own variable and then using explicit string concatenation:

awk 'BEGIN{q="\047";print q"foo!"q}'

...pero esto es desprolijo cuando tenemos que manejar textos largos que contienen varios apóstrofos.

Haz lo correcto

La forma más prolija es simplemente escribir el programa en su propio archivo. Pueden haber formas específicas del shell para resolver este problema: siéntase libre de agregarlas a esta página si conoce alguna.


¿Cómo usar printf?

Desde printf-español, editar:

Muestra todas las palabras en cada línea:

awk '{for(i=1;i<=NF;++i) printf "%s ", $i;print ""}' nombredearchivo

Muestra todas las palabras salvo la primera, en cada línea:

awk '{for(i=2;i<=NF;++i) printf "%s ", $i;print ""}' nombredearchivo

Muestra desde la tercera a la quinta palabra de cada línea:

awk -v start=3 -v end=5 '{ for(i=start;i<=end;i++) printf "%s ", $i;print "" }' nombredearchivo

Muestra hasta la octava palabra en cada línea:

awk '{ i=0; while(++i<8) printf("%s ", $i); print $i }' nombredearchivo

Convierte a espacios todos los saltos de línea en un archivo:

awk '{ printf "%s ", $O }' nombredearchivo

Muestra todo el archivo como un vector:

awk '{delete a;}{for(i=1;i<=NF;++i) a[i]=$i} { for (j in a) printf("%s ",a[j]); print ""}' nombredearchivo

¿Cómo encontrar el mayor número que mi awk puede manejar con precisión?

Desde MayorNumeroPreciso-español,editar:

La mayoría de las implementaciones usan números de coma flotante de alta precisión conocidos como "double" para representar cualquier valor numérico. Sin embargo esto podría preocuparnos cuando intentamos sumar grandes números en archivos de logs muy grandes: ¿Cuándo podémos confiar en los números de awk y cuándo deberíamos usar dc o bc para tener precisión arbitraria?

La forma más fácil para investigar la pérdida de precisión es encontrar cuando un número N deja de ser distinto de N+1:

awk 'BEGIN{for (i = 0; i < 64; i++) printf "%s\t%19.0f\t%s\n", i, 2^i, (((2^i+1) == (2^i))? "no " : "") "preciso"}'

Esto mostrará una lista de números. Por ejemplo, el mayor número confiable que este proceso encuentra al correr en mi computadora con gawk 3.1.5 bajo linux en i386 es 2^52, esto se debe a que el tamaño en bits de la mantisa en los números de coma flotantes de doble precisión del IEEE 754 es también 52.


¿Por qué «print $variable» no muestra nada? ¿por qué «print "hola $nombre"» no funciona?

Desde variable-español, editar:

AWK no es el shell, y tampoco es Perl.

Antes que nada, las variables en AWK se referencian utilizando solamente el nombre, no se coloca $ en frente a las palabras para referirse a estas como una variable - si deseas acceder a una variable llamada «nombre», simplemente te deberás referir a ésta como «nombre» (al igual que en C)

awk '{var="foo";print var}'

AWK es como C (no el shell), no expande las variables dentro de los strings literales. No podría aunque quisiera, dado que no hay forma para distinguir entre variables y palabras en una string literal. Por tanto "Hola nombre" es un string literal, más allá de si «nombre» es o no una variable en el script de AWK. Para formar nuevos strings desde strings literales y variables, es posible usar el operador de concatenación, el cual desafortunadamente resulta ser cualquier cantidad de espacios en blanco. Ejemplo:

# muestra la concatenación de un string y una variable
print "hola " nombre;

# concatena, asigna a «newstr» y lo muestra
newstr = "hola " nombre;
print newstr;

# print también reconoce la «,» como un operador "concatenar con
# separador", usando la variable ORS.
# Así que asumiendo que ORS es " ", lo siguiente es equivalente al
# ejemplo previo:
print "hola", nombre;

Bien, ¿entonces, para qué sirve el $?

Desde ReferenciarCampos-español, editar:

En AWK, $ es el operador para "referenciar campos". Justamente referencia el campo del registro de entrada actual dado por la expresión. Ejemplo, si se desea mostrar el primer campo, las siguientes son equivalentes:

# muestra el primer campo usando el operador '$' y una constante.
print $1;

# o con una expresión equivalente:
print $(2 * 0.5);

# idéntico pero con una variable en lugar de una constante:
i = 1;
print $i;

El poder de awk se encuentra en aprender a usar referencias a campos. Algunos ejemplos adicionales:

# muestra el valor de i y el campo i-ésimo.
print i, $i;

# muestra el campo i-ésimo, pero sólo si es distinto del string vacío:
if ($i != "")
  print $i;

¿Qué es un PasteBin?

Desde PasteBin-español, editar:

Un PasteBin es un sitio que permite a los usuarios del mismo, pegar tramos de código o texto. Cada tramo recibe por tanto una URL única que podría o no ser permanente; algunos sitios también avisan a los canales de IRC por medio de uno o más bots.

Pegar más que unas pocas líneas de texto, en un canal de IRC, resulta muchas veces molesto. El usar PasteBin no solo permite evitar esto, sino que también simplifica el control de versiones, y permite reconstruir casos de prueba con código para copiar y pegar, sin tener que andar sacando los textos extraños que agregan los clientes de IRC.

es mantenido por [[tag?]], un usuario frecuente de #awk, y se caracteríza por permitir remarcado de sintaxis específico para awk. Normalmente, awkbot debería mandar al canal, un enlace al texto.

Sin embargo, hay una larga ListaDePasteBins? entre los cuales elegir.