2 votes

Awk réagit différemment selon la façon dont un argument vide est spécifié

Il semble que je sois tombé sur quelque chose qui est probablement un bogue dans awk, mais qui pourrait aussi être un bogue dans ma compréhension de bash/awk.

J'essayais de déboguer des problèmes où la sortie d'un programme Python était envoyée à awk et j'obtenais l'exception suivante indépendamment de ce que faisait la commande awk.

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

Original exception was:

Il s'avère que l'awk reçoit un premier argument vide, suivi de -f awkfilename.awk . L'erreur peut donc être reproduite par la ligne de commande suivante :

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

Mais si j'exécute awk sans aucun argument (ce que je considérerais comme l'équivalent de ce qui précède), j'obtiens l'aide d'awk suivie de la même exception

 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:

Note : le message après "Original Exception was :" est en fait vide, ce n'est pas quelque chose que j'ai ignoré.

Détails sur mon système

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

Je serais heureux si quelqu'un pouvait m'éclairer. Bien sûr, la solution immédiate est de nettoyer l'argument qui est passé comme vide à awk, ce que j'ai fait, mais cela m'a rendu curieux sur la cause.

Edits

D'après les commentaires ci-dessous, je comprends que awk y awk '' sont différentes dans le sens où la seconde invocation signifie que l'awk voit le nombre d'arguments comme étant 1 (avec l'argument étant une chaîne vide) au lieu de 0.

Ce que je ne comprends toujours pas, c'est ce que fait la chaîne vide en tant qu'expression awk.

Par exemple, ce qui suit fonctionne bien

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

2voto

taneli Points 2589

L'appel d'un programme avec zéro argument (ou paramètre) est différent de l'appel d'un programme avec un argument (ou paramètre) vide.

Pour utiliser un code C à titre d'exemple :

#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
}

En exécutant ce programme en tant que example imprimera 1 - car le nom du programme est toujours transmis automatiquement et il n'y a aucun argument supplémentaire. L'exécution du programme en tant que example '' o example SomethingGoesHere imprimera 2 parce qu'il y a le nom du programme et soit un paramètre vide ou SomethingGoesHere .

Comme awk attend au moins 2 paramètres (son nom et quelque chose d'autre), appeler awk par lui-même sans aucun argument résulte en ce que vous voyez ci-dessus - l'aide étant imprimée.

C'est pour cette raison que vous êtes capable d'aligner les arguments correctement. Si vous aviez un programme qui nécessitait toujours 3 arguments, mais que vous vouliez que le deuxième soit vide, vous ne pourriez pas simplement l'omettre - le Shell ne saurait pas qu'il y a un argument qui a été omis, donc il transmettrait les 2 arguments au programme, et le programme aurait une erreur.

1voto

rwc9u Points 532

Il y a deux choses distinctes qui se passent ici : les messages d'erreur (qui proviennent en fait de Python, pas d'awk), et le message d'utilisation d'awk. Pour les isoler, il suffit de rediriger stderr des deux commandes :

$ 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 obtient une erreur parce que le programme vers lequel sa sortie est acheminée quitte (et ferme le tuyau) avant que Python n'y écrive. Voici un exemple utilisant sleep 0 comme un programme qui ne fait rien du tout, et qui se termine donc très rapidement :

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

Original exception was:

Mais si j'utilise sleep 1 il n'y a pas d'erreur car sleep ne ferme pas son extrémité du tube avant que Python ait fini d'y écrire. Vos résultats peuvent différer, en fonction des délais exacts.

Maintenant, pour le awk erreur. La différence est que awk sans argument n'est pas valable parce que vous doit fournit un programme ; comme vous l'avez exécuté de manière incorrecte, il essaie de vous aider en imprimant un message d'utilisation pour vous dire comment il doit être exécuté. D'un autre côté, awk '' dit en fait à awk d'exécuter un script vide (''), ce qui est parfaitement valide (bien que pas terriblement utile), donc aucun message d'utilisation n'est imprimé :

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

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X