altere a variável awk com base na correspondência dentro do awk

1

Eu tenho um arquivo de dados que estou pré-processando antes de enviá-lo para o gnuplot. Consiste em uma linha de cabeçalho e várias linhas de dados, com muitas colunas de tipos de dados. As três primeiras colunas são sempre do mesmo tipo e ordem. O número total de colunas é constante em um arquivo, mas não será constante entre os arquivos. Não é garantido que o seqno comece em 1, mas sempre aumentará monotonicamente.

Eu tenho um script para inserir uma linha de cabeçalho onde eu quero no arquivo de dados, mas quero poder alterar esse cabeçalho com base na correspondência em que estou atualmente. Especificamente, quero prefixar minha variável $ i para as colunas 4, 5, ..endth do meu cabeçalho. Além disso, o cabeçalho é idêntico em cada veiculação.

Isso será executado como um script, então, se eu precisar pré-processar o cabeçalho para descobrir quantas colunas ele tem, isso pode ser feito facilmente.

Meu script atual, sem a substituição de cabeçalho desejada, é (exemplos de cabeçalho adicionais no final):

header=$(head -n1 $input)
awk -v i=3 -v hdr="$header" 'NR>1 && $i!=p {print "\n\n"hdr}{p=$i} 1' ${input} > ${output}

Meu exemplo de entrada é:

#filename       seqno   phasename       a       b       c       scale   Rwp
blah_001.xye    1       corundum        3       3       12      0.001   3
blah_002.xye    2       corundum        3.1     3.1     12.1    0.002   3.5
blah_003.xye    3       corundum        3.2     3.2     12.2    0.001   3.1
blah_001.xye    2       silcon_NIST     5.4     5.4     5.4     0.002   3
blah_002.xye    3       silcon_NIST     5.41    5.41    5.41    0.004   3.5
blah_003.xye    4       silcon_NIST     5.42    5.42    5.42    0.002   3.1

Minha saída atual é:

#filename       seqno   phasename       a       b       c       scale   Rwp
blah_001.xye    1       corundum        3       3       12      0.001   3
blah_002.xye    2       corundum        3.1     3.1     12.1    0.002   3.5
blah_003.xye    3       corundum        3.2     3.2     12.2    0.001   3.1


#filename       seqno   phasename       a       b       c       scale   Rwp
blah_001.xye    2       silcon_NIST     5.4     5.4     5.4     0.002   3
blah_002.xye    3       silcon_NIST     5.41    5.41    5.41    0.004   3.5
blah_003.xye    4       silcon_NIST     5.42    5.42    5.42    0.002   3.1

Minha saída desejada é:

#filename       seqno   phasename       corundum_a       corundum_b       corundum_c       corundum_scale   corundum_Rwp
blah_001.xye    1       corundum        3       3       12      0.001   3
blah_002.xye    2       corundum        3.1     3.1     12.1    0.002   3.5
blah_003.xye    3       corundum        3.2     3.2     12.2    0.001   3.1


#filename       seqno   phasename       silcon_NIST_a       silcon_NIST_b       silcon_NIST_c       silcon_NIST_scale   silcon_NIST_Rwp
blah_001.xye    2       silcon_NIST     5.4     5.4     5.4     0.002   3
blah_002.xye    3       silcon_NIST     5.41    5.41    5.41    0.004   3.5
blah_003.xye    4       silcon_NIST     5.42    5.42    5.42    0.002   3.1

O que eu quero fazer: Como posso alterar a variável awk hdr dentro do awk para pré-anexar a variável $i às colunas da quarta extremidade da variável hdr antes de inseri-la no arquivo de entrada?

Alguns outros cabeçalhos de exemplo em outros arquivos para processamento

