Awk responde de forma diferente com base em como um argumento vazio é especificado

Awk responde de forma diferente com base em como um argumento vazio é especificado

Parece que tropecei em algo que provavelmente é um bug no awk, mas também pode ser um bug no meu entendimento do bash/awk.

Eu estava tentando depurar problemas em que a saída de um programa python estava sendo canalizada para o awk e recebia a seguinte exceção, independentemente do que o comando awk estava fazendo.

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

Original exception was:

Acontece que o awk estava recebendo um primeiro argumento vazio, seguido por -f awkfilename.awk. Portanto, o erro pode ser reproduzido pela seguinte linha de comando:

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

Mas se eu executar o awk sem nenhum argumento (que é o que eu consideraria acima equivalente), recebo a ajuda do awk seguida pela mesma exceção

 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:

Observação:a mensagem após "A exceção original foi:" está realmente vazia, não é algo que eu pulei.

Detalhes sobre meu 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

Eu ficaria feliz se alguém pudesse oferecer algumas dicas. Claro, a solução imediata é higienizar o argumento que é passado como vazio para awk, o que fiz, mas isso me deixou curioso sobre a causa.

Editar% s

Com base nos comentários abaixo, entendo isso awke awk ''sou diferente porque a segunda invocação significa que o awk vê o número de argumentos como 1 (com o argumento sendo uma string vazia) em vez de 0.

O que ainda não entendo é o que faz a string vazia como a expressão awk.

Por exemplo, o seguinte funciona bem

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

Responder1

Há duas coisas distintas acontecendo aqui: as mensagens de erro (que na verdade são do python, não do awk) e a mensagem de uso do awk. Para isolá-los, basta redirecionar o stderr de ambos os 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 está recebendo um erro porque a saída do programa está sendo canalizada para sair (e fechar o canal) antes que o python grave nele. Aqui está um exemplo usando sleep 0um programa que não faz nada e, portanto, sai muito rápido:

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

Original exception was:

Mas se eu usar sleep 1, não haverá erro porque sleep não fecha o final do tubo até que o python termine de escrever nele. Seus resultados podem ser diferentes, dependendo dos tempos exatos envolvidos.

Agora, para o awkerro. A diferença é que awksem argumento não é válido porque vocêdevefornecer um programa; como você o executou incorretamente, ele tenta ser útil imprimindo uma mensagem de uso para informar como ele deve ser executado. Por outro lado, awk ''está na verdade dizendo ao awk para executar um script vazio (''), que é perfeitamente válido (embora não muito útil), então nenhuma mensagem de uso é impressa:

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

Responder2

Chamar um programa com zero argumentos (ou parâmetros) é diferente de chamar um programa com um argumento (ou parâmetro) vazio.

Para usar algum código C como exemplo:

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

Executar este programa como exampleserá impresso 1- porque o nome do programa é sempre passado automaticamente e não há argumentos adicionais. Executar o programa como example ''ou example SomethingGoesHereimprimirá 2, porque há o nome do programa e um parâmetro em branco ou SomethingGoesHere.

Como o awk espera pelo menos 2 parâmetros (seu nome e mais alguma coisa), chamar o awk sozinho sem nenhum argumento resulta no que você vê acima - a ajuda sendo impressa.

É por esse motivo que você consegue alinhar os argumentos corretamente. Se você tivesse um programa que sempre exigisse 3 argumentos, mas quisesse que o segundo ficasse em branco, não poderia simplesmente omiti-lo - o shell não saberia que havia um argumento omitido, então passaria os 2 argumentos adiante ao programa, e o programa apresentaria um erro.

informação relacionada