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

概要

Perlのワンライナー。 sedawkでは扱いにくい、複雑な条件分岐や変換が必要なテキスト加工(CSVファイル処理など)に適している。UTF-8が標準化した現在では文字コード変換のニーズは減っているが、複雑な正規表現やPerlの組み込み機能を活用できる場面では有用である。 いろいろオプションはあるのだが、最小限に絞って備忘録的に。

  • -e 'スクリプト': 実行するPerlスクリプトを指定(1行)
perl -e 'print "Hello"'
perl

output:

Hello
perl
  • -l:(入力から改行を取り除いたうえで最後に)出力結果を改行する。表示制御の目的で使われることが多い。データ加工の際は使わないほうが安全(使うとしても最後の処理として)。
perl -le 'print "Hello"'
perl

output:

Hello
perl
  • -n:ファイルを読み込んで1行ずつ(whileで)処理する。行の内容は特殊変数$_に格納される。
perl -ne 'func' file
perl

perl -e 'open(FILE, "< file"); while(<FILE>) { func($_); }'
perl

と同じことになる。

perl -ne 'print $.": ".$_' rand.txt
perl

output:

1: 9
2: 4
3: 13
4: 53
5: 45
perl
  • -p-nに加えて結果の$_printする。sed -eみたいなことをするときに使う。
perl -pe 's/[0-3]/A/g' rand.txt
text

output:

9
4
AA
5A
45
perl
  • -0777:入力を行ごとに区切らない。-p-eと同時に用いられる。行ごとに変わるはずのない文字コード判別などの際に使う。
perl -MEncode::Guess -0777 -ne 'print guess_encoding($_, qw/shiftjis eucjp utf8/)->name' multibyte.txt
perl

output:

utf8
perl
  • -i ファイル名:ファイルの上書き
  • -i拡張子 ファイル名:ファイルの上書き&拡張子付きのバックアップファイル生成

-iオプションは末尾(スクリプトの後)に記述すること。それ以外の位置だとマルチバイト文字を含む場合などうまくいかないことがある。

perl -pe 's/[0-3]/A/g' -i.bak rand.txt
text
  • -a:Delimiter-separated valuesの処理。値は@Fに格納される
  • -Fデリミタ:デリミタの指定(デフォルトの区切り文字はホワイトスペース)

行ループの-nと改行文字の削除-lをセットで使うのが普通なので、perl -lane 'コマンド'がセットになる。

perl -F, -lnae 'print $F[1]' log.txt
perl

output:

20:03:06
20:03:07
20:03:07
perl
perl -lnae '(@F[12..$#F] !~ /mobi/i && $F[8] != 200) && next; $,="\t"; print $F[0], $F[6]' ~/logs/access_log
text

output:

180.76.15.21    /
189.45.203.245  /user
220.181.108.160 /
185.92.73.125   /aaa/bbb.html
perl

各オプションを実際のPerlのコードに対応させると

use strict; # -w
while(<STDIN>){ # -n
    chomp($_); # -l
    my @F = split(/ /, $_); # -a -F' '
    print $_; # -p
}
perl
  • -Mモジュール名:外部モジュールを指定
$ perl -MLWP::Simple -e 'getprint "http://example.com/"'
shell-session

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>
perl

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
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
perl

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
perl

encode()は戻り値として変換した文字列を返す関数。 from_to()$_自体を変換する関数。 ファイル自体を上書き(バックアップは保存)する

perl -MEncode -pe '$_ = encode("utf8", decode("eucjp", $_))' -i.bak data1.txt
perl

その他の置換処理など続けて記述することができる。

perl -MEncode -pe '$_ = encode("utf8", decode("eucjp", $_)); $_ =~ s/
/
/g;' -i.bak data1.txt
perl
perl -MEncode::Guess -0777 -ne 'print guess_encoding($_, qw/shiftjis eucjp utf8/)->name' data1.txt
perl

現在のディレクトリ直下の全ファイルに対して文字コード自動判別からのUTF-8への置換と改行コード置換

perl -MEncode -MEncode::Guess -0777 -pe '$_ = encode("utf8", decode(guess_encoding($_, qw/shiftjis eucjp/)->name, $_)); $_ =~ s/
/
/g;' -i.bak ./*
perl