外部ベンダーは、* .csvファイル形式で20を超えるテーブルのデータダンプを提供しました。文書が不足しているため、RDBMSの意味で「関連」ファイルを見つけるには、ファイルを手動で参照する必要があります。どのファイルに同じ文字列パターンがあるかを見つけて、きれいに印刷する方法はありますか?
現在私はこれを行い、手動で接続しています。
$> head -n 1 *.csv
これは私に次のような結果を与えます
==> EVO_ANGLE.csv <==
"evo_ang_id","angle_description"
==> EVOP_IMAGE.csv <==
"evop_image_id","evop_id","evo_ang_id","evo_collection","file_format","image_name","image_path", "image_type"
==> IMAGE_TYPE.csv <==
"id","image_type","group","description"
ご覧のとおり、ファイルとEVO_ANGLE
は関連しており、EVOP_IMAGE
共通点があります。evo_ang_id
EVOP_IMAGE
IMAGE_TYPE
image_type
この情報を印刷するより良い方法はありますか?各ファイルについて、そのフィールドを持つ他のファイルをどこで確認できますか?
これに対する最善の解決策は、以下を順番に実行するシェルスクリプトを作成することです。
- 各ファイルの最初の行を取得し、配列のマップに保存します。
- 各行の各単語について、配列内のその単語が表示される場所を探します。
- この情報を集めて印刷します。
これは面倒なことであり、正常に動作するには多くのデバッグが必要で、コンソール出力を表示する方が速いかもしれません。もっと良い方法がありますか? Cut / Join / Grepの組み合わせに関するヒントはありますか?
答え1
特定の属性が属するファイルを探している場合は、使用できますawk
。
csv
ファイルが次のようになっているとします。
$ for i in *.csv; do echo $i; head -n1 $i; echo; done
EVO_ANGLE.csv
"evo_ang_id","angle_description"
EVOP_IMAGE.csv
"evop_image_id","evop_id","evo_ang_id","evo_collection","file_format","image_name","image_path", "image_type"
IMAGE_TYPE.csv
"id","image_type","group","description"
次のawk
コマンドは、属性とファイル名を逆に変更します。
$ awk -F', *' ' # field separator = comma and optional spaces
FNR==1{ # Parse only the first line of each file.
for(i=1;i<=NF;i++) # Loop through all fields, and store them
a[$i]=a[$i] " " FILENAME # in an array together with the filename.
}
END{ # When all files parsed,
for(i in a) print i,a[i] # print the content of the array
}' *.csv
"image_name" EVOP_IMAGE.csv
"evo_collection" EVOP_IMAGE.csv
"image_path" EVOP_IMAGE.csv
"file_format" EVOP_IMAGE.csv
"image_type" EVOP_IMAGE.csv IMAGE_TYPE.csv
"evop_id" EVOP_IMAGE.csv
"evop_image_id" EVOP_IMAGE.csv
"id" IMAGE_TYPE.csv
"evo_ang_id" EVO_ANGLE.csv EVOP_IMAGE.csv
"description" IMAGE_TYPE.csv
"group" IMAGE_TYPE.csv
"angle_description" EVO_ANGLE.csv
複数のファイルに属する属性をフィルタリングする必要がある場合は、次のコマンドを使用します。
$ awk -F', *' 'FNR==1{for(i=1;i<=NF;i++) a[$i]=a[$i] " " FILENAME}END{for(i in a) print i,a[i]}' *.csv | awk 'NF>2'
"image_type" EVOP_IMAGE.csv IMAGE_TYPE.csv
"evo_ang_id" EVO_ANGLE.csv EVOP_IMAGE.csv
答え2
これはbash中心のバージョンと非常に似ているようです。オリーブのawkバージョン
unset fileheads fields
declare -A fileheads
declare -A fields
for f in *.csv
do
IFS=, fileheads[$f]=$(head -n1 "$f");
set -f
for field in ${fileheads[$f]}
do
fields[$field]+=x
done
set +f
done
for field in ${!fields[*]}
do
[[ ${#fields[$field]} -gt 1 ]] || continue
for file in ${!fileheads[*]}
do
[[ ${fileheads[$file]} =~ $field ]] && echo "$file has $field"
done
echo
done
これにより、各ファイル(行1)のフィールドがfileheads
ファイル名で索引付けされた連想配列に収集されます。また、各フィールド名の発生回数のリストを収集します。ここでは、フィールド名自体にカンマが表示されないと仮定します。
次に、既知のすべてのフィールドを繰り返します。いずれかが複数回表示される場合は、ファイル(配列のインデックスfileheads
)を繰り返して、対応するフィールドが含まれていることを確認します。読みやすくするために、少なくとも2つのファイルがこの基準を満たす必要があり、そのファイル名とリンクフィールドがエコーされ、その後に空白行が表示されます。
実行例:
入力する
$ head -n1 *.csv
==> EVOP_IMAGE.csv <==
"evop_image_id","evop_id","evo_ang_id","evo_collection","file_format","image_name","image_path","image_type"
==> EVO_ANGLE.csv <==
"evo_ang_id","angle_description"
==> IMAGE_TYPE.csv <==
"id","image_type","group","description"
出力
EVOP_IMAGE.csv has "evo_ang_id"
EVO_ANGLE.csv has "evo_ang_id"
EVOP_IMAGE.csv has "image_type"
IMAGE_TYPE.csv has "image_type"