Usando 'awk' para imprimir um espaço reservado em vários blocos de dados

0

Bom dia,

Eu tenho muitos blocos de dados, contendo de 1 a 8 variáveis (denotadas "CONDx" abaixo) com base na entrada do usuário. Eu escrevi um script usando awk e grep para extrair dados para serem apresentados em um formato de coluna. Esses dados que eu extraí de um arquivo maior, então talvez eu precise dar um passo atrás para a minha solução. De qualquer forma, os dados se parecem com isso:

> cat file
foo
REF    Data1
COND1  Value1
COND2  Value2
foo
REF    Data2
COND3  Value3
foo
REF    Data3
COND1  Value4
COND3  Value5
foo

Meu script apresenta os resultados no formato de coluna a seguir, que preciso modificar manualmente na direção vertical para que seja alinhado corretamente:

        COND1   COND2   COND3   COND4   COND5   COND6   COND7   COND8
Data1   Value1  Value2  Value3  x       x       x       x       x               
Data2   Value4          Value5  
Data3

A minha pergunta é, é possível usar o awk (ou sed, seja qual for) para verificar se cada CONDx está contido em cada bloco REF, se é imprimir o "ValueX" correspondente, e se não estiver, imprima um "x "(ou melhor ainda um espaço em branco) como um espaço reservado? Então a saída desejada seria:

        COND1   COND2   COND3   COND4   COND5   COND6   COND7   COND8
Data1   Value1  Value2  x       x       x       x       x       x       
Data2   x       x       Value3  x       x       x       x       x
Data3   Value3  x       Value5  x       x       x       x       x

Para o COND1, por exemplo, parte do script continha:

 grep COND1 file | awk '{print $2} END { if (!NR) print "x" }' > temp.cond1

temp.cond1 para ser colado no arquivo resultante, mas isso só imprime um "x" na primeira linha, como visto na minha saída, eu entendo por que isso não funciona, mas não consigo pensar em uma nova maneira. Eu acho que talvez seja possível fazer com uma instrução IF, talvez? Gostaria de receber ajuda.

Obrigado pelo seu tempo.

    
por Henry 10.01.2017 / 21:03

1 resposta

1

Aqui está uma implementação no awk. Já faz algum tempo desde que eu usei a linguagem por mais de um par de programa de linha, e pensei que seria um exercício interessante.

Para executar o awk com um programa, você precisa especificar o -f flag, por exemplo:

awk -f my_program.awk my_data.txt

Esta implementação apenas exibe as variáveis CONDx que ele encontra no arquivo.

# Initialize a couple of variables
BEGIN {
    fill_value = "xx"
    record_number = 0
}

# for any line that begins and ends with 'foo' save the record
# and then move on to process the next line
/^foo$/ { save_record(); next }

# for any other line, grab the key and data, and mark that the record is valid
{
    fields[$1] = $1
    record[$1] = $2;
    record[1] = "exists"
}

# after reading in all of the records, output them
END {
    # sort the fields into alpha order
    asort(fields)
    delete fields["REF"]

    printf("%-8s", "REF")
    for (field in fields) {
        printf("%-8s", fields[field])
    }
    print ""

    # print the records
    for (i=0; i < record_number; i++) {
        record_name = record_number_str(i, "REF");
        printf("%-8s", records[record_name])

        for (field in fields) {
            record_name = record_number_str(i, fields[field])
            to_print = fill_value
            if (record_name in records)
                to_print = records[record_name]
            printf("%-8s", to_print)
        }
        print ""
    }
}

function save_record() {
    if (1 in record) {
        delete record[1]
        for (rec in record)
            records[record_number_str(record_number, rec)] = record[rec]
        record_number++
    }
    delete record
}

# awk only has single dimensional associative arrays.  So we need
# to construct a key for the array that has two dimensions
function record_number_str(record_number, rec) {
    return sprintf("%06d %s", record_number, rec)
}
Eu acho que o awk não é a linguagem ideal para isso. Melhor seria algo como: perl, ruby ou python. Como contraste, aqui está a implementação de python. Note que é apenas cerca de 1/2 quantas linhas:

import fileinput

record = {}
records = []
fields = set()
for line in [l.strip() for l in fileinput.input()]:
    if line == 'foo':
        if record:
            records.append(record)
            record = {}
    else:
        key, value = line.split()
        record[key] = value
        fields.add(key)

# print the header
print("%-8s" % "REF", end="")
fields.remove("REF")
for field in sorted(fields):
    print("%-8s" % field, end="")
print()

# print the records
for record in records:
    print("%-8s" % record["REF"], end="")
    for field in sorted(fields):
            print("%-8s" % record.get(field, ''), end="")
    print()
    
por 11.01.2017 / 04:06

Tags