Perl Advent Calenderなんと2020年になってもやってます。めでたいですね。
昨日は@narita_cppによるPaws::S3 で ECS タスクロールを用いてS3へファイルをアップロードするでした。
さて、今回はPerlワンライナー小技集ということで、先日Perl Hackers Hubに寄稿した記事の没ネタ落ち穂拾いです。
historyから引っ張ってきた小技をいくつか紹介します。
電卓
地味に面倒なのですがperlだと楽ちんです。
たとえば、$1.12/hourのSaaSを1ヶ月(30日)利用した際の日本円換算を雑にやるにはこう。
$ perl -E 'say 1.12 * 24 * 30 * 104.22'
-E
は引数をperlコードとして評価するやつで、featureプラグマの一部が有効になります。
よくわかんない方はこちらをどうぞ: コマンドラインツールとしてのperl
秒間リクエスト数をリアルタイムに計測する
アクセスログと tail -F
との組み合わせでお手軽にできます。
$ tail -F /var/log/nginx/access.log | perl -nE 'if($t!=time){say$c;$c=0;$t=time}$c++'
で、なにやっているんでしょうこれ。分解してみましょう。
-nE
は -n
と -E
をまとめて書いています。
-n
はループするやつです。-E
はさっきも出たので割愛します。
詳しいことはperldocを見てください。
つまり-MO=Deparse
で展開するとこうなります。
LINE: BEGIN { # これは -E オプションのやつ
$^H{'feature_say'} = q(1);
$^H{'feature_state'} = q(1);
$^H{'feature_switch'} = q(1);
}
while (defined($_ = <ARGV>)) { # これは -n オプションのやつ
if ($t != time) {
say $c;
$c = 0;
$t = time;
}
++$c;
}
見たままですが$c
という変数をカウンタにしつつ$t
という変数に時刻(epoch)を入れて、それが変わったタイミングで1秒経ったと判断して$c
を出力して$c
と$t
をリセットするというループです。
秒間に見た行数を毎秒出してくれるので簡易的な秒間リクエスト数のリアルタイム表示に利用できます。
設定用JSONから特定の設定をまるっとキレイに消す術
$ perl -i -ne 'print unless m!^ {8}"hoge":\s*\{\s*$! .. m!^ {8}\},\s*$!' data/fuga/**/*.json
正しく2スペースインデントされているJSONの、4インデント目の"hoge"
という名前のエントリを削除します。
JSON decodeして消してJSON encodeして保存とかできたら楽なんですが、設定ファイルのものともなると厳しい場合があります。JSONCやJSON5などコメントが書ける場合などもつらいです。
そこで、文字列処理としてワンライナーでやっつけるという苦肉の策をやってみたら案外うまくいきました。よかったですね。
-i
はinplaceつまり上書きのオプションですね。sedと同じです。
-ne
は -n
と -e
をまとめて書いています。
-n
はさっきもでてきたループするやつです。-e
は-E
のfeatureを設定しない版です。特に-e
にする理由もないですが-E
にする理由もないので書きやすいほうで書きました。
BEGIN { $^I = ""; } # これは -i オプションのやつ
LINE: while (defined($_ = <ARGV>)) { # これは -n オプションのループ
print $_ unless m[^ {8}"hoge":\s*\{\s*$] .. /^ {8}\},\s*$/;
}
m!^ {8}"hoge":\s*\{\s*$! .. m!^ {8}\},\s*$!
が謎ですね。
これはPerlの大変マイナーな演算子である範囲演算子(フリップフロップ演算子)と呼ばれるものです。
フリップフロップ演算子
範囲演算子..
は一般的には1 .. 10
のように数値の範囲を示して整数としての1
から10
までの連番のリストを表現するために使われる演算子です。
しかし、スカラコンテキストではsedのコンマ演算子(1,3
など)のように振る舞うために真偽値を返します。数値の場合は読込中のファイルの行数$.
に対して処理しますが、正規表現の場合は読み込んだファイルの行$_
に対して処理します。この特徴的な挙動を指して範囲演算子のスカラコンテキストでの用法はフリップフロップ演算子とも呼ばれます。
つまり、m!^ {8}"hoge":\s*\{\s*$! .. m!^ {8}\},\s*$!
はm!^ {8}"hoge":\s*\{\s*$!
にマッチする行から m!^ {8}\},\s*$!'
にマッチする行まで真になります。
対象の行を取り除くにはprint unless
で逆の条件にしてprint
すればよいというわけです。
詳細はperldocを読みましょう: http://perldoc.jp/docs/perl/5.26.1/perlop.pod#Range32Operators
もう少し紹介しようと思ったど長くなってきたのでこのへんで。明日は@xtetsujiさんです。お楽しみに!