Eu tenho um arquivo de dados com vários blocos de dados entre palavras-chave específicas (DATA
, END
). Estou usando awk
para extrair os blocos de dados em arquivos separados, com base em um nome de arquivo obtido do referido bloco. Como alguns blocos de dados compartilham o mesmo nome, estou renomeando cada arquivo de saída com um número inteiro crescente se o arquivo (“blockname
“) já existir:
#cat input.file useless stuff1 DATA blockname1 data1 data1 END useless stuff2 DATA blockname2 data2 data2 END useless stuff3 DATA blockname1 data3 data3 END useless stuff4
Esperados seriam três arquivos de saída blockname1
, blockname2
e blockname1_1
(observe como o último arquivo possui um número inteiro atribuído a ele)
#cat blockname1 DATA blockname1 data1 data1 END
(os outros de acordo …)
Agora, o seguinte script funciona como eu desejo:
awk "BEGIN { FS=" +" } ; \ /DATA/,/END/ \ { if ( $1 ~ /DATA/ ) \ { block=$2 ; i=0 ; file=block ;\ while ( system("test ! -e " file ) ) \ { i++ ; file=block"_"i ; print file } \ } ; \ print $0 > file \ } " \ input.file
Meu problema está no loop while
e sua chamada de sistema:
Eu esperava que system("test -e " file)
fosse VERDADEIRO quando file
existisse e fosse FALSO se file
ainda não existe, ou seja, o while
loop só começará a ser executado se file
estiver presente e para quebrar se (o novo) file
ainda não existir.
No entanto, se eu usar system("test -e " file)
(e torná-lo detalhado com print file
), eu tenho um loop infinito do mesmo nome com sufixo inteiro crescente e o oposto system("test !-e " file)
fornece o resultado desejado.
Portanto, isso se comporta exatamente de forma inversa ao que eu esperava.
Resposta
OK, concluí: o problema está nas diferentes definições do que é VERDADEIRO e FALSO entre o status de saída de test
e while
condição de loop em awk
.
Um comando test
positivo resulta em um código de saída de 0
para TRUE e um negativo em 1
para FALSE.
No entanto, em awk
o loop while
interpreta 0
como FALSO e 1
como VERDADEIRO, então exatamente o oposto definição.
Por exemplo:
awk "{ while ( 0 ) ; { print "0" } }" file
não será profissional duce qualquer saída, enquanto
awk "{ while (1) ; { print "1" } }" file
imprimirá 1
s infinitos.
Prática recomendada deve, portanto, ser explícito em tal combinação
while ( system("command") == 0 )
ou
while ( system("command") == 1 )
respectivamente.
Portanto, no meu caso
while ( system("test -e " file ) == 0 )
mostra o comportamento esperado.
Resposta
awk
system()
retorna um status de saída do comando executado – 0 para sucesso e! = 0 se não for sucesso. Por exemplo, você pode tentar executar:
v = system("date");
v será 0
se você executar:
v = system("dat");
v pode ser 127 ou um valor diferente de 0, o erro retornado do sistema operacional se o comando dat estiver ausente ou não for encontrado.
Resposta
Se bem entendi, o objetivo é extrair o conteúdo de input.file em vários arquivos evitando perder blocos com o mesmo nome.
Se esse for o caso, e, se o diretório de destino estiver sempre vazio antes da extração, então há uma solução melhor (e mais rápida):
awk " /DATA/{ block=$2; n = blocks[block]++; file=block (n? "_" n: ""); } /DATA/,/END/{ print > file }" input.file
Desta forma, o awk não “Não é necessário executar um novo shell N vezes apenas para testar se o arquivo existe.
Observações:
- Não há necessidade do bloco BEGIN, porque o separador de campo do awk já tem espaços.
- Não há “necessidade do
"\"
no final das linhas, porque a aspa simples já é multilinha.
while
. No entanto, sua solução é bem legal – obrigado, eu prefiro isso em vez da minha coisa volumosa. O bloco BEGIN é uma sobra de meu formato de arquivo diferente – esqueci que se tornou inútil em meu exemplo genérico. Deixar de fora a barra invertida me poupará alguns problemas. Obrigado por isso também. Mas você acertou em cheio a respeito da intenção ‘ do script. Você poderia explicar a parten = blocks[block]++; file=block (n? "_" n: "")
com mais detalhes?blocks
que é indexada por nome de bloco. Ex. Na primeira instância de"blockname1"
:blocks["blockname1"]
. Awk encontre esse índice e porque ele é ‘ t encontrado assume""
(também considerado zero). Agora, em awkn = var++
é equivalente a{n=var;var++}
, entãon==""
eblocks["blockname1"]==1
.Finalmente,file=block (n? "_" n: "")
é o mesmo que{file=block;if(n!="") file+="_" n}
.