Perlのよく使うワンライナー(テキスト処理)

概要
Perlのワンライナー。
sedやawkでは扱いにくい、複雑な条件分岐や変換が必要なテキスト加工(CSVファイル処理など)に適している。UTF-8が標準化した現在では文字コード変換のニーズは減っているが、複雑な正規表現やPerlの組み込み機能を活用できる場面では有用である。
いろいろオプションはあるのだが、最小限に絞って備忘録的に。
よく使うオプション
基本
-e 'スクリプト': 実行するPerlスクリプトを指定(1行)
perl -e 'print "Hello"'
output:
Hello
入力が前提
-l:(入力から改行を取り除いたうえで最後に)出力結果を改行する。表示制御の目的で使われることが多い。データ加工の際は使わないほうが安全(使うとしても最後の処理として)。
perl -le 'print "Hello"'
output:
Hello
-n:ファイルを読み込んで1行ずつ(whileで)処理する。行の内容は特殊変数$_に格納される。
perl -ne 'func' file
は
perl -e 'open(FILE, "< file"); while(<FILE>) { func($_); }'
と同じことになる。
perl -ne 'print $.": ".$_' rand.txt
output:
1: 9
2: 4
3: 13
4: 53
5: 45
-p:-nに加えて結果の$_をprintする。sed -eみたいなことをするときに使う。
perl -pe 's/[0-3]/A/g' rand.txt
output:
9
4
AA
5A
45
-0777:入力を行ごとに区切らない。-pや-eと同時に用いられる。行ごとに変わるはずのない文字コード判別などの際に使う。
perl -MEncode::Guess -0777 -ne 'print guess_encoding($_, qw/shiftjis eucjp utf8/)->name' multibyte.txt
output:
utf8
-i ファイル名:ファイルの上書き-i拡張子 ファイル名:ファイルの上書き&拡張子付きのバックアップファイル生成
-iオプションは末尾(スクリプトの後)に記述すること。それ以外の位置だとマルチバイト文字を含む場合などうまくいかないことがある。
perl -pe 's/[0-3]/A/g' -i.bak rand.txt
CSVの処理
-a:Delimiter-separated valuesの処理。値は@Fに格納される-Fデリミタ:デリミタの指定(デフォルトの区切り文字はホワイトスペース)
行ループの-nと改行文字の削除-lをセットで使うのが普通なので、perl -lane 'コマンド'がセットになる。
perl -F, -lnae 'print $F[1]' log.txt
output:
20:03:06
20:03:07
20:03:07
perl -lnae '(@F[12..$#F] !~ /mobi/i && $F[8] != 200) && next; $,="\t"; print $F[0], $F[6]' ~/logs/access_log
output:
180.76.15.21 /
189.45.203.245 /user
220.181.108.160 /
185.92.73.125 /aaa/bbb.html
各オプションを実際のPerlのコードに対応させると
use strict; # -w
while(<STDIN>){ # -n
chomp($_); # -l
my @F = split(/ /, $_); # -a -F' '
print $_; # -p
}
拡張機能
-Mモジュール名:外部モジュールを指定
$ perl -MLWP::Simple -e 'getprint "http://example.com/"'
output:
<!doctype html>
<html>
<head>
<title>Example Domain</title>
<meta charset="utf-8" />
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style type="text/css">
:
</html>
ワンライナーではないが細かい処理でちょっと便利なメモ
常用対数を使いたいとき
log10(9999)はないのでlog(9999)/log(10)で代用する。
高度な算術演算子
5 % 3: 剰余5 ** 3: べき乗
特殊変数
$.: 現在の行番号$,:print引数のセパレータ$/: 入力(open)時の行区切り文字$\: 出力(print)時の行区切り文字$!: エラーの内容
参考になるワンライナーの例
置換
バックスラッシュをエスケープ
perl -pe 's/\\/\\\\/g;' customer.dat1 > customer.dat2
perl -pe 's/\\/\\\\/g;' -i customer.dat1
perlでCSVファイルの操作
perl -F/,/ -lane 'print $F[1]' data.csv > out
perl -F/,/ -lane 'print @F[1,2]' data.csv > out
# 一部の列を抽出して置換し、タブ区切りテキストとして出力
perl -lnae '$F[5] =~ s/aid=(\w+).*bid=(\w+).*/$1\t$2/g; $F[10] =~ s/.*([fgh]id=[\w\-]+).*/$1/g; $,="\t"; print $F[5], $F[9], $F[10], $F[11]' 123456.log > 123456.txt
文字コード変換
EUC-JPからUTF-8に変換する場合。
perl -MEncode -pe '$_ = encode("utf8", decode("eucjp", $_))' data1.txt > data2.txt
perl -MEncode -pe 'Encode::from_to($_, "eucjp", "utf8");' data1.txt > data2.txt
encode()は戻り値として変換した文字列を返す関数。
from_to()は$_自体を変換する関数。
ファイル自体を上書き(バックアップは保存)する
perl -MEncode -pe '$_ = encode("utf8", decode("eucjp", $_))' -i.bak data1.txt
その他の置換処理など続けて記述することができる。
perl -MEncode -pe '$_ = encode("utf8", decode("eucjp", $_)); $_ =~ s/
/
/g;' -i.bak data1.txt
文字コード判別
perl -MEncode::Guess -0777 -ne 'print guess_encoding($_, qw/shiftjis eucjp utf8/)->name' data1.txt
現在のディレクトリ直下の全ファイルに対して文字コード自動判別からのUTF-8への置換と改行コード置換
perl -MEncode -MEncode::Guess -0777 -pe '$_ = encode("utf8", decode(guess_encoding($_, qw/shiftjis eucjp/)->name, $_)); $_ =~ s/
/
/g;' -i.bak ./*
