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 awk
e 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 0
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 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 awk
erro. A diferença é que awk
sem 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 example
será impresso 1
- porque o nome do programa é sempre passado automaticamente e não há argumentos adicionais. Executar o programa como example ''
ou example SomethingGoesHere
imprimirá 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.