2012/05/24

Perl Shell(psh)を入れてみた話

去年Perl Shell(psh)というものを見つけて、今度試してみようと思ったまま時間が過ぎて、八十八夜も過ぎてしまったので、思い出したようにPerl Shellを試してみました。

いつも使っているtcshやBourneシェルとはかなり違った文化な感じで、とりあえず入れて少し触ってみた、という程度の内容です。

Perl Shellのインストール

cpanmでもインストールできるのですが、最初にそれで入れたpshは動作がおかしかったので、githubからソースを持ってきて、必要なモジュールを入れてからmake installしました。

インストールしたのはうちのMacで、実行に使用したPerlは5.14.2です。
% cd /usr/local/src⏎
% git clone https://github.com/gnp/psh.git⏎
Cloning into psh...
remote: Counting objects: 5457, done.
remote: Compressing objects: 100% (2064/2064), done.
remote: Total 5457 (delta 2878), reused 5410 (delta 2831)
Receiving objects: 100% (5457/5457), 974.67 KiB | 373 KiB/s, done.
Resolving deltas: 100% (2878/2878), done.

% cd ./psh⏎
% sudo cpanm BSD::Resource Term::ReadLine::Gnu⏎
...
% perl Makefile.PL && make && sudo make install⏎
...
Installing /usr/local/bin/psh
Appending installation info to /usr/local/lib/perl5/5.14.2/darwin-2level/perllocal.pod
/usr/local/bin/perl postinstall.pl /usr/local /usr/local
Installing share files to /usr/local/share/psh
% rehash && which psh⏎
/usr/local/bin/psh

PerlのShellと言えばアコヤガイ
ulimitが使用できるよう BSD::Resource モジュールを、Ctrl-P等が使えるよう Term::ReadLine::Gnu モジュールをそれぞれcpanmで入れてからビルドしてます。

うまいことビルドとインストールが終わったらPerl Shellは /usr/local/bin/psh (/usr/bin/perlを使ったら /usr/bin/psh になる、たぶん)が利用できるようになっているはずです。

Perl Shellを起動

一般的なShellを起動するのと同じで、pshを実行するとPerl Shellが起動します。コマンドなのでマニュアルはman pshで読みます。あるいはWebで。
% /usr/local/bin/psh⏎
psh%
psh% man psh

サンプルコマンドを試す

manに書いているような簡単なサンプルを試しました。

sedの代わりとして

psh% ls -laF | s/May/五月/g⏎
total 224
drwxr-xr-x  33 user  admin   1122 五月 22 20:16 ./
drwxrwxr-x  48 root  admin   1632 五月 22 20:14 ../
drwxr-xr-x  13 user  admin    442 五月 22 20:14 .git/
-rw-r--r--   1 user  admin     70 五月 22 20:14 .gitignore
...

行番号を付ける(quick filter)

psh% ls -F1 | { printf "%02d %s", ++$x, $_ }q⏎
01 CHANGES.pod
02 COPYRIGHT
03 HACKING.pod
...
末尾のqはquick filterとして動作するようで、{ }内のコード実行結果だけ表示されるようです。逆にqを付けないと、ls -1Fの実行結果と | {...}の処理結果がそれぞれ表示されます。

Perlっぽいもの

tcshとbashに於て環境変数やシェル変数の宣言は、=を付けるか付けないかの違いがあってたまに間違えますが、Perl ShellではPerlの変数宣言と同じように記述して変数が作れます。Scalar, Array, Hash, それとリファレンスも使えます。

環境変数も%ENVへアクセスすれば読み書きが可能です。

他にもPerlの関数をそのままコマンドラインから呼び出したりできるので、UNIXコマンドを意識しなければ、そのままPerlのインタラクティブシェルのような感じで使えます。
psh% $x = 9⏎
psh% print $x.qq(\n)⏎
9
psh% $y = [ 1..10 ];⏎
psh% print $_.qq(\n) for @$y;⏎
1
2
3
4
...
10
psh% map { $_ *= 10 } @$y;⏎
psh% print $_.qq(\n) for @$y;⏎
10
20
30
...
psh% print $ENV{SHELL}.qq(\n)⏎
/usr/local/bin/psh

