2つのファイルを比較しfile a
てfile b
同じ列を使用する必要がありますが、列の値の比較など、2つのファイルにランダムに配置する必要がありますaccount
。一致するレコードは次のとおりです。code
date
type
pc
vol
bs
account
file a
account1
file b
file a
file c
私はLinuxの背景知識がなく、オンラインフォーラムを検索した後、AWKでこれを行うことができることを少し知っていますが、awkには慣れていません。助けてください。 Linux環境では比較が必要です。
ランダムに配置された列は、コマンドがファイルaとファイルbを一致させるために使用できる列を提供できることを意味します(列の順序は両方のファイルで同じではありません)。どちらのファイルでも、一致する列は8、10、15のいずれかになります。
アカウントと同様に、account1は最初と最後の列ではなく、コマンドは更新する列を選択する必要があります。
繰り返し処理 -->ファイルbにファイルaの1つのレコードが重複している場合は、ファイルbの最初の一致レコードを更新して、一致で再利用できないようにする必要があります。 -->ファイルaに重複が多い場合、ファイルbに一致するレコードが1つしかない場合、最終ファイルcはファイルaの一致する値レコードをすべて更新するのではなく、アカウント値を1つだけ更新する必要があります。
file a
account,temp1,code,type,date,subtask,pc,toy,vol,bs,sub
6576,WEQR,TYRE,BS,54122022,OBCD,K,BAT,5000,F,SCSC
1234,GFHD,ASDF,BS,21122022,STOP,C,CAT,1000,S,MATH
7654,GHAD,LOPI,CV,9089022,KGAD,G,BSEE,5908,J,IOYU
file b
account,code,date,type,inst,insttype,pc,str,vol,bs,name,xdate,account1
1234,ASDF,21122022,BS,GOLDY,RUB,C,123.1,1000,S,RON,90891234,CCCCC
2761,LOPCS,10122022,BSFD,SLV,STR,C,123.9,1001,B,RON,99999988,DDDDD
0980,RTDF,28822025,JUFG,BRNZ,HIY,C,123.8,2000,S,RON,88881234,EEEEE
file c
account,temp1,code,type,date,subtask,pc,toy,vol,bs,sub
6576,WEQR,TYRE,BS,54122022,OBCD,K,BAT,5000,F,SCSC
CCCCC,GFHD,ASDF,BS,21122022,STOP,C,CAT,1000,S,MATH
7654,GHAD,LOPI,CV,9089022,KGAD,G,BSEE,5908,J,IOYU
答え1
この回答は、以下を使用する解決策から始まります。ミラーcsvsql
、Millerのソリューションと一緒にMillerを使用し続けます。csvkitその後、使用されるソリューションで終わりますcsvsql
。
使用ミラー(mlr
)最初に(左)次に名前付きフィールドのデータを結合しますfileA
。fileB
account,code,date,type,pc,vol,bs
...その後、account1
フィールドの名前を変更しますaccount
(フィールドがあるレコードの場合は、account1
結合されたレコードのみ)。
次に、フィールドの順序を変更し、出力から不要なフィールドを削除します。
mlr --csv \
join -f fileA -j account,code,date,type,pc,vol,bs --ul then \
rename account1,account then \
cut -o -f account,temp1,code,type,date,subtask,pc,toy,vol,bs,sub fileB
質問のデータ出力を提供します。
account,temp1,code,type,date,subtask,pc,toy,vol,bs,sub
CCCCC,GFHD,ASDF,BS,21122022,STOP,C,CAT,1000,S,MATH
6576,WEQR,TYRE,BS,54122022,OBCD,K,BAT,5000,F,SCSC
7654,GHAD,LOPI,CV,9089022,KGAD,G,BSEE,5908,J,IOYU
両方の入力ファイルのフィールドの順序は関係ありません。
結合に使用できるフィールドがわからない場合は、共通フィールド名を個別に計算できます(残念ながら、Millerは「自然結合」操作を実行できませんが、結合するフィールド名の明示的なリストを提供する必要があります)。
mlr --csv put -q '
if (NR == 1) {
for (k in $*) { @f[k] = 1 }
} else {
for (k in @f) {
is_null($[k]) { unset @f[k] }
}
}
end {
common_fieldnames = joink(@f,",");
emit common_fieldnames
}' fileA fileB
与えられたデータに対して次のCSVデータセットを出力します。
common_fieldnames
"account,code,type,date,pc,vol,bs"
到着ただ--csv
と結合されているように、ヘッダーがなく、引用符なしのCSV出力を生成するオプションを使用して、カンマ区切りリストを取得します。--headerless-csv-output
--quote-none
まったく異なるアプローチcsvsql
はcsvkit自然左結合を実行し、出力を後処理するmlr
ために使用されます。
csvsql --query 'SELECT * FROM "fileA" NATURAL LEFT JOIN "fileB"' fileA fileB |
mlr --csv \
put 'is_not_null($account1) { $account = $account1 }' then \
cut -o -f account,temp1,code,type,date,subtask,pc,toy,vol,bs,sub
これにより、2つのファイル間でどのフィールドが共通であるかを心配する必要がなくなります。
必要に応じて、SQLを使用してすべての操作を実行できます。
csvsql --query '
CREATE TEMPORARY TABLE tmp AS SELECT * FROM "fileA" NATURAL LEFT JOIN "fileB";
UPDATE tmp SET account = account1 WHERE account1 IS NOT NULL;
SELECT account,temp1,code,type,date,subtask,pc,toy,vol,bs,sub FROM tmp;' fileA fileB
答え2
#!/bin/bash
IFS=, hdrs_to_check="$*"
col_to_change="account"
col_with_value="account1"
awk -F, -v hdrs_to_check="$hdrs_to_check" \
-v col_to_change="$col_to_change" \
-v col_with_value="$col_with_value" '
function make_compound_key(hdrs_2_idx_map) {
key = ""
for (i = 1; i <= hdrs_to_check_arr_size; i++) {
hdr_name = hdrs_to_check_arr[i]
hdr_idx = hdrs_2_idx_map[hdr_name]
key = key$hdr_idx","
}
return key
}
BEGIN {
hdrs_to_check_arr_size = split(hdrs_to_check, hdrs_to_check_arr, ",")
}
#Both file headers processing
FNR == 1 {
#Map file_a and file_b headers to their indexes.
for (i = 1; i <= NF; i++) {
if (NR == 1) {
f_b_hdr_2_idx_map[$i] = i
} else {
f_a_hdr_2_idx_map[$i] = i
}
}
next
}
#file_b processing
FNR == NR {
key = make_compound_key(f_b_hdr_2_idx_map)
# Duplicate keys are not changing the "account1" value, it is fixed
# from the first key occurence.
if (!(key in file_b_dct)) {
file_b_dct[key] = $f_b_hdr_2_idx_map[col_with_value]
}
next
}
#file_a processing
FNR != NR {
key = make_compound_key(f_a_hdr_2_idx_map)
# "file_a_updated_dct" is needed to prevent following lines
# with same "key" be changed. These lines are left unchanged.
if ((key in file_b_dct) && !(key in file_a_updated_dct)) {
$f_a_hdr_2_idx_map[col_to_change] = file_b_dct[key]
file_a_updated_dct[key]
}
print
}
' file_b.txt OFS=, file_a.txt
#' file_b.txt OFS=, file_a.txt | column -s, -t
使用法:
$ ./my_script.sh account code date type pc vol bs