カテゴリー
[Awk & Jq活用講座] CSVファイルで読み出した文字列を複雑なルールで置換したい
※ 当ページには【広告/PR】を含む場合があります。
2021/03/19
基礎テク〜CSVをファイルから/ヒアドキュメントから読み出す
cat
$ cat hoge.csv
#👇hoge.csvファイルの中身
1,2,3,4,5
6,7,8,9,10
$ cat << EOF
1,2,3,4,5
6,7,8,9,10
EOF
#👇csvデータとして取り扱える
1,2,3,4,5
6,7,8,9,10
CSV_DATA
echo
$ CSV_DATA=$(cat << EOF
1,2,3,4
5,6,7,8
EOF
)
#👇改行を含む文字列のechoでは変数をダブルクオーテーション(")で囲う必要がある
$ echo "$CSV_DATA" | awk -F"," '{ print $0; }'
1,2,3,4
5,6,7,8
$ awk -F"," '{ print $0; }' << EOF
1,2,3,4
5,6,7,8
EOF
Awkによる置換の基礎
Awk
gsub
用法:
gsub(<置換前の文字パターン>,<置換後の文字パターン>,<対象文字列>)
sub
$ awk -F"," '
BEGIN { OFS="," }
{
#一列目の文字($1)を / から - に置き換え
gsub("/", "-", $1);
print $1, $2, $3;
}' << EOF
2021/04/06,出張,山田
2021/04/08,会議,佐藤
2021/04/17,リモートワーク,鈴木
EOF
#👇出力
2021-04-06,出張,山田
2021-04-08,会議,佐藤
2021-04-17,リモートワーク,鈴木
$ awk -F"," '
BEGIN { OFS="," }
{
gsub(/[0-9]{4}\/[0-9]{2}\/[0-9]{2}/, "----/--/--(未定)", $1);
print $1, $2, $3;
}' << EOF
2021/04/06,出張,山田
2021/04/08,会議,佐藤
2021/04/17,リモートワーク,鈴木
EOF
#👇出力
----/--/--(未定),出張,山田
----/--/--(未定),会議,佐藤
----/--/--(未定),リモートワーク,鈴木
gensub
用法:
gensub(<置換前の文字パターン>,<置換後の文字パターン>,<n番目 or "g"で全て置き換え>,<対象文字列>)
(...)
\\1
\\2
$ awk -F"," '
BEGIN { OFS="," }
{
date_ = gensub(/[0-9]{4}\/([0-9]{2})\/([0-9]{2})/, "\\1月\\2日", "g", $1);
print date_, $2, $3;
}' << EOF
2021/04/06,出張,山田
2021/04/08,会議,佐藤
2021/04/17,リモートワーク,鈴木
EOF
#👇出力
04月06日,出張,山田
04月08日,会議,佐藤
04月17日,リモートワーク,鈴木
Jqによる置換の基礎
$ jq -sR '
#👇mapを使うために配列化のために([...])でラップする
[
#👇改行位置で配列に変換し、中身を取り出す
split("\n")[]
#👇空文字を弾く
| select(length > 0)
#👇コンマ切りで配列に変換する
| split(",")
]
#👇mapで配列の中身をjson要素に変換する
| map({"日付": .[0], "予定": .[1], "担当": .[2]})
' << EOF
2021/04/06,出張,山田
2021/04/08,会議,佐藤
2021/04/17,リモートワーク,鈴木
EOF
#👇出力
[
{
"日付": "2021/04/06",
"予定": "出張",
"担当": "山田"
},
{
"日付": "2021/04/08",
"予定": "会議",
"担当": "佐藤"
},
{
"日付": "2021/04/17",
"予定": "リモートワーク",
"担当": "鈴木"
}
]
-R
-s
$ jq -sR '
[
split("\n")[]
| select(length > 0)
| split(",")
]
| map(.[0] |= gsub("/"; "-"))
| map({"日付": .[0], "予定": .[1], "担当": .[2]})
' << EOF
2021/04/06,出張,山田
2021/04/08,会議,佐藤
2021/04/17,リモートワーク,鈴木
EOF
#👇出力
[
{
"日付": "2021-04-06",
"予定": "出張",
"担当": "山田"
},
{
"日付": "2021-04-08",
"予定": "会議",
"担当": "佐藤"
},
{
"日付": "2021-04-17",
"予定": "リモートワーク",
"担当": "鈴木"
}
]
$ jq -sR '
[
split("\n")[]
| select(length > 0)
| split(",")
]
| map(.[0] |= (capture("[0-9]{4}/(?<mon>[0-9]{2})/(?<day>[0-9]{2})") as $capt | $capt.mon + "月" + $capt.day + "日"))
| map({"日付": .[0], "予定": .[1], "担当": .[2]})
' << EOF
2021/04/06,出張,山田
2021/04/08,会議,佐藤
2021/04/17,リモートワーク,鈴木
EOF
#👇出力
[
{
"日付": "04月06日",
"予定": "出張",
"担当": "山田"
},
{
"日付": "04月08日",
"予定": "会議",
"担当": "佐藤"
},
{
"日付": "04月17日",
"予定": "リモートワーク",
"担当": "鈴木"
}
]
@csv
$ CONVERTED_JSON=$(cat << EOF
[
{
"日付": "04月06日",
"予定": "出張",
"担当": "山田"
},
{
"日付": "04月08日",
"予定": "会議",
"担当": "佐藤"
},
{
"日付": "04月17日",
"予定": "リモートワーク",
"担当": "鈴木"
}
]
EOF
)
$ echo "$CONVERTED_JSON" | jq -r '.[] | [.["日付"], .["予定"], .["担当"]] | @csv' | sed 's/"//g'
#👇出力
04月06日,出張,山田
04月08日,会議,佐藤
04月17日,リモートワーク,鈴木
"
応用 〜 置換ルールをCSVに登録して、文字列を一括置換する
1,壱
2,弐
3,参
4,肆
5,伍
6,陸
7,漆
8,捌
9,玖
1-4-3,4
7-5-2,3
9-2-3,6
7-4-1,9
1-4-7,8
awkの場合
$ cat << EOF > replace_rule.csv
1,壱
2,弐
3,参
4,肆
5,伍
6,陸
7,漆
8,捌
9,玖
EOF
$ cat << EOF > example.csv
1-4-3,4
7-5-2,3
9-2-3,6
7-4-1,9
1-4-7,8
EOF
$ awk -F "," '
BEGIN {
OFS=",";
count=0;
}
F == 0 {
before_arr[count] = $1;
after_arr[count] = $2;
count++;
next;
}
{
for (i = 0; i < count; i++ ) {
gsub(before_arr[i], after_arr[i], $1);
}
print $1, $2;
}
' F=0 replace_rule.csv F=1 example.csv
#👇置換した結果
壱-肆-参,4
漆-伍-弐,3
玖-弐-参,6
漆-肆-壱,9
壱-肆-漆,8
F
jqの場合
for...in
csv_data=$(jq -sR '
[ split("\n")[] | select(length > 0) | split(",") ]
' << EOF
1-4-3,4
7-5-2,3
9-2-3,6
7-4-1,9
1-4-7,8
EOF
)
replacing_map=$(jq -sR '
[ split("\n")[] | select(length > 0) | split(",") ]
| map({"before": .[0], "after": .[1]})
' << EOF
1,壱
2,弐
3,参
4,肆
5,伍
6,陸
7,漆
8,捌
9,玖
EOF
)
for item in $(echo "$replacing_map" | jq -c .[]); do
csv_data=$(echo "$csv_data" | jq -s --argjson item "$item" '
(.[][][0] |= gsub($item.before; $item.after))[]
')
done
echo "$csv_data" | jq -r '.[] | @csv' | sed 's/"//g'
#👇置換した結果
壱-肆-参,4
漆-伍-弐,3
玖-弐-参,6
漆-肆-壱,9
壱-肆-漆,8
(配列)[]
[[1],[2],[3]] > [1] [2] [3]
--argjson
$item
まとめ
参考サイト
記事を書いた人
ナンデモ系エンジニア
主にAngularでフロントエンド開発することが多いです。 開発環境はLinuxメインで進めているので、シェルコマンドも多用しております。 コツコツとプログラミングするのが好きな人間です。
カテゴリー