システムのバックエンドはなんだかんだとperlをメインでつかってていろいろノウハウがあるのでまとめてみる
http://www.rwds.net/kuroita/program/Perl_unicode.h... とか今でもたまに見直す
windowsはとりあえずおいといて、linuxだとrpmで入っているバージョンは古いので、ソースから最新のバージョンをインストールする
インストール方法は結構ふるいので、perlbrewとかつかったほうがいい。最近のperl事情2012参照
インストール方法は結構ふるいので、perlbrewとかつかったほうがいい。最近のperl事情2012参照
cd /usr/local/src wget //www.cpan.org/src/5.0/perl-5.12.2.tar.gz tar xvfz perl-5.12.2.tar.gz cd perl-5.12.2 ./Configure -Dprefix=/usr/local -Dusethreads -Accflags=-DPERL_REENTRANT_MAXSIZE=65536 make make test make install過去に5.10を入れたのをhttp://blog.livedoor.jp/kurt0027/archives/52014712...に書いているのでそれも参考にする。configureでlibperl.soをどうするかと聞かれたら、とりあえずはyにしておいた
※ぼちぼち更新しないとなあ。情報が古い。おなじく最近の最近のperl事情2012参照
- Class::Accessor
- Class::Data::Inheritable
- Class::Data::Accessor
- Class::Trigger
- DBD::Mock
- Devel::NYTprof
- FindBin::Real
- feature ":5.10.0"
- IPC::Cmd
- IPC::Run(こっちは標準じゃないよ)
- IPC::Open2
- IPE::Open3
- Path::Class
- Proc::PID::File
- Parallel::ForkManager
- Term::Prompt
- YAML::Syck
- Sub::Install
- Class::C3(NEXTのかわりね) 5.10.0からはmro "c3"とするといいみたい。でその架け橋となるのがMRO::Compat
- UNIVERSAL::require
- Module::Pluggable
- Log::Dispatch::Config
- autodie
- parent(use baseの代替。いまや常識のようだ)
- Sub::Retry
結構いろいろとオプションがあって、コマンドをいろいろ組み合わせてやるよりも便利かも。例えば
perl -n -a -F: -e 'printf "%-10s %s\n",@F' /etc/shadowで/etc/shadowからアカウントとパスワードを取り出す。オプションは以下
- -n はSTDIN(標準入力)、もしくはファイル名から受け取ったデータをwhileでまわす処理を自動化
- -a autosplit mode。用は区切り文字がある場合に-Fで指定した文字列を@Fという配列にいれてくれる
- -F -aを指定した場合の区切り文字を設定。/etc/shadowは:で区切られているので今回は-F:で指定。-F//なんかで正規表現を指定することも可能
- -e eval mode。perlコードを評価する。-eのあとにスクリプトを記述。
- -i ファイル内部を置換して、バックアップファイルを作成するときに指定
- -l 出力時に自動改行
- -E from 5.10。use feature したのとほぼ同じ状態になるらしい。sayが使えたりとか
find /path/to/foo -type f | perl -n -l -e 'printf "%-20s%dbyte\n", $_, -s $_'
find /path/to/foo -type f | perl -n -l -e 'BEGIN{ $sum = 0 } $sum += -s; END{ print $sum }'
たとえばhtmlファイル内の<!-- COMMENT -->を削除したいけど1000個以上ファイルがある場合
perl -i.bak -p -e 's/<!\-\- COMMENT \-\->//' *.htmlとすればコンテンツを一括で置換してさらにバックアップ(この場合だと拡張子.bakのファイルが作られる)もしてくれる*1。さらに応用でとあるディレクトリ内(ここでは/path/to/cgi-binとする)のファイル内にかかれている/usr/bin/perlを /usr/local/bin/perl とかにする場合は
grep -lr '#!/usr/bin/perl' /path/to/cgi-bin/* | xargs -t perl -i.bak -ple 's|#!/usr/bin/perl|#!/usr/local/bin/perl|g'とすると一括で変更可能。ただしもとのファイルのバックアップができるのでいらない場合は
find /path/to/cgi-bin -name "*.bak" | xargs rm -fとかするとOK。
uuidgenでもいいんだけど数値主体な文字列になってしまうので
randstr byte数
# 長ったらしいから関数化してしまうとよい randstr() { len=$1 perl -E 'BEGIN{ @chars = ("a".."z","A".."Z",0..9); $len = shift } { @rand_chars = map { $chars[sprintf("%d", rand(scalar(@chars)))] } 1..$len } END{ say join("", @rand_chars) }' $len }使い方は
randstr byte数
randstr 8 kTL4IMT7こんな感じ
# no such process PID などのエラーメッセージが返って来なければ生存している kill 0 $PIDしかし環境によっては使えなかったりするので
perl -e 'print kill 0 => $PID'で1が返ってきた場合は生存している、0もしくはundefの場合は生存していない。こっちのが確実かも
nkfが入っている場合は
# -g は --guessでもよい nkf -g filenameで調べることができるけど、nkfが古かったり(-gが使えない)nkf自体が入っていない場合はperlのEncode::Guessモジュールを使うことで判別可能
perl -MEncode::Guess -nle 'BEGIN{ @alldata } data.= $_; END{ print guess_encoding($data, qw(euc-jp shiftjis 7bit-jis) )->name }' filenameEncode::Guess::guess_encodingはたまに文字コード判定に失敗する場合がある。失敗した場合は
Can't locate object method "name" via package "shiftjis or euc-jp" (perhaps you forgot to load "shiftjis or euc-jp"?) at -e line 1, <> line 19. END failed--call queue aborted, <> line 19."shiftjis or euc-jp"という文字列で返ってきていることになる。標準モジュールじゃないけど、Jcodeモジュール使う手もあり
getpgrp, setpgrpを使う。
kill -KILL -`perl -e 'getpgrp($PID)'`とすると対象プロセスグループに属するプロセス全てにシグナルを送信することができる。 setpgrpは対象プロセスのプロセスグループを変更する時に使う。第1引数が0の場合は現在のプロセスに対して、プロセスグループの設定を行う。
setpgrp 0, $$;みたいな感じ。詳細はhttp://perl.misty.ne.jp/function02/setpgrp.html
最近ではExUtils::MakeMakerではなく、Module::InstallなるモジュールでCPANにupする時のモジュール雛形をつくるのが流行らしい。それを簡単にしてくれるスクリプトがpmsetup。http://svn.bulknews.net/repos/public/misc/pmsetupからとってくる
使い方は簡単で
使い方は簡単で
# PATH通ってるところにおいて、実行権限つける pmsetup Module::Nameとするとauthor, emailを聞かれるので適当に答える*3と実行したディレクトリにModule-Nameというディレクトリができるので、後は実際にupするモジュールの入れ替え、Makefile.PLの書き換えを行う。あとは
perl Makefile.PL make make test make manifest make disttest make dist make distcleanとおなじみの作業でtarballが作成される
local $Data::Dumper::Sortkeys = 1; local $Data::Dumper::Indent = 1; local $Data::Dumper::Terse = 1; local $Data::Dumper::Deparse = 1;こんな感じで使う
http://blogs.yahoo.co.jp/kipp/46446122.html などにも書かれているけど、YAML::Dumpを使うほうがいいかも。
それかUnicode::RecursiveDowngradeを通してからData::Dumperでダンプする
それかUnicode::RecursiveDowngradeを通してからData::Dumperでダンプする
cpanp f moduleApp::CLI::Extensionだと現段階ではこのように表示される
cpanp f App::CLI::Extension 1 App-CLI-Extension 2008-09-14 0.01 HOLLY 2 App-CLI-Extension 2008-09-14 0.01 HOLLY 3 App-CLI-Extension 2009-09-08 0.10 HOLLY 4 App-CLI-Extension 2009-09-08 0.10 HOLLY 5 App-CLI-Extension 2009-09-08 0.20 HOLLY 6 App-CLI-Extension 2009-09-10 0.20 HOLLY 7 App-CLI-Extension 2009-09-18 0.30 HOLLY 8 App-CLI-Extension 2009-09-08 0.30 HOLLY 9 App-CLI-Extension 2009-09-18 0.40 HOLLY 10 App-CLI-Extension 2009-09-08 0.40 HOLLY 11 App-CLI-Extension 2009-11-29 0.50 HOLLY 12 App-CLI-Extension 2009-11-29 0.50 HOLLY 13 App-CLI-Extension 2009-11-30 0.60 HOLLY 14 App-CLI-Extension 2009-11-30 0.60 HOLLY 15 App-CLI-Extension 2009-12-05 0.70 HOLLY 16 App-CLI-Extension 2009-12-05 0.70 HOLLY一覧を参照した上で番号を指定するとその番号に該当するバージョンのモジュールをインストールすることができる
i 1
cpanp s conf [~/perl] allow_build_interactivity '1' base '/root/.cpanplus' buildflags '' cpantest '' cpantest_mx '' debug '' dist_type '' email 'cpanplus@example.com' extractdir '' fetchdir '' flush '1' force '' lib [] makeflags '' makemakerflags '' md5 '1' no_update '' passive '1' prefer_bin '' prefer_makefile '1' prereqs '2' shell 'CPANPLUS::Shell::Default' show_startup_tip '1' signature '' skiptest '' storable '1' timeout '300' verbose '' write_install_logs '1'
cpanpで対話モードにはいったあと
s conf <key> <value>と入力。モジュールインストール時に依存するモジュールも問い合わせなしでインストールする設定の場合だと
s conf prereqs 1となる
chomp(my $hostname = readpipe "hostname");でもいいけど
use Sys::Hostname; my $hostname = hostname;のが外部コマンド使わんでいい
use Socket; my $ip_address = "xxx.xxx.xxx.xxx"; $hostname = gethostbyaddr(inet_aton($ip_address), AF_INET); print "$hostname\n";
use Socket; my $hostname = "hostname.domain"; my $ip_address = inet_ntoa(inet_aton($hostname)); print"$ip_address\n";
md5sumを使えば
# md5sum hoge.txt とした場合 413eda89cba6c7c42003091cfe2c78bd hoge.txtとすればできるけど、perlだけで実現したい場合は
#!/usr/bin/perl use strict; use Digest::MD5; my $file = shift; open my $fh, "<", $file or die $!; my $hash = Digest::MD5->new->addfile($fh)->hexdigest; close $fh; print "$hash $file\n";で同じような処理が可能。外部コマンドあんまし使いたくない場合はいい。
htpasswdの-mオプションはForce MD5 encryption of the passwordだが、これをperlから扱おうと思っても残念ながら簡単にできない
htpasswd -mbc .htpasswd hoge hogehogeと実行すると.htpasswdには
hoge:$apr1$EYfANhrC$r2yAPD0VCf0bwgJ54ONPu0のように保存される。この文字列を扱うにはCrypt::PasswdMD5を使えばよい。.htpasswdに登録されているhogeアカウントのパスワードを照合したい場合は
#!/usr/bin/perl use strict; use Crypt::PasswordMD5; my $password = "hogehoge"; my $md5_crypt_password = '$apr1$EYfANhrC$r2yAPD0VCf0bwgJ54ONPu0'; my($salt) = $md5_crypt_password =~ /^$apr1$(.*{8}).+$/; if($md5_crypt_password eq apache_md5_crypt($password, $salt)) { print "password match\n"; } else { print "password unmatch\n"; }とすればよい
- アカウント holly
- パスワード hoge
perl -MMIME::Base64 -le 'print encode_base64("$ARGV[0]\0$ARGV[0]\0$ARGV[1]")' holly hoge amVycnkAamVycnkAcm9jawと出力されるので、telnetなどでSMTP認証するときに
# 250 DSNが出力されたあとに↓を入力 auth plain amVycnkAamVycnkAcm9jaw== # 成功した場合は↓が返ってくる 235 2.0.0 Authentication successful
250 DSNが出力後に、
# ↓を入力 auth cram-md5 # ↓のキーとなる文字列が返ってくるので 334 PDQwMTQ2OTQ3NjQuMTE0OTUxQGZlZG9yYTguZW5kbGVzcy1uYW1lbGVzcy54eHg+キーとなる文字列が返ってくるので
# /usr/bin/perl -MDigest::HMAC_MD5 -MMIME::Base64 -le 'print encode_base64($ARGV[0] . " " . Digest::HMAC_MD5::hmac_md5_hex(decode_base64($ARGV[2]), $ARGV[1]))' holly hoge PDQwMTQ2OTQ3NjQuMTE0OTUxQGZlZG9yYTguZW5kbGVzcy1uYW1lbGVzcy54eHg+ amVycnkgZmQwZjU3ZGQ2NTJhMzcwNTQwZDYzMDYzMWVmN2YwZDE=出力が得られた文字列をそのままtelnetに貼り付けてenterを押すとよい
いろいろ条件があって、system call使いたいが、それらを利用してperlモジュール使えない時の最終手段。/usr/include/asm/unistd_32.h あたりにsyscallでsystem callを呼び出す番号が定義されている
#!/usr/bin/perl use strict; # /usr/include/linux/kernel.h:#define SI_LOAD_SHIFT 16 our $SI_LOAD_SHIFT = 16; # /usr/include/asm/unistd_32.h:#define __NR_sysinfo 116 our $NR_SYS_INFO = 116; my $shift = 1 << $SI_LOAD_SHIFT; my $buf = "\0" x 64; syscall($NR_SYS_INFO, $buf) == 0 or die $!; my @loads = map { $_ / $shift } (unpack "l L3", $buf)[1..3]; printf "load average: %.2f, %.2f, %.2f\n", @loads
# こんなの use 5.10.1; # とかこんなの use v5.10.1;とか指定できるが、
use 5.010_001;みたいな書き方にしとくこと
- 外部からのデータ(ファイルから読み取った値、DBから取得した値、webappならGET/POSTなどで渡された入力パラメータなど)は全てutf8 flagをたてる
- 各処理はutf8 flagがたった状態で処理する(当然ながらuse utf8しとくこと)
- 外部へ出力する場合はutf8 flagを落とす
http://www.rwds.net/kuroita/program/Perl_unicode.h... とか今でもたまに見直す
はじめは文字化けが発生したりapacheのerror_logにwarning(内容忘れた)などがよく出力されていたが
- 正規表現でマルチバイトを使用可能
- 文字数を取得できる(byteで取得したい場合はbytes pragmaのbytes::lengthを使う。http://perldoc.perl.org/bytes.html)
- 当然ながらその他の文字列系処理(substrとか)もマルチバイトを意識することなく処理可能(だと思う)
utf8 flagをたてる/落とすの基本的な処理を行うモジュール
- encode
- encode_utf8
- decode
- decode_utf8
- is_utf8
- from_to
文字コード判定用。文字コード判定できなかったときの処理さえ気をつければ問題ない。http://blog.livedoor.jp/dankogai/archives/50737353... ←これ
ファイルを読み取り時に取得したデータに自動的にutf8 flagをたてて、出力時にutf8 flagを落とす
その都度指定がめんどくさい場合は
#!/usr/bin/perl use strict; use utf8; my $file = "aiueo.txt"; open my $fh, "<:utf8", $file or die "can not open $file. $!";; chomp(my $data = <$fh>); close $fh;
その都度指定がめんどくさい場合は
#!/usr/bin/perl use strict; use utf8; use open IO => ":utf8"; my $file = "aiueo.txt"; open my $fh, "<", $file or die "can not open $file. $!"; chomp(my $data = <$fh>); close $fh; open my $fh, ">", "${file}.new" or die "can not open $file. $!"; print $fh "かきくけこ\n"; close $fh;
use strict; use utf8; use open ":utf8"; # use open IO => ":utf8" と同じ use open ":std"; chomp(my $data = <STDIN>);
postgresの場合はDBD::Pgのpg_enable_utf8というものを使うといけると思う。
#!/usr/bin/perl use strict; use DBI; my $dbname = "hogedb"; my $dbuser = "hogeuser"; my $dbpass = "dbpass"; my $dbh = DBI->connect("dbi:Pg:dbname=$dbname", $dbuser, $dbpass, {AutoCommit => 0, RaiseError => 1, pg_enable_utf8 => 1}); # anything to do $dbh->disconnect;DBD::mysqlの場合だとmysql_enable_utf8というのがある
Devel::NYTProfがよい
nytprof.outというファイルが出来る。これがプロファイルの結果となるが、これだけでは結果はまだ見れないので
を実行するとnytprofディレクトリが出来るのであとはそのなかにあるindex.htmlを参照すればよい。なかなか見た目もいい感じ。
入ってないのならDevel::DProf(CORE Module)でも一応調べることは可能
/usr/bin/perl -d:NYTProf foo.plとすると
nytprof.outというファイルが出来る。これがプロファイルの結果となるが、これだけでは結果はまだ見れないので
nytprofhtmlり
を実行するとnytprofディレクトリが出来るのであとはそのなかにあるindex.htmlを参照すればよい。なかなか見た目もいい感じ。
入ってないのならDevel::DProf(CORE Module)でも一応調べることは可能
/usr/bin/perl -d:DProf foo.pltmon.outというファイルが生成されるので、dprofppを実行する
Total Elapsed Time = 0.426661 Seconds User+System Time = 0.376661 Seconds Exclusive Times %Time ExclSec CumulS #Calls sec/call Csec/c Name 18.5 0.070 0.080 1 0.0699 0.0796 YAML::Type::code::BEGIN 7.96 0.030 0.039 7 0.0043 0.0055 Log::Dispatch::Config::BEGIN 7.96 0.030 0.029 5 0.0059 0.0058 App::CLI::Plugin::DBI::BEGIN 5.31 0.020 0.020 6 0.0033 0.0033 FindBin::BEGIN 5.31 0.020 0.029 7 0.0028 0.0042 App::CLI::BEGIN 4.25 0.016 0.115 1094 0.0000 0.0001 YAML::Base::__ANON__ 2.65 0.010 0.010 1 0.0100 0.0100 B::bootstrap 2.65 0.010 0.010 1 0.0100 0.0100 utf8::AUTOLOAD 2.65 0.010 0.010 1 0.0100 0.0096 Carp::longmess 2.65 0.010 0.010 9 0.0011 0.0011 utf8::SWASHNEW 2.65 0.010 0.010 9 0.0011 0.0011 Exporter::as_heavy 2.65 0.010 0.010 4 0.0025 0.0024 App::CLI::Plugin::Parallel::ForkMa nager::BEGIN 2.65 0.010 0.010 12 0.0008 0.0008 DynaLoader::dl_load_file 2.65 0.010 0.010 14 0.0007 0.0007 warnings::unimport 2.65 0.010 0.099 1 0.0099 0.0985 YAML::init_action_objectこんな感じでみることが可能
ExtUtils::Installedで
#!/usr/bin/perl use strict; use warnings; use ExtUtils::Installed; my $ei = ExtUtils::Installed->new; map { printf "%s\t\t%s\n", $_, $ei->version($_) } $ei->modules;消すこともできるけど、怖いからやめとく
たぶん自分でモジュールを配布する上で準備している場合によくやるやつ
perl Makefile.PL makeこの時点でblib/lib などにモジュールが展開されるのだが、make installとかしてしまうまえに、少しだけ簡単なスクリプトを書いてテストとかしたい場合
use ExtUtils::testlib; # 今回作成したFoo.pmをload use Foo;とかするとblib/libのパスを通すとか細かいことを気にする必要がなくなる
タグ
最新コメント