chamada de sistema awk com efeito invertido

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.

Comentários

  • Bem, meu problema foi mais para entender o comportamento ” estranho ” da condição 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 parte n = blocks[block]++; file=block (n? "_" n: "") com mais detalhes?
  • O algoritmo usa uma matriz: 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 awk n = var++ é equivalente a {n=var;var++}, então n=="" e blocks["blockname1"]==1.Finalmente, file=block (n? "_" n: "") é o mesmo que {file=block;if(n!="") file+="_" n}.
  • Eu não era ‘ div Mesmo sabendo que uma string é uma variável de indexação válida e esta instrução if reduzida – muito útil, obrigado novamente. Eu ‘ estou triste, não posso dar a você a ” resposta aceita ” aqui: apesar de mim vou adotar essa abordagem, uma vez que cumpre minha tarefa inicial, não ‘ responder à pergunta acima (interpretação da condição no loop while) – isso iria contra meu entendimento desses sites Q & Um sistema. Mesmo assim, aprendi muito – obrigado novamente.

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *