Qual system()
do awk deve retornar está mal especificado .
O que parece ser comum entre awk
implementações é que, após uma saída normal, ele retorna o código de saída (o número passou para exit(3)
módulo 256), mas quando o processo shell é morto por um sinal, há um muito comportamento diferente.
Observe também que, embora a função C system(3)
deva ignorar SIGINT (e SIGQUIT) no pai, não está muito claro (pelo menos para mim) que o requisito também se aplica a awk
' system()
. Algumas awk
implementações (como mawk
) morrerão naquele SIGINT (esse também é o comportamento que eu gostaria de ver, pois não gosto de meu CTRL-C ser ignorado apenas porque awk
está rodando o system()
function), algumas (como gawk
ou implementações tradicionais) não.
Observe também que alguns shells podem interceptar alguns desses sinais e eventualmente chamar exit()
, o que afetaria o comportamento (veja a discussão em comentários sobre o shell Bourne, por exemplo), é por isso que uso exec
nos exemplos abaixo para remover o shell do loop.
Para o valor retornado por system()
(há ainda mais variação se você considerar close()
1 ) em um SIGINT, vemos:
$ nawk 'BEGIN {print system("exec kill -s INT $$")}'
0.0078125
$ bwk-awk 'BEGIN {print system("exec kill -s INT $$")}'
0.0078125
$ mawk 'BEGIN {print system("exec kill -s INT $$")}'
130
$ gawk 'BEGIN {print system("exec kill -s INT $$")}'
0
0.0078125
sendo 2 / 256
(para SEGV
de 11
, você obteria 0,542969 ((128 + 11) / 256) se um núcleo fosse descartado, 0,0429688 (11/256) caso contrário), nawk
sendo o nawk
encontrado no Solaris 10 ou 11, ou sua porta Linux no toolchest da Heirloom, bwk-awk
sendo o awk
mantido pelo próprio Brian Kernighan (o K
em awk
) a base para o awk
encontrado em alguns BSDs (aqui testados no Debian GNU / Linux). /usr/xpg4/bin/awk
no Solaris 11 se comporta como gawk
.
Portanto, com base no valor s
retornado por system(3)
(um inteiro onde os bits 0 a 6 são o número do sinal, o bit 7 o core-bit e os bits 8 a 15 o código de saída), awk
' s system()
acima retorna:
-
s / 256
(tradicionalawk
implementations), -
int(s/256)
(gawk
), - ou em
mawk
, a mesma transformação feita por shells como Bourne ou C-shell, por exemplo ((s&127)+128
se morto,s>>8
caso contrário), exceto que se um núcleo for descartado, você obtém(s&127)+256
em vez de(s&127)+128
(o valor é(s&255)+128
).
Então, aqui, você poderia fazer:
awk 'BEGIN{print system("trap exit\ 1 INT; sleep 10")}'
Mas isso ainda faria com que awk
fosse eliminado com algumas implementações awk
, como mawk
. Se o seu sh
for bash
ou yash
, você poderá fazer:
awk 'BEGIN{print system("set -m; sleep 10; exit")}'
Portanto, sleep
é executado em seu próprio grupo de processos (e apenas obtém o SIGINT).
Outra alternativa poderia ser ignorar o SIGINT antes de chamar awk
. No entanto, a maioria das shells (e isso é um requisito POSIX) não pode mudar um manipulador de sinal se o sinal já foi ignorado no início. Então coisas como:
(
trap '' INT
awk 'BEGIN{print system("trap exit\ 1 INT; sleep 10; exit")}'
)
não vai funcionar. zsh
não tem essa limitação (auto-infligida), então se você sabe que zsh
está disponível, você poderia fazer:
(
trap '' INT
awk 'BEGIN{print system("exec zsh -c \"TRAPINT() exit 1; sleep 10\"")}'
)
O que funcionaria se awk
fosse mawk
, gawk
ou outro e evitaria ter que mexer no controle do trabalho. Neste ponto, vale a pena considerar usar perl
/ python
/ ruby
... em vez de awk
, onde você pode adaptar o tratamento de sinais às suas necessidades.
Notas
1 Sobre close()
de um pipeline, como em:
awk 'BEGIN {cmd = "kill -s INT $$"; cmd | getline; print close(cmd)}'
Primeiro, desta vez ^C
interrompe awk
em todas as implementações que eu tentei (não existe esse requisito para ignorar o SIGINT / SIGQUIT para popen(3)
/ pclose(3)
(uma maneira natural de implementar esse getline
) como existe para system(3)
).
Mas, quando se trata do status de saída (em que s
é o valor retornado por pclose(3)
/ waitpid(2)
, como para system()
acima), vemos:
- O Solaris
nawk
: não funciona, você não pode chamarclose()
assim no Solarisnawk
. -
/usr/xpg4/bin/awk
no Solaris. Retorna sempre 0, mesmo após umexit(1)
feito pelo processo. Claramente um bug de conformidade. -
gawk
ebwk-awk
: dás
(exit 1
fornece 256, morto por SIGINT, 2, morto por um SIGSEGV de 11 com núcleo, dá 139). -
mawk
: o mesmo que parasystem()
, parece quemawk
é a única implementação que pensou nisso.