awk repete linhas muitas vezes

2

Estou usando o awk para criar um arquivo que contenha linhas de texto & amp; usa um arquivo de entrada de números. Eu quero substituir cada número uma vez, ou seja, a linha 1 recebe o primeiro número, a linha 2 recebe o segundo número, a linha 3 recebe o terceiro número. No entanto, a cada linha é atribuído o primeiro número, seguido por cada linha atribuída ao segundo número, etc ...

Aqui está o meu arquivo de entrada de texto (test.awk):

{printf("\n( == \"cs.cpool\") && (h==1) {printf(\"%%f %%s\n\",=="",); a=1;}"); 
printf("\n( == \"cs.leafc\") && (h==1) {printf(\"%%f %%s\n\",=="",); a=1;}"); 
printf("\n( == \"cs.dead_leafc\") && (h==1) {printf(\"%%f %%s\n\",=="",); a=1; h=0;}"); 
}

este é o arquivo de entrada de números:

-0.00432739
0.41369093
0.00000000
Comando

: awk -f test.awk < input.txt > new.txt

produz isto onde as 3 linhas são repetidas 3 vezes:

( == "cs.cpool") && (h==1) {printf("%f %s\n",==-0.00432739,); a=1;}
( == "cs.leafc") && (h==1) {printf("%f %s\n",==-0.00432739,); a=1;}
( == "cs.dead_leafc") && (h==1) {printf("%f %s\n",==-0.00432739,); a=1; h=0;}

( == "cs.cpool") && (h==1) {printf("%f %s\n",==0.41369093,); a=1;}
( == "cs.leafc") && (h==1) {printf("%f %s\n",==0.41369093,); a=1;}
( == "cs.dead_leafc") && (h==1) {printf("%f %s\n",==0.41369093,); a=1; h=0;}

( == "cs.cpool") && (h==1) {printf("%f %s\n",==0.00000000,); a=1;}
( == "cs.leafc") && (h==1) {printf("%f %s\n",==0.00000000,); a=1;}
( == "cs.dead_leafc") && (h==1) {printf("%f %s\n",==0.00000000,); a=1; h=0;}

o que eu quero é isso:

( == "cs.cpool") && (h==1) {printf("%f %s\n",==-0.00432739,); a=1;}
( == "cs.leafc") && (h==1) {printf("%f %s\n",==0.41369093,); a=1;}
( == "cs.dead_leafc") && (h==1) {printf("%f %s\n",==0.00000000,); a=1; h=0;}

Alguém pode me dizer como impedi-lo de atribuir cada número a cada linha e depois repetir as 3 linhas?

    
por janet 01.09.2015 / 09:26

4 respostas

2

