Perl のコマンドラインハッシュ
Perlがインストールされたサーバへの通常ログイン、もしくはTELNETでのログイン権限を持っていれば、コマンドラインからPerlを呼び出してプログラムを実行させることができます。この場合は、出力結果はブラウザではなくコマンドプロンプトに表示されることになります。コマンドラインからのプログラム実行は、ブラウザを使う必要がないので、簡単なテストなどに最適です。
コマンドラインから Perlに対して指示するためのオプション指定のことをコマンドラインハッシュと呼びます。コマンドラインハッシュを利用することにより、コマンドラインからプログラムファイルを指定し、実行させる以外にも、直接コマンドライン上でプログラムを書き、実行させることができます。これがいわゆる1行スクリプトと呼ばれるものです。
いくつかのMS-DOSマシンなどでは、引数を囲むにはダブルクォートを持ち要らなければならないことに注意してください。
Perl インタプリタ
Perlの実行可能形式は Perl インタプリタと呼ばれています。通常の Perl プログラムは、Perl インタプリタ
によって実行されます。多くのPerl プログラムは、1行目が次のようになっています。
#! /usr/local/bin/perl
この #! の行は、/usr/local/bin/perlプログラムを探して、ファイルの残りの部分をそのプログラムに渡して実行できるようにシェルに伝えています。
Perlプログラムを書く際にはスクリプトの先頭に正しく #! の行を記述しておき、コマンド+xで実行可能に
しておく必要があります。
引数指定
コマンドプロンプトから、次のように入力してリターンキーを押してください。-eオプションは次に続く'...'をperlスクリプトとして実行することを意味します。
perl -e "print 'Hello world!!';"
ファイル指定
ファイル名 hello.pl を作成し、次のように入力します。
print "Hello world!!\n";
上記で作成したファイルの名前を引数にして、コマンドプロンプトから次のようにperlコマンドを実行することができます。
perl hello.pl
直接実行
これは UNIX でのみ使用可能な方法です。ファイル名 hello.plを作成し、次のように入力します。
#!/usr/local/bin/perl print "Hello world!!\n";
1行目は、perl コマンドが置かれているディレクトリに応じて変更します。#!というのはUNIXのファイル特有の記号で、その後ろに続くコマンドを起動するためのおまじないです。chmodコマンドを次のように使用してファイルのモードを変更してください。
chmod 755 hello.pl
コマンドプロンプトから次のように入力して実行してください。
hello.pl
CGI スクリプトで Perl を使用する場合は、ほとんどこの3番目の方法になります。
標準入力読み込み
perl コマンドの引数が指定されていない場合、標準入力から読み取った内容を perlスクリプトとして実行します。
echo 'print "Hello World!!\n";' | perl
# UNIXの場合
echo print "Hello World!!\n"; | perl # Windowsの場合
データを標準入力からPerl スクリプトに渡す
UNIX のコマンドラインから、標準入力のデータを Perl スクリプトに渡すことができます。
echo "print 'Hello World'" | perl -
コマンドラインスイッチ
- コマンドライン書式
- 0[8進数] レコードセパレータの指定
- -a オートスプリットモード
- -c 文法チェック
- -d デバッグモード
- -D数字 デバッグフラグの設定
- -e コマンドライン入力
- -i 入力ファイルの修正とバックアップ
- -I インクルードファイルの位置の指定
- -l 行末処理の自動化
-
-n sed
-n や awk のエミュレート -
-p sed
のエミュレート - -P コンパイル前にCプリプロセッサを通す
- -s コマンドラインハッシュの解析結果を変数に設定
-
-S 環境変数
PATH の設定 - -u スクリプトのコンパイル後にコアダンプ
- -U 安全でない操作を可能にする
- -v Perlのバージョンとパッチレベルを表示
- -w 識別子に関するさまざまな警告を表示
- -x スクリプトがメッセージに埋め込まれていることを知らせる
コマンドライン書式
Perlは、コマンドラインハッシュがコマンドラインの最初に指定されていると想定しています。通常、その次にスクリプトの名前が置かれ、さらに後ろにスクリプトに渡される引数が続きます。
コマンドライン書式
perl [-sTuU] [-hv]
[-V[:コンフィギュレーション変数名]] [-cw] [-d[:デバッグモジュール名]]
[-D[デバッグフラグ]] [-pna] [-F パターン] [-l[8進数]] [ -0[8進数] ] [-I
ディレクトリ] [-m[-]モジュール] [-M[-] 'モジュール...'] [-P] [-S]
[-x[ディレクトリ]] [-i[拡張子]] [-e 'コマンド'] [--] [プログラムファイル]
[引数]...
引数のない単一文字のスイッチは、その後ろのスイッチと組み合わせてまとめて指定することができます。
#! /usr/local/bin/perl -spi.bak
-0[8進数] レコードセパレータの指定
-0 8進数
レコードセパレータ( $/ )を8進数で指定します。数字を指定しない場合は NULL
値がセパレータになります。
このハッシュの前後に、他のハッシュを置くことができます。例えば、ファイル名の最後にヌルキャラクタを付けてプリントするfind があるなら、次のように使えます。
find . -name '*.bak' -print0 | perl
-n0e unlink
値 | 意味 |
---|---|
00 | ファイルをパラグラフモードで読み込む。 |
0777 | 全ファイルを読み込む。 |
-a オートスプリットモード
-a
-n や -p と一緒に指定すると、自動スプリットモードになります。-a を指定することにより、-n や
-p により自動的に行われる while ループ内で、最初に split コマンドが自動的に実行されます。
split の返却値リストは、配列 @F にセットされます。
perl -ane 'print pop(@F), "\n";'
上記コマンドラインと下記のスクリプトは、意味的に同じです。
while ( <> ) { @F = split ' '; print pop(@F), "\n"; }
-F オプションを利用して、 split の区切り文字を指定することもできます。
perl -F':' -a -n -e 'print join("\t" , @F), "\n";' /etc/passwd
-c 文法チェック
-c
スクリプトの文法をチェックし、実行せずに終了します。 スクリプトに誤りがなければ、syntax OK
と出力されます。
> perl -c script.cgi searchweb.cgi syntax OK
-d デバッグモード
-d
perl を -d ハッシュをつけて起動すると、デバッグモニタのもとでスクリプトが実行されます。デバッガは最初の実行可能文の前で止まり、デバッグ用コマンドを入力するよう促します。
-D数字 デバッグフラグの設定
-D数字
デバッグフラグをセットする。(この機能が使えるようにPerlをインストールするには、Configureがcc用のフラグを指定するように求めてきたときに、-DDEBUGGINGを指定します)
スクリプトがどのように実行されるかを見るには、-D14 を指定します。
-D1024 も有用な値です。これを使うと、コンパイルされた文法ツリーをリストします。
また、-D512 を使うと、コンパイルされた正規表現を出力します。
値 | 意味 |
---|---|
1 | トークン化と構文解析 |
2 | コマンドリンケージ |
4 | ラベルスタックの処理 |
8 | 実行をトレースする |
16 | オペレータノード構成 |
32 | 文字列/数値変換 |
64 | -Pに対するプリプロセッサコマンドを表示 |
128 | メモリ割り当て |
256 | フォーマット処理 |
512 | 正規表現の解析 |
1024 | ツリーを表示 |
2048 | 汚染のチェック |
4096 | メモリリーク |
8192 | コマンドラインのハッシュを表示 |
-e コマンドライン入力
-e コマンドライン
1 行のスクリプトを指定します。複数行のスクリプトを指定するには -e を複数指定します。
perl -e 'print "Hello World\n"'
-i 入力ファイルの修正とバックアップ
-i拡張子
<>で入力するファイルについて、処理した結果を元のファイルに書き戻します。
拡張子を指定すると、元のファイル名にその拡張子を加えた新しいファイルを作成し、それに処理結果を出力します。
たとえば、HTML ファイルの記述で <body> タグを全て <body bgcolor="#C0C0C0">
に変更するには以下のようにします。
perl -i.bak -p -e 's/<body>/<body bgcolor="#C0C0C0">/ig;' *.html
この結果、オリジナルのHTMLファイルを置換し、 .bak という拡張子をつけてバックアップファイルが作成されます。上記のようにワイルドカード(*)で指定すれば、
複数ファイルすべてを一気に置換することができます。
-I インクルードファイルの位置の指定
-I ディレクトリ
-P と一緒に指定して
Cプリプロセッサにインクルードファイルの位置を知らせます。デフォルトでは、プリプロセッサ文
#include <somefilename>
があると、/usr/local/lib/perlとカレントディレクトリを検索します。
また、require関数の検索で使うために、同じディレクトリが配列@INCにセットされます。
-l 行末処理の自動化
-l 8進数
行末処理を自動的に行います。このオプションを -p や -n と同時に用いると、-p や -n オプションのループブロック内の最初で chomp
が行われます。 つまり、 -n オプションと併用した場合、下記と同様です。
while(<>) { chomp($_); .... }
-l オプションには、二つの効果があります。
- -n または -p と一緒に指定した場合、行ターミネータを自動的に除く。
- $\ に 8 進の値をセットし、 print
文が全て最後に行ターミネータをつけるようにする。 8 進数を省略すると、$/ の値を $\
にセットする。
例えば、行を 80 コラムに切り揃えるためには
perl -lpe 'substr($_, 80) = ""'
※ $\ = $/ の代入はスイッチが処理される時に行なわれるので、 -l の後に -0
がある場合、入力レコードセパレータが出力レコードセパレータと違う値を持つ場合がある
gnufind / -print0 | perl -ln0e 'print "found $_" if -p'
この場合は $\ を改行、$/ をヌルキャラクタにセットします。
-n sed
-n や awk のエミュレート
-n
スクリプトの前後に下に示すループがあるものとして perl
を起動します。こうすると、引数のファイル全部について繰り返しが行われます。
while (<>) {
... # スクリプトがここにくる
}
-n オプションは、与えたプログラムの外側に下のようなループがあるのと同じような動作をします。
<> は、ダイアモンド演算子と呼ばれ、ファイル名が引数として与えられた場合はファイルから読み込み、引数がない場合は標準入力から読み込むという演算子です。
-n オプションによく似たオプションとして -p オプションがあります。-p オプションは、ループブロックの内側の最後に print $_;
があるように振舞います。読み込んだ値を出力したい場合は -p オプションを使ってください。
以下に示す例は一週間以上前のファイルを効率的に全て消去する方法です。
find . -mtime +7 -print | perl -nle 'unlink;'
こうすると find の -exec
スイッチを使うよりも高速です(ファイル名が見つかるたびにプロセスを起動する必要がないからです)。
-p sed
のエミュレート
-p
スクリプトの前後に下に示すループがあるものとして perl
を起動します。こうすると、引数のファイル全部について繰り返しが行われます。
while (<>) { ... # スクリプトがここにくる } continue { print; }
行は自動的に表示されます。出力しないようにするには -n を使います。
たとえば、-p オプションを使って /etc/passwd ファイルに行番号をつけて出力するには下記のようにします。
perl -p -e 'print ++$i, ": "' /etc/passwd
BEGIN { } と END { } で、ループ前後の処理を記述することが可能です。
perl -p -e 'BEGIN{ print "/etc/passwd \n";} END {print "\n";}'
/etc/passwd
とすると、 -- /etc/passwd --\n を print してから、/etc/passwd を一行ずつ print
し、最後に done.\n を print します。
-P コンパイル前にCプリプロセッサを通す
-P
perl のコンパイルの前に C プリプロセッサを通します。
perl のコメントも cpp の命令も # で始まるので、コメントを C
プリプロセッサが理解する単語、例えば if や else や define
で始めてはいけません。回避策として、行頭に#ではなく ;# を使う方法があります。
-s コマンドラインハッシュの解析結果を変数に設定
-s
コマンドラインのスクリプト名の後、ファイル名の引数(または
`--')の前のスイッチについて初歩的な解析を行います。
スイッチが見つかると、@ARGV から除かれ、対応する変数を perl
スクリプト内でセットします。次のスクリプトでは、`-xyz'
スイッチをつけてスクリプトを起動した時、またその時のみ `true' を出力します。
#!/usr/bin/perl -s if ($xyz) { print "true\n"; }
-S 環境変数
PATH の設定
-S
PATH環境変数を使ってスクリプトを探すようにします(スクリプト名が /
で始まらないかぎり)。これは特に #! をサポートしないマシンにおいて #!
をエミュレートするのに利用されます。その使い方は以下の通りです。
#!/usr/bin/perl eval "exec /usr/bin/perl -S $0 $*" if $running_under_some_shell;
システムは 1 行目を無視し、スクリプトを /bin/sh に渡します。 /bin/sh は perl
スクリプトをシェルスクリプトとして実行しようとします。シェルは 2 行目を通常のシェルコマンドとして実行し、
perl インタプリタを起動します。
システムによっては $0 は必ずしもフルパスを含まないので、 -S を用いて perl
に必要ならばスクリプトを探すように指示します。 perl がスクリプトを見つけると、解析を行い、変数 $running_under_some_shell
が真になることはないので、 2 行目を無視します。
ファイル名に含まれるスペースなどを正しく扱うには、 $* よりも ${1+"$@"}
のほうがよいでしょうが、 csh が解釈する場合には動作しません。
sh ではなくて csh で起動するには、あるシステムでは #!
行をコロンのみを含む行に書き換える必要があるかもしれません。 perl
はこの行を無視します。その他のシステムではこの方法は使えず、次のように、csh、sh、perl
のどの下でも動作するような、方法をとる必要があります。
eval '(exit $?0)' && eval 'exec /usr/bin/perl -S $0
${1+"$@"}'
& eval 'exec /usr/bin/perl -S $0 $argv:q'
-u スクリプトのコンパイル後にコアダンプ
-u
スクリプトのコンパイルの後、コアダンプします。このコアダンプから、undump
プログラム(提供していない)を用いて実行可能ファイルに変換できます。こうすると、ディスク消費が増えるかわりに(実行ファイルを
strip すれば最小にできる) スタートアップが速くなります。
この実行形式を set-id プログラムとして走らせるのなら、通常の perl ではなく
taintperl を用いてコンパイルします。
ダンプする前に実行したいスクリプトがある場合は、代わりに dump コマンドを使います。
※ undump が使えるかどうかはプラットフォームによるので、マシンによっては利用できないものもある
-U 安全でない操作を可能にする
-U
安全でない操作を可能にします。"安全でない"操作とは、スーパーユーザの権限で走らせている際にディレクトリを
unlink すること、および"汚れ"チェックの結果、警告が出るような setuid
プログラムを走らせることだけです。
-v Perlのバージョンとパッチレベルを表示
-v
perl のバージョンやパッチレベルなどの情報を出力します。
-w' 識別子に関するさまざまな警告を表示
-w'
識別子について以下の場合に警告を出す。
- 一度だけ出てくるもの
- セットする前に使用されるスカラー変数
- 複数回定義されるサブルーチン
- 定義されていないファイルハンドルへの参照
- リードオンリーでオープンしたファイルハンドルへの書き込み
- == を数値ではなさそうな値に用いている
- サブルーチンの再帰が 100 以上
-x スクリプトがメッセージに埋め込まれていることを知らせる
-xディレクトリ
スクリプトがメッセージ内に埋め込まれていることを perl に知らせます。 #! で始まり、 perlという文字列を含む最初の行が現れるまでのゴミは無視されます。その行に指定した意味のあるスイッチはすべて適用されます(ただし通常の #! 処理と同じく、スイッチのかたまりひとつだけです)。
ディレクトリ名を指定すると、 perl はスクリプトを実行する前にそのディレクトリに移ります。
-x は先頭のゴミのみを捨てます。スクリプトの後にゴミがある場合は、スクリプトを __END__で終わらなければなりません (望むなら、スクリプトで後ろのゴミの一部または全部をファイルハンドル DATA経由で処理することは可能です)。