
おはようございます、
ユーザー入力に基づいて、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()