Perlにはコマンドライン引数としてスクリプトその物を指定する事が出来る-eオプションが有ります。
Perlではこの仕組みを使ってスクリプトをお手軽に実行する事を通称ワンライナー(One Liner)と呼んでいます。コマンドライン上で指定するので、多くは1行以内にスクリプトが収まっている事からこの様に呼ばれていますが、実際には複数行を指定する事も出来ます。日本語では「1行野郎」と訳する事が多いようです。
-eオプションの最も基本的な使い方
1つの-eオプションにまとめて指定
複数の-eオプションにそれぞれ指定
他の引数と組み合わせて使う
-nオプションでwhileを補う
-lオプションで読み込み時の改行削除と、書き込み時の改行追加を補う
-pオプションで自動出力
-CオプションでUTF-8文字列を扱う
モジュールの読み込み指定
その他のオプション引数
-aFオプションで入力された行を自動的に分割
-iオプションで入力された結果を入力元へ書き戻す
簡単な実行例を見てみましょう。基本はコマンドライン引数-eに続けて実行したいスクリプトをクォートして指定します。
$ perl -e 'print "Hello, World\n"'
Hello, World
冒頭でも触れましたが、One Linerと言いながらスクリプトは複数行書く事も出来ます。一つの-e引数の中に複数行のスクリプトを書いてもOKですし、-e引数を複数回指定して、それぞれ1行ずつスクリプトを書いてもOKです。
$ perl -e 'print "Hello, World\n"; print "Hello, World again\n"'
Hello, World
Hello, World again
$ perl -e 'print "Hello, World\n";' \
> -e 'print "Hello, World again\n"'
Hello, World
Hello, World again
これだけでは余り便利さは感じませんが、他のコマンドライン引数と組み合わせると、どんどん便利になっていきます。
perlコマンドの-nオプションは指定したスクリプト全体がwhile(<>) {}で囲んで実行してくれる引数です。
$ more newfile.txt
aaa
bbb
ccc
$ perl -ne 'print if /a/' newfile.txt
aaa
ちなみに-eオプションと無関係に使う事も出来ますが、実際には普通のスクリプトで使う事はまず無いでしょう。
while構文を使って行単位にテキストファイルを処理する際には、読み込み時に改行削除(chomp関数)を行い、書き込み時に改行追加(\n)を行う事が多いと思いますが、これも自動的にやってくれるオプションが有ります。
-nオプション(または、後述する-pオプション)と-lオプションを組み合わせると、自動的に特殊変数$_にchomp関数が適用されます。またprintする時に自動的に改行が追加されます(実際には$/の内容が$\にコピーされて、その内容が付加されるだけですが...詳細はリファレンスを参照して下さい)。
以下は、読み込んだCSVの項目順を逆転させるスクリプトの例です。余計な改行を上手く処理してくれています。
$ more sample.csv
aaa,0001
bbb,0002
ccc,0003
$ perl -nle "print join ',',(reverse split /,/)" sample.csv
0001,aaa
0002,bbb
0003,ccc
-nオプションは、スクリプト全体にwhile(<>) {}を補ってくれましたが、-pオプションでは$_の自動出力が加わります。つまり、スクリプト全体にwhile(<>) {} continue {print;}を補ってくれます(printの引数が省略されているので、特殊変数$_の内容が出力されます)。
以下は、読み込んだCSVの項目の区切り文字をタブに置き換えて出力するスクリプトの例です。特殊変数$_を書きかえる事で、タブに置き換えた内容を自動的に出力してくれます(自分で$_を書き変えていますが、直接printした方が早い気もしますね)。
$ more sample.csv
aaa,001
bbb,002
ccc,003
$ perl -ple '$_ = join "\t",(split /,/)' sample.csv
aaa 001
bbb 002
ccc 003
Perl v5.8.1以降で使用できるオプションです。Perlでは文字列にutf8フラグが立っていないと文字として正しく認識できず、文字数のカウントや正式表現によるマッチングが出来ません(utf8フラグが無いスカラー変数の文字列は単なるバイト列として扱われる)。
標準入出力や、PerlIOレイヤーのデフォルト設定をUTF-8に設定する事でutf8フラグの上げ下げ(入力にはフラグを設定し、出力時にはフラグを落とす)を自動化する事が出来ます(ただし、UTF-8以外の文字コードを自動的に変換する事はできません)。
以下の例は-Cオプションを使ってutf8フラグを上げたパターンと、上げないパターンでの比較です。1行のカウント結果の数字が異なる事が分かると思います。
$ more sample.csv
aaa,001,あいう
bbb,002,かきくけ
ccc,003,さしすせそ
$ perl -Cio -nle 'print length' sample.csv
11
12
13
$ perl -nle 'print length' sample.csv
17
20
23
-Cオプションの後ろに続けて、何の入出力をUTF-8として取り扱うのか指定するオプションを指定します。オプションの意味を以下の表にまとめました。
| オプション | -Cの後ろの引数の意味 |
|---|---|
| I | 標準入力はUTF-8 |
| O | 標準出力はUTF-8 |
| E | 標準エラー出力はUTF-8 |
| S | I+O+Eと同じ |
| i | テキストの入力はUTF-8 (PerlIOレイヤーのデフォルトがUTF-8) |
| o | テキストの出力はUTF-8 (PerlIOレイヤーのデフォルトがUTF-8) |
| D | i+oと同じ |
| A | @ARGV(コマンドライン引数)がUTF-8 |
| L | ロケールが適切にUTF-8にセットされていれば、 I+O+E+i+o+Aと同じ |
最近のロケールがUTF-8化されている環境であれば、-CL指定が良いですね。
-Mオプションに引き続き、モジュール名を指定すると、スクリプト内でuseした事と同じ意味になります。Perlではモジュール無しにはスクリプトは書けないので必須の機能ですね。
$ perl -MTime::Piece -e 'print localtime->datetime."\n"'
2010-03-16T20:41:20
以降は自分では使った事無いのだけど、よく使われるらしいオプション引数を落ち葉拾い的に紹介。
CSV形式のデータをsplit関数で分解しながら処理する事が多いと思いますが、-aFオプションはそれを自動的に行ってくれる引数です。Fに引き続き区切り文字を指定すると、@F = split /{Fに指定した区切り文字}/と同じ動作になります。
以下の例は、入力されたCSVを区切り文字で分解して、間にタブを挟んで出力する例です。
$ more sample.csv
aaa,0001
bbb,0002
ccc,0003
$ perl -aF, -nle 'print join "\t",@F' sample.csv
aaa 0001
bbb 0002
ccc 0003
-iオプションは入力された内容を書き換えて、入力元へ書き戻す事が出来ます。
$ more sample.txt
aaa,001
bbb,002
ccc,003
$ perl -i -ple 's/,/\t/g' sample.txt
$ more sample.txt
aaa 001
bbb 002
ccc 003
-iに引き続いて、拡張子を指定すると書き換え前のバックアップを取る事も出来ます。
$ more sample.txt
aaa,001
bbb,002
ccc,003
$ perl -i.bak -ple 's/,/\t/g' sample.txt
$ more sample.txt
aaa 001
bbb 002
ccc 003
$ more sample.txt.bak
aaa,001
bbb,002
ccc,003

コメントする