#filename   seqno   phasename   temp    temp_err    csL csL_err csG csG_err strL    strL_err    strG    strG_err    B_Na    B_Na_err    B_Mg    B_Mg_err    B_F B_F_err B_H B_H_err B_O B_O_err B_Fe    B_Fe_err    F_occ   F_occ_err   Na_x    Na_x_err    Na_z    Na_z_err    F1_x    F1_x_err    F1_y    F1_y_err    F1_z    F1_z_err    F2_x    F2_x_err    F2_z    F2_z_err    a1  a1_err  a2  a2_err  a3  a3_err  a4  a4_err  a5  a5_err  a6  a6_err  a7  a7_err  s1  s1_err  s2  s2_err  s3  s3_err  a   a_err   b   b_err   c   c_err   al  al_err  be  be_err  ga  ga_err  volume  volume_err  mass    mass_err    MAC MAC_err density density_err LAC LAC_err Lvol    Lvol_err    e0  e0_err  scale   scale_err   wt% wt%_err num_area    num_area_err    r_bragg r_bragg_err r_wp    r_wp_err    r_exp   r_exp_err   gof gof_err
#filename   seqno   phasename   csL csL_err strG    strG_err    a   a_err   b   b_err   c   c_err   al  al_err  be  be_err  ga  ga_err  volume  volume_err  mass    mass_err    MAC MAC_err density density_err LAC LAC_err Lvol    Lvol_err    e0  e0_err  scale   scale_err   wt% wt%_err num_area    num_area_err    r_bragg r_bragg_err r_wp    r_wp_err    r_exp   r_exp_err   gof gof_err
#filename   seqno   phasename   csG strL    F1_x    F1_y        F1_z    volume      gof 
    
por masher 03.08.2018 / 09:36

2 respostas

2
$ awk -f script.awk file
#filename       seqno   phasename       corundum_a      corundum_b      corundum_c      corundum_scale  corundum_Rwp
blah_001.xye    1       corundum        3       3       12      0.001   3
blah_002.xye    2       corundum        3.1     3.1     12.1    0.002   3.5
blah_003.xye    3       corundum        3.2     3.2     12.2    0.001   3.1

#filename       seqno   phasename       silcon_NIST_a   silcon_NIST_b   silcon_NIST_c   silcon_NIST_scale       silcon_NIST_Rwp
blah_001.xye    2       silcon_NIST     5.4     5.4     5.4     0.002   3
blah_002.xye    3       silcon_NIST     5.41    5.41    5.41    0.004   3.5
blah_003.xye    4       silcon_NIST     5.42    5.42    5.42    0.002   3.1

Onde script.awk é

BEGIN   { OFS = "\t" }

/^#/    {
    # save header fields

    for (i = 1; i <= NF; ++i)
        header[i] = $i

    next
}

# if column 2 contains a lower number than the previous line
# (or if no previous line with data), then output header
$2 < col2 || !col2 {
    # output blank line if needed
    if (print_blank) {
        print ""
    }
    print_blank = 1

    # print first three headers as-is
    for (i = 1; i <= 3; ++i)
        printf("%s%s", header[i], OFS)

    # prepend column three to remaining headers
    for (i = 4; i < NF; ++i)
        printf("%s_%s%s", $3, header[i], OFS)
    printf("%s_%s%s", $3, header[NF], ORS)
}

# print all lines and save value from column 2
{ col2 = $2; print }

O script salva o cabeçalho dos dados de entrada na matriz header . Quando encontramos uma segunda coluna cujo valor é menor do que o valor da coluna dois da linha anterior, geramos um novo cabeçalho antes de gerar os dados. O cabeçalho é precedido por uma linha em branco, a menos que seja o primeiro cabeçalho. Os nomes das colunas variáveis recebem seus nomes do terceiro campo.

O script não usa parâmetros.

    
por 03.08.2018 / 09:49
1

Se existe a possibilidade de que grupos de nomes de pseudônimos comecem com o seqno maior do que o último, pode não funcionar dependendo do seqno, mas talvez melhor no nome de fásica. Você pode tentar esta adaptação da proposta de Kusalananda:

    awk '
    FNR == 1        {split ($0, header)
                     next
                    }

    $3 != LAST      {printf TMPRS; TMPRS = ORS
                     for (i = 1; i <= NF; ++i) printf ("%s%s%s", (i>3)?$3"_":_, header[i], (i==NF?ORS:OFS))
                    }

                    {LAST = $3
                     print
                    }
    ' OFS="\t" filename1 filename2
    
por 03.08.2018 / 15:16