ちょっと応用してみた感じの試行

RSSが一定以上のプロセスを絞り込む(grep filter)

psh% ps axu | head -2⏎
USER             PID  %CPU %MEM      VSZ    RSS   TT  STAT STARTED      TIME COMMAND
hoge             260   5.2  1.7  2604588  71088   ??  S     7:15PM   1:25.32 /Applications/Utilities/Terminal.app/Contents/MacOS/Terminal -psn_0_90134

psh% ps aux | { $_[5] > 1024 * 100 }g⏎
...
psを実行した結果、うまいことスペース(かタブ?)でsplitされたものが@_に入るので、RSSはPerlの配列では5番目(0から始まる)です。 なので$_[5]が100MB(1024KB * 100)以上のプロセスだけを絞り込めます。この動作は末尾のg(grep filter)によるものだそうです。

同じようにCPU使用率が50%以上のものを絞り込んだりする数値計算によるフィルタが考えられます。

このあたりは従来の伝統的なUNIXコマンドを駆使するよりも簡単に結果を得られる気が(たぶんawkでも同じ事が出来ると思います、たぶん...)します。

Time::Pieceモジュールを使って6時間以内のaccess_logを取り出す

同じくgrep filterですが、モジュールも使えます。

いつも書くPerlと同じくuseで呼ぶとShellを終了するまでずっと使える状態になります。requireでも同様に読み込めますが、Perl Shellに於けるuseとrequireの動作の違いは知りません。

下記はTime::Piece->strptimeでaccess_logの日付・時刻をマシンタイムに変換して現在時刻と比較して6時間以内のログだけを取り出している例です。
psh% cd /usr/local/httpd/logs⏎
psh% use Time::Piece;⏎
psh% cat access_log | { $x = localtime Time::Piece->strptime( $_[3], "[%d/%b/%Y:%T" ); $x > time - 21600 }g⏎
...

ほかのShellと違うところ

標準エラーを捨てる時の 2> /dev/null の書き方が違います。manにはサポートしてないって書いてあり、かわりに下記のように記述するようです。
% /usr/local/bin/psh⏎
psh%
psh% /bin/ls /tmp/hoge/fuga/piyo >[2] /dev/null⏎
[1] Error 11778 ls -1 /tmp/hoge/fuga/piyo
ファイルディスクリプタ番号は同じ2ですが、書き方が少し違います。

他には、
  • pushd/popdがない(eval errorって言われる)
  • ( cd /tmp && touch ./test.txt )を実行するとeval error (Illegal division by zero...ってエラー
などちょいちょい違うところに出くわします。見た限り、tcsh,bash等で shell built-in command なものでpshで実装されていないものは ``Command not found or syntax wrong:'' と言われたり、エラーが出たりするようです。

挙動不審なところ :-(

/usr/local/bin/psh -wで起動すると、
  • コマンド実行で``Use of uninitialized value $num in numeric eq (==)...''とか出る
  • どのコマンドを実行しても↑がでる(´ヘ`;)
-wを付けなくても、たまに起きるのが
  • cd /usr/local/src等実在するディレクトリへ移動できない事がある(No such ...)
  • /sbin/ifconfigを実行すると``Having no space between pattern and following...''と出る事がある
などなど、やや挙動不審なところがありました。pshを起動し直すと回復します、ソース見て原因特定とかやってません。

まとめ

とりあえず入れて使ってみた、という段階の内容です。僕はサーバエンジニアなので、bashすらない古代のシステムに入る事もあり、おそらく標準では入っていないであろう近代的なShellにどっぷり浸かる事はないと思います。

Perl Shellの利点としては、sed, awkなどのUNIXコマンドに精通していないけどPerlなら分かるって場合に、在る程度のオペレーションが出来るのかなぁって所かと思います。

あるいはShellとしてではなく、Perlのインタラクティブシェルとして使う、という姿勢の方がPerl Shellって便利と思えるかもしれません。

関連リンク

0 件のコメント:

コメントを投稿