データロギングシステムの1000個のファイルを含むディレクトリがあり、各ファイルには最大40,000行以上を含めることができます。問題は、時々1つ以上のセンサーからデータが記録されず、失われることです。
ファイル1:
A,B,C,D,F
10,20,10,20,5
ファイル2:
B,C,D,E,F
20,10,20,5,10
ファイル3:
D,E,F
10,30,20
必要な結果は、すべてのファイルを1つのヘッダーにマージ/接続することです。入力ファイルに列がない場合(破損したセンサーのため)、そのセクションはNULL値に置き換えられます。
A,B,C,D,E,F
10,20,10,20,,5
,20,10,20,5,10
,,,10,30,20
最後の列Fは日付/時刻スタンプなので、常に存在します。
この答えを見つけましたが、すべてのヘッダー/列がすべてのファイルで同じであるとします。
ヘッダーの順序が異なる複数の大きなCSVファイルを貼り付ける
私もこの問題を発見しました複数のCSVファイルをマージして、一致する列と一致しない列を取得します。しかし、私が利用できるほど答えは完全ではありません。
ありがとう
答え1
非常にきれいでシンプルな代替ツールを試してみたい場合(https://github.com/johnkerl/miller)、入力CSVファイルを含むフォルダから始めて、このコマンドを使用します。
mlr --csv unsparsify *.csv >out.csv
あなたはやる
A,B,C,D,F,E
10,20,10,20,5,
,20,10,20,10,5
,,,10,20,30
F a を終了するには、次のコマンドを使用します。
mlr --csv unsparsify then reorder -e -f F *.csv
ファイルが多い場合は、次の2つの手順で実行できます。
mlr --icsv cat *.csv >tmp.txt
mlr --ocsv unsparsify tmp.txt >out.csv
答え2
BEGIN {
OFS = FS = ","
# Parse given column headers and remeber their order.
# nf will be the number of fields we'd want in the output.
nf = split(pick, header)
for (i = 1; i <= nf; ++i)
order[header[i]] = i
# Output headers.
print pick
}
FNR == 1 {
# Parse column headers from input file.
delete reorder
for (i = 1; i <= NF; ++i)
# If the current header is one that we'd like to pick...
if ($i in order)
# ... record what column it is located in.
reorder[order[$i]] = i
next
}
{
# Process data fields from input file.
# We build a new output record, so explicitly split the current record
# and save it in the field array, then empty the record and rebuild.
split($0, field)
$0 = ""
for (i = 1; i <= nf; ++i)
# If reorder[i] is zero, it's a column that is not available in the
# current file.
$i = (reorder[i] == 0 ? "" : field[reorder[i]])
print
}
上記awk
のスクリプトは、抽出したい列を特定の順序でパラメータとして選択し、各入力ファイルからその列を抽出します。
質問に表示されるデータの例:
$ awk -v pick='A,B,C,D,E,F' -f script.awk file*.csv
A,B,C,D,E,F
10,20,10,20,,5
,20,10,20,5,10
,,,10,30,20
$ awk -v pick='F,B,A' -f script.awk file*.csv
F,B,A
5,20,10
10,20,
20,,
答え3
データ行間に実際の空行がないと仮定し、GNU awkを使用してソートします。
$ cat tst.awk
BEGIN { FS=OFS="," }
FNR==1 {
delete f
for (i=1; i<=NF; i++) {
f[$i] = i
flds[$i]
}
numFiles++
next
}
{
for (tag in f) {
val[numFiles,tag] = $(f[tag])
}
}
END {
PROCINFO["sorted_in"] = "@val_str_asc"
sep = ""
for (tag in flds) {
printf "%s%s", sep, tag
sep = OFS
}
print ""
for (fileNr=1; fileNr<=numFiles; fileNr++) {
sep = ""
for (tag in flds) {
printf "%s%s", sep, val[fileNr,tag]
sep = OFS
}
print ""
}
}
。
$ awk -f tst.awk file{1..3}
A,B,C,D,E,F
10,20,10,20,,5
,20,10,20,5,10
,,,10,30,20