「awk」を使用して複数のデータチャンクでプレースホルダを印刷します。

「awk」を使用して複数のデータチャンクでプレースホルダを印刷します。

おはようございます、

ユーザー入力に基づいて、1〜8個の変数(以下に「CONDx」と表示されています)を含む複数のデータブロックがあります。列形式で表示するデータを抽出するために、awkとgrepを使用してスクリプトを作成しました。大きなファイルからデータを抽出したので、ソリューションから一歩踏み出す必要があるかもしれません。とにかく、データは次のとおりです。

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

私のスクリプトは、次の形式で結果を表示します。正しく配置するには、手動で垂直に変更する必要があります。

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

私の質問は、awk(またはsedなど)を使用して、各CONDxが各REFブロックに含まれていることを確認し、対応する「ValueX」を印刷する場合、そうでない場合は「x」(またはBetter)を印刷することは可能ですか?空白)をプレースホルダとして使用しますか?したがって、希望の出力は次のようになります。

        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

COND1 を例にとると、スクリプトの一部には以下が含まれます。

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

temp.cond1を結果ファイルに貼り付けましたが、出力に示すように、最初の行にのみ「x」が印刷されます。なぜ動作しないのか理解していますが、これを行う新しい方法を考えることはできません。 IF文でできると思いましたか?どんな助けでも大変感謝します。

時間をいただきありがとうございます。

ベストアンサー1

これはawkでの実装です。言語で数行以上のプログラムを書いて、それが面白い練習になると思ったかなりかなり古いです。

プログラムを使用してawkを実行するには、フラグを指定する必要があります-f。たとえば、次のようになります。

awk -f my_program.awk my_data.txt

この実装はファイル内のCONDx変数のみを出力します。

# 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)
}

私はawkが最も理想的な言語ではないと思います。より良い方法はPerl、Ruby、またはPythonです。比較のために、以下はPythonの実装です。行数は約1/2にすぎません。

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()

おすすめ記事