Como passar uma string que especifica colunas para serem impressas no awk?

3

Eu tenho um arquivo com um grande número de colunas separadas por espaço. Eu quero imprimir colunas específicas com base em determinados critérios numéricos de forma dinâmica. Por exemplo:

]$ cols=$(for i in 'seq 1 3'; do echo -n "\$$[$[i-1]*6+1],\$$[$[i-1]*6+2],\$$[$[i-1]*6+3],\$$[$[i-1]*6+4+66],\$$[$[i-1]*6+5+66],\$$[$[i-1]*6+6+66],"; done)

que me dá as colunas que eu quero imprimir:

]$ echo ${cols%?}
$1,$2,$3,$70,$71,$72,$7,$8,$9,$76,$77,$78,$13,$14,$15,$82,$83,$84

quando eu passo isso para o awk como uma string, eu não entendo o que eu quero:

]$ awk -v cols=${cols%?} '{print cols}' file-testawk | head -2
$1,$2,$3,$70,$71,$72,$7,$8,$9,$76,$77,$78,$13,$14,$15,$82,$83,$84
$1,$2,$3,$70,$71,$72,$7,$8,$9,$76,$77,$78,$13,$14,$15,$82,$83,$84 

o awk trata-o como uma string em vez de identificadores de coluna.

Como posso passar uma string de colunas para imprimir no awk de uma maneira que seja corretamente reconhecida? Estou à procura de uma solução simples, mais ou menos de uma linha, por ex. assim:

cols=$(for i in 'seq 1 3'; do echo -n "\$$[$[i-1]*6+1],\$$[$[i-1]*6+2],\$$[$[i-1]*6+3],\$$[$[i-1]*6+4+66],\$$[$[i-1]*6+5+66],\$$[$[i-1]*6+6+66],"; done); awk -v cols=${cols%?} '{print cols}' file-testawk > file.out
    
por Dimi 02.06.2017 / 21:15

3 respostas

3

o awk não tem recursos como o eval, mas você pode fazer um truque usando a funcionalidade awk -f (leia o script do arquivo) combinada com a substituição do processo bash:

$ a="\,\"
$ echo "$a"
$1,$4
$ a="{print $a}"
$ echo "$a"
{print $1,$4}
$ awk -f <(echo "$a") <<<"one two three four five"
one four
    
por 02.06.2017 / 22:05
2

Uso: ./pass_numbers_to_awk.sh Explicação nos comentários.

#!/bin/bash

#generate random string of numbers - simulation column's numbers 
for i in {1..2}; do
    for j in {1..3}; do
        num=$(( (i-1) * 6 + j ))
        #numbers separated by vertical bar symbol 
        string_of_numbers+="${num}|"
    done
done

# pass to awk string like a "1|2|3|7|8|9|13|14|15|", 
# removing last vertical bar "|"
##
# use the awk split function - for information 
# look at the 'man mawk | grep -A 3 split\(s,A,r\)'
##      
# go through array and print specified columns.

awk -v string_from_bash="${string_of_numbers%?}" '
BEGIN {
    num_of_cols = split(string_from_bash, array_of_columns, "|");
}
{
    for (i = 1; i <= num_of_cols; i++) {

        # Prevent trailing spaces emergence
        OFS = (i > 1) ? " " : ""

        printf "%s%s", OFS, $array_of_columns[i];
    }
    printf "\n";
}' < input.txt

Criando o arquivo input.txt para teste: ./create_table.sh > input.txt

#!/bin/bash

for i in {A..O}; do
    for j in {1..10}; do
        echo -n "column_${j} "
    done
    echo
done
    
por 04.06.2017 / 02:47
1

awk é especialista em fazer esses cálculos de índice, portanto:

awk -v N=3 '
   {
   for ( i=1; i<= N; ++i )
      print $((i-1)*6+1), $((i-1)*6+2), $((i-1)*6+3), $((i-1)*6+4+66), $((i-1)*6+5+66), $((i-1)*6+6+66)
   }
' data.file

Sendo a idéia básica, se você fornecer ao awk um número armazenado em uma variável i , então awk poderá buscar o campo correspondente a esse número via $(i) . Agora, i também pode ser uma expressão, como é o caso aqui.

    
por 02.06.2017 / 21:48