0. はじめに
本稿はWanoグループ Advent Calendar 2020 14日目の投稿になります。
ラクダ本1の緒言にもあるようにPerlは"簡単な仕事を簡単にできるように設計されている"ので、日々のちょっとした作業、特にちょっとしたテキストファイルの処理をしたりする際に何かとお世話になっています。また、自分は怠惰なので、その場限りのちょっとした作業のためにスクリプトファイルを書くことをめんどくさがります。PerlはAwkのように、短い記述量で多くのことをこなしてくれるため、ワンライナーをパイプ処理の途中にねじ込むことも容易です。本稿では、そんな日々のちょっとした作業を楽にしてくれるかもしれないコマンドライン上でのPerlのスニペットやワンライナーを紹介します。
1. 普段使いのUnixコマンドのレパートリーにPerlを加える
多くのUnix (もしくは、Linux)環境において、Perlは標準で入っているので、特別なセットアップ作業等の必要はありません。最初からperlコマンドが使える環境がほとんどです。標準外のCPAN Moduleが使うようなことが無いのであれば、何も特別な準備は必要ないでしょう。尤も、CPAN Moduleを使わないのであれば、awkやsedで事足りる場合が多いので、よりPerlで怠惰に作業をこなすために自由にCPAN Moduleを導入・管理できる環境を軽く整えておくのがよいでしょう。とはいえ、これも、標準のcpanコマンドよりちょっと便利なcpanminus2をインストールして、ホーム直下にでもcpanfileを置いて、それでモジュールを管理する程度で十分でしょう (nodejsにおけるnpmとglobalのpackage.jsonみたいなものですね)。
また、本稿ではperlの文法や起動オプションについては特に解説してないので、不明点については、perlのドキュメント3や本稿末尾に記載の書籍4,5等を適宜参照してください。
2. Perlによるテキスト処理あれこれ
今回はサンプルとしてSpotify Charts6からダウンロードできるCSVファイルを使用します。とりあえず、2020/12/01付けの日本のTOP 200チャートのデータを取得して、中身を確認してみます。
$ curl -s https://spotifycharts.com/regional/jp/daily/2020-12-01/download -o spotify.top200.daily.jp.20201201.csv
$ head spotify.top200.daily.jp.20201201.csv
中身(headの出力)はこんな感じ
,,,"Note that these figures are generated using a formula that protects against any artificial inflation of chart positions.",
Position,"Track Name",Artist,Streams,URL
1,Dynamite,BTS,309097,https://open.spotify.com/track/4saklk6nie3yiGePpBwUoc
2,炎,LiSA,301412,https://open.spotify.com/track/0cSkn2l67csUljEy0EEBPn
3,夜に駆ける,YOASOBI,247609,https://open.spotify.com/track/3dPtXHP0oXQ4HCWHsOA9js
4,ドライフラワー,優里,221340,https://open.spotify.com/track/7dH0dpi751EoguDDg3xx6J
5,虹,"Masaki Suda",211879,https://open.spotify.com/track/7AIj86wFWqm7X1TZ2hzHwS
6,"Stand by me, Stand by you.",HIRAIDAI,211637,https://open.spotify.com/track/2RbVD1IgXtyQFlLtbthaZ3
7,"Step and a step",NiziU,202135,https://open.spotify.com/track/5DgAgJbHcm74RyA9YKj6k1
8,"Make you happy",NiziU,177733,https://open.spotify.com/track/4FrxgrNbNrdfq8093JaEJf
左詰めで見にくいので、perlを使って見やすい感じに整形しましょう。エクセルで開けばいいのでは?と思うかもしれませんが、自分は怠惰なのでターミナルから離れることすらめんどうなのです。後は、結果を | vim -
でvimに渡して、そのままごにょごにょできるのでコマンドライン上でやる方が何かと便利だったりします。
tail -n +2 spotify.top200.daily.jp.20201201.csv \
| head \
| perl -CS -MText::CSV=csv -E '$,="\t";@csv = @{csv(in => *STDIN)};map { say @{$_} } @csv' \
| column -tn -s $'\t'
Position Track Name Artist Streams URL
1 Dynamite BTS 309097 https://open.spotify.com/track/4saklk6nie3yiGePpBwUoc
2 炎 LiSA 301412 https://open.spotify.com/track/0cSkn2l67csUljEy0EEBPn
3 夜に駆ける YOASOBI 247609 https://open.spotify.com/track/3dPtXHP0oXQ4HCWHsOA9js
4 ドライフラワー 優里 221340 https://open.spotify.com/track/7dH0dpi751EoguDDg3xx6J
5 虹 Masaki Suda 211879 https://open.spotify.com/track/7AIj86wFWqm7X1TZ2hzHwS
6 Stand by me, Stand by you. HIRAIDAI 211637 https://open.spotify.com/track/2RbVD1IgXtyQFlLtbthaZ3
7 Step and a step NiziU 202135 https://open.spotify.com/track/5DgAgJbHcm74RyA9YKj6k1
8 Make you happy NiziU 177733 https://open.spotify.com/track/4FrxgrNbNrdfq8093JaEJf
9 裸の心 Aimyon 176070 https://open.spotify.com/track/4Jv7U0JJpbQnOrjtDwDZTZ
見やすい。csvからtsvへの変換は、sed -E 's/("([^"]*)")?,/\2\t/g'
のような正規表現でもいいのですが、自分はいちいち覚えてられないので、Text::CSV Moudle7を使ってます。ワンライナーでも使いやいのでお勧めのMoudleです。テーブル整形の部分は、個人的にcolumn
コマンドが好きなのでこれを使っていますが、Text::Table::Tiny8みたいなModuleを使ってもいいかもしれないですね。
続いて、チャートインの多いアーティストとその合計Stream数をさくっと確認してみましょう。
tail -n +2 spotify.top200.daily.jp.20201201.csv \
| perl -CS -MText::CSV=csv -E '$,="\t";@csv = @{csv(in => *STDIN)}; map { say @{$_} } @csv' \
| perl -CS -F'\t' -alE '$h{$F[2]}++; $j{$F[2]}+=$F[3]; END { $,="\t"; map { say $_, $h{$_}, $j{$_} } keys %h }' \
| sort -t $'\t' -k2 -k3 -nr \
| column -nt -s $'\t' \
| head -n 20
BTS 14 1024687
Official HIGE DANdism 9 925246
back number 9 395498
King Gnu 7 450881
Mrs. GREEN APPLE 6 475984
Kenshi Yonezu 6 360720
TWICE 6 307827
YOASOBI 5 647537
NiziU 5 471590
Aimyon 5 449613
HIRAIDAI 5 346069
Masaki Suda 4 376490
ヨルシカ 4 264116
ONE OK ROCK 4 121369
ARASHI 4 117007
LiSA 3 525058
もさを。 3 189626
Vaundy 3 181857
BLACKPINK 3 113619
Ariana Grande 3 96995
少々タイプ数が多いですが、慣れればこのくらいまでは思考停止で書けるようになると思います。LiSAがチャートイン楽曲数3つで、チャートイン楽曲数7のKing GnuのStream合計を超えてるのすごいですね(感想)。
後は、あまりやらないですが、CSVをJSONに変換してみます。
tail -n +2 spotify.top200.daily.jp.20201201.csv \
| perl -CI -MText::CSV=csv -MJSON::PP=encode_json -E '$,="\t";@csv = @{csv(in => *STDIN, headers => "auto")}; say encode_json([@csv[0..2]]);' \
| jq .
[
{
"Artist": "BTS",
"Streams": "309097",
"URL": "https://open.spotify.com/track/4saklk6nie3yiGePpBwUoc",
"Position": "1",
"Track Name": "Dynamite"
},
{
"Streams": "301412",
"Artist": "LiSA",
"URL": "https://open.spotify.com/track/0cSkn2l67csUljEy0EEBPn",
"Position": "2",
"Track Name": "炎"
},
{
"Position": "3",
"URL": "https://open.spotify.com/track/3dPtXHP0oXQ4HCWHsOA9js",
"Streams": "247609",
"Artist": "YOASOBI",
"Track Name": "夜に駆ける"
}
]
CSVをJSONに変換したいということはあまりないかもしれませんが、逆に、JSONをテーブル形式で見たいことは結構あるので、以下のようなワンライナーはよく使います。
bash ./csv2json.sh > csv2json.output.json
cat csv2json.output.json \
| perl -CO -MJSON::PP=decode_json -E '$json = join("", <>); @h = ("Track Name", "URL"); @json = @{decode_json($json)}; $,="\t"; say @h; map { say @$_{@h} } @json' \
| column -tn -s $'\t'
Track Name URL
Dynamite https://open.spotify.com/track/4saklk6nie3yiGePpBwUoc
炎 https://open.spotify.com/track/0cSkn2l67csUljEy0EEBPn
夜に駆ける https://open.spotify.com/track/3dPtXHP0oXQ4HCWHsOA9js
ドライフラワー https://open.spotify.com/track/7dH0dpi751EoguDDg3xx6J
虹 https://open.spotify.com/track/7AIj86wFWqm7X1TZ2hzHwS
Stand by me, Stand by you. https://open.spotify.com/track/2RbVD1IgXtyQFlLtbthaZ3
Step and a step https://open.spotify.com/track/5DgAgJbHcm74RyA9YKj6k1
Make you happy https://open.spotify.com/track/4FrxgrNbNrdfq8093JaEJf
裸の心 https://open.spotify.com/track/4Jv7U0JJpbQnOrjtDwDZTZ
紅蓮華 https://open.spotify.com/track/0qMip0B2D4ePEjBJvAtYre
実際には、jqでざっくりフィルタリングしてからPerlに突っ込むことが多いですね。JSON Moduleを使うときは内部文字コード変換が入るので、-C
オプションの値に注意が必要です。
3. おわりに
PerlやPythonのように大体の環境に標準で入ってるスクリプト言語をアーミーナイフとして使いこなせると何かと便利です。Perlは書いたことあるけど、コマンドラインドラインでは使わないという人は、せっかくなので、ワンライナーPerlについて色々と調べてみるとシェルでの生活がより良いものなるかもしれません。
-
L. Wall, T. Christiansen, J. Orwant: Programming Perl (Third Edition), O'Reill Media, Inc., 2000 (近藤嘉雪・訳: プログラミングPerl 第3版 Volume 1, O'Reilly Japan, 2002). ↩
-
perldoc perlrun
↩ -
T. Maher: Minimal Perl: For Unix and Linux People, Manning Publication, 2006 (安藤慶一, 磯部孝一郎・訳: ミニマルPerl, O'Reilly Japan, 2008). ↩
-
S. Agarwal: Perl one-lines cookbook [OnlineBook], 2020, Accessed 13 Dec. 2020. [Link]. ↩
-
Text::Table::Tiny, meta::cpan, Accessed 13 Dec. 2020 [Link] ↩