como executar o awk a partir do número de linha específico armazenado em uma variável

0

Eu quero pegar os lençóis da primeira aparição de "barra" depois da aparência de "foo". Isso deve ser executado em um loop while, para o arquivo inteiro. Assim:

test_file:

foo
xxx
xxx
xxx
bar
bar
xxx
bar
xxxx
xxx
xx
foo
xxx
xxx
xxx
xxx
xxx
bar

Ele deve retornar:

linenumbersfoo: 1 12
linenumbersbar: 5 18

Meu código:

linenumbersfoo=($(awk '/foo/ {print FNR}' test_file.sh))
length="${#linenumbersfoo[@]}"

while [[ $COUNTERR -lt length  ]]; do
number=$((${linenumbersfoo["$COUNTERR"]}))

linenumbersbar[$COUNTERR]=$(awk '"$number"<=NR, /bar/ {print FNR;exit;}' test_file.sh)

let COUNTERR=COUNTERR+1 
done

echo "${linenumbersfoo[@]}"

echo "${linenumbersbar[@]}"

Eu recebo:

linenumbersfoo: 1 12
linenumbersbar: 1 1

O problema parece ser a variável "número", se eu escrever, por ex. 5 em vez de $ number, funciona.

Qualquer ajuda é muito apreciada!

EDIT: O arquivo de teste deve ter esta aparência:

bar foo
xxx
xxx
xxx
bar
bar
xxx
bar
xxxx
xxx
xx
bar foo
xxx
xxx
xxx
xxx
xxx
bar

significa que eu devo encontrar a primeira barra após o foo, mas NÃO na linha com o foo

EDIT: Desculpe por isso, mas o arquivo de teste não mostrou todos os casos, última tentativa:

bar foo
xxx
xxx
xxx
bar
bar
xxx
bar
xxxx
xxx
xx
bar foo
xxx
xxx
bar foo
xxx
xxx
xxx
xxx
xxx
bar

resultado esperado:

linenumbersfoo: 1 12 15
linenumbersbar: 5 15 21

Se houver o seguinte para "bar foo", quero que ele seja encontrado. A linha 15 não foi encontrada.

    
por Julian 08.03.2018 / 11:44

2 respostas

0

EDIT: adicionando uma melhoria para corresponder ao seu EDIT ...

uma sugestão com o awk:

BEGIN {
  ffoo=0; ffoos=""; fbars="";
} 
/foo/ {
  ffoo=1; ffoos=ffoos" "NR;
} 
/bar/ {
  if ((match($0, "foo") == 0) && (ffoo!=0)) {
    fbars=fbars" "NR; 
    ffoo=0;
  }
} 
END {
  print "linenumbersfoo: "ffoos"\n"; 
  print "linenumbersbar: "fbars"\n";
}
    
por 08.03.2018 / 12:11
0

Não faça isso em um loop de shell, awk fará isso por você.

Este é um script awk que você pode armazenar em um arquivo de script e invocar com awk -f script.awk filename (modificado para funcionar com a edição recente da pergunta):

BEGIN { lookfor[0] = "foo"; lookfor[1] = "bar"; i = 0 }

$0 ~ lookfor[i] {
    lines[lookfor[i]] = lines[lookfor[i]] ? lines[lookfor[i]] ", " NR : NR
    i = (i + 1) % 2
}

END { for (n in lines) printf("%s\t%s\n", n, lines[n]) }

Executando isso nos seus dados de exemplo:

$ awk -f script.awk file
foo     1, 12
bar     5, 18

O script awk procura as strings na matriz lookfor . Primeiro, ele procura pela primeira string ( foo ) e, quando a encontra, começa a procurar pela segunda string ( bar ) e, em seguida, a primeira novamente de maneira alternada. Cada vez que encontra uma string, ele armazena o número da linha atual na matriz associativa lines para a string correspondente.

No final, os números de linha coletados em lines são exibidos.

A linha de aparência descolada

lines[lookfor[i]] = lines[lookfor[i]] ? lines[lookfor[i]] ", " NR : NR

adiciona o número da linha ao final da sequência de números de linha na matriz lines . Se a string estiver vazia, ela apenas ajusta para o número da linha atual, mas se ela já contiver alguma coisa, uma vírgula é inserida entre a string existente e o número da linha.

Você pode mudar isso para o mais simples

lines[lookfor[i]] = lines[lookfor[i]] " " NR

que irá inserir um espaço entre os números de linha (e na frente do número da primeira linha).

    
por 08.03.2018 / 12:01