Usando o módulo 3 ( % ) e uma pequena correção em printf(\"%%f %%s\n\",=="",)

{
  if (NR%3==1) {printf("\n( == \"cs.cpool\") && (h==1) {printf(\"%%f %%s\n\",=="",); a=1;}")};
  if (NR%3==2) {printf("\n( == \"cs.leafc\") && (h==1) {printf(\"%%f %%s\n\",=="",); a=1;}")};
  if (NR%3==0) {printf("\n( == \"cs.dead_leafc\") && (h==1) {printf(\"%%f %%s\n\",=="",); a=1; h=0;}")}
}

O módulo também é uma boa ideia, se você tiver mais de três linhas no seu input.txt . O número 3 no código acima depende das printf linhas em test.awk . Com quatro printf linhas, você precisa de algo assim:

{
  if (NR%4==1) {printf("\n( == \"cs.cpool\") && (h==1) {printf(\"%%f %%s\n\",=="",); a=1;}")};
  if (NR%4==2) {printf("\n( == \"cs.leafc\") && (h==1) {printf(\"%%f %%s\n\",=="",); a=1;}")};
  if (NR%4==3) {printf("\n( == \"cs.dead_leafc\") && (h==1) {printf(\"%%f %%s\n\",=="",); a=1; h=0;}")};
  if (NR%4==0) {printf("\n( == \"foo.bar\") && (h==1) {printf(\"%%f %%s\n\",=="",); a=1; h=0;}")}
}

Saída com três linhas em input.txt :

% awk -f test.awk input.txt

( == "cs.cpool") && (h==1) {printf("%f %s\n",==-0.00432739,); a=1;}
( == "cs.leafc") && (h==1) {printf("%f %s\n",==0.41369093,); a=1;}
( == "cs.dead_leafc") && (h==1) {printf("%f %s\n",==0.00000000,); a=1; h=0;}

Saída com mais de três linhas em input.txt

% awk -f test.awk input.txt

( == "cs.cpool") && (h==1) {printf("%f %s\n",==-0.00432739,); a=1;}
( == "cs.leafc") && (h==1) {printf("%f %s\n",==0.41369093,); a=1;}
( == "cs.dead_leafc") && (h==1) {printf("%f %s\n",==0.00000000,); a=1; h=0;}
( == "cs.cpool") && (h==1) {printf("%f %s\n",==-0.00432739,); a=1;}
( == "cs.leafc") && (h==1) {printf("%f %s\n",==0.41369093,); a=1;}
( == "cs.dead_leafc") && (h==1) {printf("%f %s\n",==0.00000000,); a=1; h=0;}
    
por A.B. 01.09.2015 / 10:25
1

Você pode usar o seguinte código awk (test.awk):

BEGIN{count=0}{count++}{if(count==1){printf("\n( == \"cs.cpool\") && (h==1) {printf(\"%%f %%s\n\",=="",); a=1;}");
printf("\n( == \"cs.leafc\") && (h==1) {printf(\"%%f %%s\n\",=="",); a=1;}");
printf("\n( == \"cs.dead_leafc\") && (h==1) {printf(\"%%f %%s\n\",=="",); a=1; h=0;}"); }}
    
por snoop 01.09.2015 / 10:06
1

Gostaria de salvar os números em uma matriz e usá-los. Primeiro, modifique seu test.awk para que fique assim:

( == \"cs.cpool\") && (h==1) {printf(\"%%f %%s\n\",=="",); a=1;} 
( == \"cs.leafc\") && (h==1) {printf(\"%%f %%s\n\",=="",); a=1;} 
( == \"cs.dead_leafc\") && (h==1) {printf(\"%%f %%s\n\",=="",); a=1; h=0;} 

Você pode fazer isso automaticamente com este comando:

sed -i 's/^{//;s/}$//;s/printf("\n//;s/");//' test.awk 

Uma vez feito isso, você pode usar este script para obter sua saída:

$ awk 'NR==FNR{a[NR]=; next}{gsub(/"$1"/,a[FNR]); print}' input.txt test.awk 
( == \"cs.cpool\") && (h==1) {printf(\"%%f %%s\n\",==-0.00432739,); a=1;} 
( == \"cs.leafc\") && (h==1) {printf(\"%%f %%s\n\",==0.41369093,); a=1;} 
( == \"cs.dead_leafc\") && (h==1) {printf(\"%%f %%s\n\",==0.00000000,); a=1; h=0;} 

Explicação

NR é o número da linha atual e FNR é o número da linha atual do arquivo atual . Então, os dois são iguais apenas quando o primeiro arquivo está sendo lido. Portanto, a primeira parte do script awk acima ( NR==FNR{a[NR]=; next} ) cria uma matriz cujas chaves são os números de linha do arquivo input.txt e cujos valores são os números correspondentes. Em seguida, ele executa next para passar para a próxima linha sem executar a segunda parte do script.

A segunda parte substituirá a string "" pelo valor armazenado na matriz a do número da linha atual do segundo arquivo ( FNR ). O resultado é o que você pediu.

Outra abordagem seria usar alguns truques. Em vez de usar um script para isso, use paste para unir os arquivos e awk para fazer a substituição. Primeiro modifique test.awk conforme descrito acima e, em seguida:

$ paste input.txt test.awk | awk '{gsub(/"$1"/,);="";print;}'
 ( == \"cs.cpool\") && (h==1) {printf(\"%%f %%s\n\",==-0.00432739,); a=1;}
 ( == \"cs.leafc\") && (h==1) {printf(\"%%f %%s\n\",==0.41369093,); a=1;}
 ( == \"cs.dead_leafc\") && (h==1) {printf(\"%%f %%s\n\",==0.00000000,); a=1; h=0;}

Explicação

O comando paste imprimirá cada linha de seus arquivos de entrada juntos. Então, com a entrada acima, será impresso:

$ paste input.txt test.awk
-0.00432739 ( == \"cs.cpool\") && (h==1) {printf(\"%%f %%s\n\",=="",); a=1;} 
0.41369093  ( == \"cs.leafc\") && (h==1) {printf(\"%%f %%s\n\",=="",); a=1;} 
0.00000000  ( == \"cs.dead_leafc\") && (h==1) {printf(\"%%f %%s\n\",=="",); a=1; h=0;} 

Isso é então passado por um script awk que

  • Usa gsub para substituir todas as ocorrências de "" pelo valor de ( gsub(/"$1"/,); );
  • Quando isso for feito, será definido como vazio ( ="" ) para que o número do primeiro arquivo não seja impresso no início da linha.
  • Finalmente, imprime a linha resultante ( print ).
por terdon 06.09.2015 / 15:32
0

Janet, você precisa deixar o awk saber que depois de aplicar a primeira linha de código na primeira linha de entrada, ela deve pular para a próxima linha de entrada. E então, que depois de aplicar a segunda linha de código, ela deve pular para a próxima linha de entrada e assim por diante. Caso contrário, o awk aplica cada linha de código em cada linha de entrada. A maneira mais fácil de fazer isso é inserir um comando getline após cada linha de código (exceto após o último, onde é inútil):

[alessandro@localhost ~]$ cat /tmp/a.awk
{printf("\n( == \"cs.cpool\") && (h==1) {printf(\"%%f %%s\n\",=="",); a=1;}"); 
getline
printf("\n( == \"cs.leafc\") && (h==1) {printf(\"%%f %%s\n\",=="",); a=1;}"); 
getline
printf("\n( == \"cs.dead_leafc\") && (h==1) {printf(\"%%f %%s\n\",=="",); a=1; h=0;}"); 
}
[alessandro@localhost ~]$ cat /tmp/a.txt
-0.00432739
0.41369093
0.00000000
[alessandro@localhost ~]$ awk -f /tmp/a.awk /tmp/a.txt
( == "cs.cpool") && (h==1) {printf("%f %s\n",==-0.00432739,); a=1;}
( == "cs.leafc") && (h==1) {printf("%f %s\n",==0.41369093,); a=1;}
( == "cs.dead_leafc") && (h==1) {printf("%f %s\n",==0.00000000,); a=1; h=0;}[alessandro@localhost ~]$ 
    
por Alessandro 06.09.2015 / 16:24