O awk responde de maneira diferente com base em como um argumento vazio é especificado

2

Parece que eu tropecei em algo que provavelmente é um bug no awk, mas também pode ser um erro 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 obtinha 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:

Como se viu awk estava sendo passado um primeiro argumento vazio, seguido por -f awkfilename.awk . Então o erro pode ser reproduzido pela seguinte linha de comando:

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

Mas se eu rodar o awk sem nenhum argumento (que é o que eu consideraria acima como sendo o equivalente a), 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 "Original Exception was:" está vazia, não é algo que eu ignorei.

Detalhes sobre o 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 alguma visão. É claro que a solução imediata é higienizar o argumento que é passado como vazio para o awk que eu fiz, mas isso me deixou curioso sobre a causa.

Edições

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

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

Por exemplo o seguinte funciona bem

$ echo "" > /tmp/empty.awk
$ python -c 'print "hello"' | awk -f /tmp/empty.awk
$ echo $?
$ 0
    
por Puneet 04.02.2012 / 03:16

2 respostas

1

Existem duas coisas separadas acontecendo aqui: as mensagens de erro (que são realmente de python, não awk) e a mensagem de uso do awk. Para isolá-los, apenas redirecione 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 ...]

O AIUI python está recebendo um erro porque o programa está sendo canalizado para saídas (e encerra o canal) antes de ser gravado pelo Python. Aqui está um exemplo usando sleep 0 como um 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 há erro porque a suspensão não fecha a extremidade do canal até que o Python tenha terminado de gravar nele. Seus resultados podem ser diferentes, dependendo dos horários exatos envolvidos.

Agora, para o erro awk . A diferença é que awk sem um argumento não é válido porque você deve fornecer um programa; desde que você o executou indevidamente, ele tenta ser útil imprimindo uma mensagem de uso para lhe dizer como ela deve ser executada. Por outro lado, awk '' está realmente dizendo ao awk para executar um script vazio (''), que é perfeitamente válido (embora não seja muito útil), portanto nenhuma mensagem de uso é impressa:

$ awk
usage: awk [-F fs] [-v var=value] [-f progfile | 'prog'] [file ...]
$ awk ''
    
por 04.02.2012 / 06:19
2

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

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
}

A execução deste programa como example imprimirá 1 - porque o nome do programa é sempre passado automaticamente e não há nenhum argumento adicional. Executar o programa como example '' ou example SomethingGoesHere imprimirá 2 , porque existe o nome do programa e um parâmetro em branco ou SomethingGoesHere .

Como o awk espera pelo menos 2 parâmetros (seu nome e outra coisa), chamar o awk por si mesmo 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 requeresse 3 argumentos, mas você quisesse que o segundo ficasse em branco, você não poderia simplesmente omiti-lo - o shell não saberia que havia um argumento que foi omitido então passaria os 2 argumentos ao longo para o programa, e o programa teria um erro.

    
por 04.02.2012 / 05:57

Tags