Defina uma variável para a correspondência de padrões do awk do bash

1

Eu estou tentando pegar 100 linhas após o texto "time: X" com X em {0,40,80, ..., 200}. Aqui está o que eu tenho até agora:

#!/bin/bash
start=1
end=5
for i in $(seq $start $end);do 
  j=$(($i*40))
  awk '/time: $j/{for(i=1;i<=100;i++}{getline;print}}' file > fileX-$j.txt
done 

No entanto, isso não parece funcionar. Minha pergunta especificamente é sobre a variável $ j e como eu preciso defini-la logo após '/ time: ...'

Por exemplo, eu tenho um arquivo chamado 'file':

time: 1
1 2 3 
1 33 1 
2 31 4
time: 40
2 1 3 
9 8 77
1 3 4

Eu gostaria de criar dois arquivos separados nesse caso; primeiro contendo

1 2 3 
1 33 1 
2 31 4

e o segundo com:

1 2 3 
1 33 1 
2 31 4

Eu tentei passar $ j como uma variável como mazs mencionou, mas ainda me dá arquivos vazios. Aqui está como eu fiz:

awk -v jj=$j '/time: jj/{for(i=1;i<3;i++){getline;print}}' file > fileX-$j.txt
    
por user164723 07.04.2016 / 15:22

2 respostas

0

Você tem que passar a variável shell $ j para awk:

awk -v jj="$j" '...'

Observe que isso pressupõe que o valor da variável não contenha barras invertidas, pois o argumento para awk -v é submetido à expansão de barra invertida.

    
por 07.04.2016 / 15:31
0

Existem dois problemas. A primeira é que o shell não expande $j dentro de aspas simples: '$j' informa ao shell que você deseja a string $j , não o valor da variável j .

Nesse caso, como o valor contém apenas dígitos, você pode colocá-lo fora das aspas simples:

awk '/time: '"$j"'/{for(i=1;i<=100;i++}{getline;print}}' file > fileX-"$j".txt

Observe que, se o valor de j continha caracteres especiais regexp ( . , * , etc.), esses caracteres seriam interpretados como tal. Por exemplo

j='2*3'
awk '/foo '"$j"' bar/'

o script imprime linhas contendo itens como foo 3 bar , foo 23 bar , foo 223 bar , etc. e não foo 2*3 bar . E se houvesse um / no valor, o awk veria o final da construção de correspondência de expressão regular; por exemplo

j='2/3'
awk '/foo '"$j"' bar/'

resultaria em awk reclamando que a sequência de tokens /foo 2/ , 3 , bar , / não está sintaticamente correta.

Você pode definir uma variável para um awk com a opção de linha de comando -v :

j='a\tb'
awk -v j="$j" '{print j}'

Observe que isso realiza uma expansão de barra invertida no valor de j . Por exemplo, o snippet acima substitui cada linha por a↦b , em que é um caractere de tabulação.

Mas isso não funciona diretamente no seu caso, porque o awk não expande variáveis dentro de /…/ : /foo/ corresponde à string foo , não o valor da variável foo . Para usar uma variável em uma correspondência de expressão regular, você precisaria usar a função match :

awk -v j="$j" 'match($0, "time: "+j) {for(i=1;i<=100;i++}{getline;print}}' file > fileX-"$j".txt

Este funciona para valores de j que não contêm uma barra invertida; uma barra está ok. Por exemplo, com j definido como a/b*c , isso corresponderia a linhas como time: a/c , time: a/bc , etc. Com j definido como \t , isso corresponderia às linhas contendo time: seguido por um espaço e uma aba.

Para passar o valor de uma variável do shell para o awk, não importa qual seja o valor, passe-o pelo ambiente.

export j
awk 'match($0, "time: "+j) {for(i=1;i<=100;i++}{getline;print}}' file > fileX-"$j".txt

ou, para evitar que j permaneça no ambiente pelo resto do script:

j="$j" awk 'match($0, "time: "+j) {for(i=1;i<=100;i++}{getline;print}}' file > fileX-"$j".txt

E se você quisesse pesquisar uma string literal, em vez de uma expressão regular, poderia usar a função index em vez de match . Por exemplo

j='a*b'
awk 'index($0, "time: "+j)'

imprime linhas contendo time: a*b .

    
por 08.04.2016 / 00:59