Dividir em awk não não imprimindo valores de matriz

3

Eu tenho uma string tstArr2 que tem o seguinte conteúdo

'3 5 8'

Agora no awk eu quero analisar um arquivo simples

test my array which array is better array

INDIA USA SA NZ AUS ARG GER BRA
US AUS INDIA ENG NZ SRI PAK WI BAN NED IRE

apenas nestas colunas numeradas. Eu tentei o seguinte

awk -vA="$tstArr2" 'BEGIN{split(A,B," ");} {if(NR>1){for(i=1; i<= length(B); i++){printf "%s ",B[i]}}print " "}' testUnix3.txt

Mas diz

awk: Cannot read the value of  B. It is an array name.

The input line number is 2. The file is testUnix3.txt.
The source line number is 1.

O que estou perdendo? Se eu tentar o seguinte

awk -vA="$tstArr2" 'BEGIN{split(A,B," ");} {if(NR>1){for(i in B){printf "%s ",$B[i]}}print " "}' testUnix3.txt

imprime as saídas, mas elas não estão em ordem. Eu quero que eles estejam em ordem. Por favor explique. Saída desejada:

 SA AUS BRA

 INDIA NZ WI
    
por recmach 20.11.2014 / 08:27

3 respostas

5

POSIX definido comprimento em awk é uma função de string, argumento considerado como uma linha. Usar length com uma matriz como argumento é um comportamento não especificado.

Em algumas implementações de awk como gawk (versão > = 3.1.6 ) , versão do OS X do AWK , você pode usar length com uma matriz como argumento, ele retornará o número de elementos na matriz.

A matriz em awk é uma matriz associativa, o loop através da matriz associativa não garante nada sobre a ordem. Nesse caso, você pode aproveitar a função split , que retorna o número de campos para obtenha os elementos numéricos do array.

POSIXly, você pode tentar:

$ awk -vA="$tstArr2" '
  BEGIN{n = split(A,B," ");}
  {
    if(NR > 1) {
      for(i = 1;i <= n;i++) {
        printf "%s ",$B[i];
      }
    }
    print " ";
  }
' file

SA AUS BRA  
INDIA NZ WI
    
por 20.11.2014 / 09:01
2

(Para o não-GNU awk, por favor veja a resposta do @ cuonglm.)

Com isso como arquivo de teste:

$ cat testUnix3.txt 
test my array which array is better array

INDIA USA SA NZ AUS ARG GER BRA
US AUS INDIA ENG NZ SRI PAK WI BAN NED IRE

Este código seleciona as colunas 3, 5 e 8:

$ tstArr2='3 5 8'
$ awk  -vA="$tstArr2" 'BEGIN{split(A,B," ");} NR>1{for(i=1; i<= length(B); i++) printf "%s ",$B[i]; print "";}' testUnix3.txt

SA AUS BRA 
INDIA NZ WI 

O acima foi testado com o GNU awk .

awk faz um loop e pede

awk tem matrizes associativas. Como o tutorial do awk do Grymoire explica:

There is one minor problem with associative arrays, especially if you use the for command to output each element: you have no control over the order of output.

Essa é a razão pela qual o outro código que você citou, que usa um for(i in B) loop, pode, às vezes, imprimir colunas fora de ordem.

O GNU awk tem uma extensão para superar esse problema:

$ gawk -vA="$tstArr2" 'BEGIN{split(A,B," "); PROCINFO["sorted_in"]="@ind_num_asc"} {if(NR>1){for(i in B){printf "%s ",$B[i]}print " "}}' testUnix3.txt

SA AUS BRA  
INDIA NZ WI  

Ao definir PROCINFO["sorted_in"]="@ind_num_asc" , os índices serão colocados em loop por ordem numérica crescente. Esta extensão GNU está documentada aqui .

    
por 20.11.2014 / 08:43
1

Há muita sobrecarga para usar um instrumento tão poderoso quanto awk para tarefas simples:

tstArr2='3,5,8'
tail -n+2 testUnix3.txt | cut -d' ' -f"$tstArr2"
    
por 20.11.2014 / 11:11

Tags