Awk responde de manera diferente según cómo se especifica un argumento vacío

Awk responde de manera diferente según cómo se especifica un argumento vacío

Parece que me he topado con algo que probablemente sea un error en awk, pero también podría ser un error en mi comprensión de bash/awk.

Estaba intentando depurar problemas en los que la salida de un programa Python se canalizaba a awk y obtenía la siguiente excepción independientemente de lo que estuviera haciendo el comando awk.

close failed in file object destructor:
Error in sys.excepthook:

Original exception was:

Resulta que a awk se le pasó un primer argumento vacío, seguido de -f awkfilename.awk. Entonces el error se puede reproducir mediante la siguiente línea de comando:

python -c 'print "hello"'  | awk '' 

Pero si ejecuto awk sin ningún argumento (que es lo que consideraría equivalente a lo anterior), obtengo la ayuda de awk seguida de la misma excepción.

 python -c 'print "hh"'  | awk 

Usage: awk [POSIX or GNU style options] -f progfile [--] file ...
Usage: awk [POSIX or GNU style options] [--] 'program' file ...
POSIX options:      GNU long options:
    -f progfile     --file=progfile
    -F fs           --field-separator=fs
    -v var=val      --assign=var=val
    -m[fr] val
    -W compat       --compat
    -W copyleft     --copyleft
    -W copyright        --copyright
    -W dump-variables[=file]    --dump-variables[=file]
    -W exec=file        --exec=file
    -W gen-po       --gen-po
    -W help         --help
    -W lint[=fatal]     --lint[=fatal]
    -W lint-old     --lint-old
    -W non-decimal-data --non-decimal-data
    -W profile[=file]   --profile[=file]
    -W posix        --posix
    -W re-interval      --re-interval
    -W source=program-text  --source=program-text
    -W traditional      --traditional
    -W usage        --usage
    -W use-lc-numeric   --use-lc-numeric
    -W version      --version

To report bugs, see node `Bugs' in `gawk.info', which is
section `Reporting Problems and Bugs' in the printed version.

gawk is a pattern scanning and processing language.
By default it reads standard input and writes standard output.

Examples:
    gawk '{ sum += $1 }; END { print sum }' file
    gawk -F: '{ print $1 }' /etc/passwd
close failed in file object destructor:
Error in sys.excepthook:

Original exception was:

Nota:el mensaje después de "La excepción original fue:" en realidad está vacío, no es algo que me haya saltado.

Detalles sobre mi sistema

Python 2.6.5 (r265:79063, Apr 16 2010, 13:57:41) 
[GCC 4.4.3] on linux2

$ awk --version
GNU Awk 3.1.6

$ cat /etc/lsb-release 
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=10.04
DISTRIB_CODENAME=lucid
DISTRIB_DESCRIPTION="Ubuntu 10.04.3 LTS

$ uname -a
Linux <hostname> 2.6.32-37-generic #81-Ubuntu SMP Fri Dec 2 20:32:42 UTC 2011 x86_64     GNU/Linux

Me encantaría que alguien pudiera ofrecerme alguna idea. Por supuesto, la solución inmediata es desinfectar el argumento que se pasa como vacío a awk, lo cual hice, pero esto me hizo sentir curiosidad por la causa.

Ediciones

Según los comentarios a continuación, lo entiendo awky awk ''soy diferente en que la segunda invocación significa que awk ve que el número de argumentos es 1 (con el argumento como una cadena vacía) en lugar de 0.

Lo que todavía no entiendo es qué hace la cadena vacía como lo hace la expresión awk.

Por ejemplo, lo siguiente funciona bien

$ echo "" > /tmp/empty.awk
$ python -c 'print "hello"' | awk -f /tmp/empty.awk
$ echo $?
$ 0

Respuesta1

Aquí suceden dos cosas distintas: los mensajes de error (que en realidad son de Python, no de awk) y el mensaje de uso de awk. Para aislarlos, simplemente redirige stderr desde ambos comandos:

$ python -c 'print "hello"' 2>pyerr | awk 2>awkerr
$ cat pyerr 
close failed in file object destructor:
Error in sys.excepthook:

Original exception was:
$ cat awkerr 
usage: awk [-F fs] [-v var=value] [-f progfile | 'prog'] [file ...]

AIUI Python recibe un error porque el programa al que se canaliza su salida sale (y cierra la tubería) antes de que Python escriba en él. Aquí hay un ejemplo que utiliza sleep 0un programa que no hace nada en absoluto y, por lo tanto, sale muy rápido:

$ python -c 'print "hello"' | sleep 0
close failed in file object destructor:
Error in sys.excepthook:

Original exception was:

Pero si uso sleep 1, no hay ningún error porque el modo de suspensión no cierra el extremo de la tubería hasta que Python haya terminado de escribir en él. Sus resultados pueden diferir, dependiendo de los tiempos exactos involucrados.

Ahora, por el awkerror. La diferencia es que awksin un argumento no es válido porquedebesuministrar un programa; Como lo ejecutó incorrectamente, intenta ser útil imprimiendo un mensaje de uso para indicarle cómo debe ejecutarse. Por otro lado, awk ''en realidad le está diciendo a awk que ejecute un script vacío (''), que es perfectamente válido (aunque no muy útil), por lo que no se imprime ningún mensaje de uso:

$ awk
usage: awk [-F fs] [-v var=value] [-f progfile | 'prog'] [file ...]
$ awk ''

Respuesta2

Llamar a un programa con cero argumentos (o parámetros) es diferente a llamar a un programa con un argumento (o parámetro) vacío.

Para usar algo de código C como ejemplo:

#include <stdio.h>
int main(int argc, char** argv)
{
    printf("%d\n", argc); // print the number of arguments we've received
    return 0; // exit successfully
}

Ejecute este programa como examplese imprimirá 1, porque el nombre del programa siempre se pasa automáticamente y no hay argumentos adicionales. Al ejecutar el programa como example ''o example SomethingGoesHerese imprimirá 2, porque está el nombre del programa y un parámetro en blanco o SomethingGoesHere.

Como awk espera al menos 2 parámetros (su nombre y algo más), llamar a awk por sí solo sin ningún argumento da como resultado lo que ve arriba: se imprime la ayuda.

Es por esta razón que puedes alinear los argumentos correctamente. Si tuviera un programa que siempre requiriera 3 argumentos, pero quisiera que el segundo estuviera en blanco, no podría simplemente omitirlo: el shell no sabría que hay un argumento que se omitió, por lo que pasaría los 2 argumentos. al programa, y ​​el programa tendría un error.

información relacionada