
行値を列値に変換するのに役立ちます。私の入力はfile.dat
次のとおりです
最初の2つのフィールドはそれぞれアルファベット文字列と数字です。入力には常に同じ数のフィールドがあります。6。
入力する
A|1|DLT|07:30|10:30|34
A|1|STG|07:30|10:30|NA
A|1|MAIN|06:30|10:30|NA
A|2|STG|07:30|10:30|NA
A|2|UNLD|04:30|10:30|90
B|1|DLT|03:30|10:30|34
B|1|STG|07:30|09:30|NA
B|1|MAIN|07:25|10:30|NA
B|1|UNLD|05:30|12:30|8
出力に変化があります。出力フィールドすべての行には18個のフィールドがあり、各行には入力ファイルの最初の2つのフィールドがあり、その後には次の順序で3番目、...、18番目のフィールドがあります。ここで、空のフィールドは入力ファイルから欠落している行です。レコードの順序はDLTで、STG、MAIN、およびUNLDの後に対応するレコードが続きます。
出力
A|1|DLT|07:30|10:30|34|STG|07:30|10:30|NA|MAIN|06:30|10:30|NA||||
A|2|||||STG|07:30|10:30|NA|||||UNLD|04:30|10:30|90
B|1|DLT|03:30|10:30|34|STG|07:30|09:30|NA|MAIN|07:25|10:30|NA|UNLD|05:30|12:30|8
- A | 1 UNLDがありません
- A | 2にはDLTとMAINはありません。
- 記録は失われません。
同様に、入力ファイルの3番目のフィールドに対応するレコードが見つからない場合は、出力フィールドが次のようになるように空の値に置き換える必要があります。18地域。
答え1
私のawk
アドバイス:
awk -F'|' '{ if (a[$1$2] == "") {
a[$1$2] = $0
}
else {
a[$1$2] = a[$1$2]","$3"|"$4"|"$5"|"$6
}
}
END {
for (key in a) {
print a[key]
}
}' <input.txt | sort
説明する
この-F'|'
オプションは定義しますフィールド区切り記号(awk
行のフィールドを解析するために使用されます)はファイル形式なので、文字「|」として使用されます。
a[...]
配列です。配列はawk
インデックスではなく、Python辞書に多少似ています。鍵これは実際に文字列です。入力ファイルの各行のテストでは、エントリが存在する場合は最初の2つのフィールド(最初の行など)if (a[$1$2] == "")
に対応するキーを確認します。$1$2 = A1
そうでない場合(A|1|...
最初の行を読み取る)、行全体がこのキー(a[$1$2] = $0
)に保存されます。すでにコンテンツがある場合(A|1|...
別の行が保存されている場合)、エントリをコンマで連結し、「|」を使用してフィールドを3から6まで区切ります。 (a[$1$2] = a[$1$2]","$3"|"$4"|"$5"|"$6
)。
最後に、ファイルの検索が完了したら、各キーのエントリを出力する必要があります。私たちはEND
これをブロックで行います(このコマンドはすべてのファイルを読み取った後に実行されます)。これを行うには、for (key in a)
配列()のすべてのキーを繰り返し、各キーの項目を印刷します。
その後、最終出力はにパイプされますsort
。配列キーは英数字で巡回されないため、後で行などをawk
取得できるように出力をソートする方がきれいになります。A|1|...
A|2|...
最後の編集により、すべてが少しトリッキーになりました。必要な指示がawk
多少複雑になる可能性があるため、スクリプトファイルを生成することをお勧めします(例:拡張子付きのテキストファイルの生成awk
)。次のスクリプトをコピーしてください。.awk
myScript.awk
BEGIN { FS="|" }
$3 == "DLT" {
dlt[$1"|"$2]=$3"|"$4"|"$5"|"$6
a[$1"|"$2]++
}
$3 == "STG" {
stg[$1"|"$2]=$3"|"$4"|"$5"|"$6
a[$1"|"$2]++
}
$3 == "MAIN" {
main[$1"|"$2]=$3"|"$4"|"$5"|"$6
a[$1"|"$2]++
}
$3 == "UNLD" {
unld[$1"|"$2]=$3"|"$4"|"$5"|"$6
a[$1"|"$2]++
}
END {
for (key in a) {
if (dlt[key] == "") dlt[key]="|||"
if (stg[key] == "") stg[key]="|||"
if (main[key] == "") main[key]="|||"
if (unld[key] == "") unld[key]="|||"
print key"|"dlt[key]"|"stg[key]"|"main[key]"|"unld[key]
}
}
それを書く:
awk -f myScript.awk <input.txt | sort
私の元の答えの説明を理解したら、このアルゴリズムも理解できます。今回は、各データ型(dlt、stg、main、unld)の配列を作成し、その値を最初の2つのフィールドに対応するキーに保存します。配列はa
すべての可能なキーを追跡するために使用されます。最後に、配列のキーを繰り返しa
、そのキーのデータ配列の1つが空の場合は、必要に応じて "|||"を入力し、各行に18のフィールドがあります。
答え2
少し違うバレンタインB.の回答:
awk -F"|" '
{
key = $1 "|" $2
a[key] = 1
b[key][$3] = $3 "|" $4 "|" $5 "|" $6
}
END {
subtype[1] = "DLT"
subtype[2] = "STG"
subtype[3] = "MAIN"
subtype[4] = "UNLD"
for (key in a)
{
output = key
for (i = 1; i <= 4; i++)
{
st = subtype[i]
if (b[key][st] == "")
output = output "||||"
else
output = output "|" b[key][st]
}
print output
}
}' file.dat
のようにバレンタインB.の回答:
-F"|"
|
入力行からフィールドを抽出できるように、フィールド区切り記号をに設定します。key
A|1
または、A|2
またはB|1
通常、最初の2つのフィールドの接続に設定します。これを使用して、そのキーの組み合わせに関連するデータの最大4行を結合します。a[key]
表示するデータ(キー)を記録するには1に設定します。b[key][$3]
キーの後ろの残りの行に設定します。たとえば、にb["A|1"]["DLT"]
設定されます"DLT|07:30|10:30|34"
。このように、我々はログを残すことができます。みんな私たちが見るデータ(質問で指定されているように行に6つ以下のフィールドがあると仮定)に何が含まれているのかわからず、これを行うことに注意してください$3
。
すべてのデータを読んだ後:
- サブタイプ(たとえば、有効な値、「DLT」、「STG」、「MAIN」、および「UNLD」)を定義する配列な
$3
ので、サブタイプを複数回リストする必要はありません。 - 私たちが見たすべてのキーを繰り返します。出力ラインの構築を開始します。
- 上記の4つのサブタイプを繰り返します。そのキーとそのサブタイプのデータがある場合はそれを出力行に追加し、そうでない場合は4つの空のフィールドを追加します。
- この行を印刷してください。
sort
出力を整列させるには、パイプで接続します。 (私が「もし」と言った理由は、たとえ質問がプログラム出力例はソートされていますが、これが出力をソートする必要があるわけではありません。 )
2番目のフィールドに何があるかについての質問は正確ではありません。ただ「数字」としか出ていません。数値が異なる整数になり、数値でソートするには、次のようにします。
sort -t"|" -k1,1 -k2,2n
答え3
4番目のフィールドの値をキャプチャし、「val」という変数に保存します。
配列を作成し、最初と2番目のフィールドに基づいて配列の値を追加します。
最後に、配列値を印刷して小さな調整(交換、削除など)を行います。
$ awk -F\| '{ val=$3;
for (i=4;i<=NF;i++) {val=val"|"$i}
Arr[$1OFS$2]=Arr[$1OFS$2]","val;
next
}
END { for (i in Arr) {
A=Arr[i];
sub(" ","|",i);
print i,A
}
}' test.txt | sed "s/ ,/\|/"
A|1|DLT|07:30|10:30|34 ,STG|07:30|10:30|NA ,MAIN|06:30|10:30|NA
B|1|DLT|03:30|10:30|34 ,STG|07:30|09:30|NA ,MAIN|07:25|10:30|NA ,UNLD|05:30|12:30|8
A|2|UNLD|04:30|10:30|90 ,DLT|08:30|11:30|4 ,STG|07:30|10:30|NA