最終更新 2024.04.01
Perl表技集 Perl基礎入門
ファイルの先頭に use strict; と書くと、そのファイル中のメイン関数(関数宣言なしに 書き始める部分)、サブルーチン全てに変数宣言が必要となる。 変数宣言は my $a; my ($a,$b,$c,@array); のように行う。配列変数は @ をつける。
メイン関数の中で宣言した変数はグローバル変数となる。
break : last continue : next
open(FP,"> file");
print FP "$moji\n";
printf FP ("%4d \n",$i);
close(FP);
open(FP,"<&STDIN");
open(FP,"< file");
$moji = <FP>;
close(FP);
open(FP,">&STDERR");
$iret = open(FP,"< file");
if ( $iret == FALSE ){
print STDERR "cannot open file\n";
exit 1;
}
成功したとき : 1
失敗したとき : 空白
open(FP,"< $fname") || die "cannot open file $fname\n";
ファイルのロック
open(FP,"> filename");
flock(FP,2); # ロック
print FP,"....";
flock(FP,8); # 解除
close(FP);
読み書きモードの使い方
open(FP,"+< filename");
$dat = <FP>; 読み込み
truncate(FP,0); # ファイルサイズを 0 にする
# これを怠ると seek の後に書き込んだサイズが元のファイルより
# 小さいとき、元のファイルの後半が残る
seek(FP,0,0); # 読み取りポインタをファイル先頭に
print FP "data\n";
close(FP);
unlink ("fname","fname2","fname3");
print "i = ",$i,"\n"; basic と同じ構文
print "i = $i \n"; $i は " " の内側にも書ける
print "\"i\" = 1\n"; エスケープシーケンス
printf("a = %10.5lf \n",$a); C と同じように書いても良い
$moji = sprintf("a = %10.5lf ",$a); sprintf は引数の書き方が少し違う
$moji = sprintf("%20s ",$str); 20 文字右つめ
$moji = sprintf("%-20s ",$str); 20 文字左つめ
print FP "i = $i \n"; ファイルへの入出力
printf FP ("a = %10.5lf ",$a);
print @list; 隙間なく並べる
print "@list"; 要素ごとの間に空白を 1 つ入れる
$argc = @ARGV; 引数の個数を取得 $ARGV[0] 第一引数
<STDIN> <STDOUT> <STDERR>
$host = $ENV{'HOST'}; 環境変数はハッシュ変数 %ENV に入っている
値渡し
&sub1($a,$b);
sub sub1{
my($a2,$b2) = @_; <---- 引数は配列 @_ に格納される
my($c); <---- $c はローカル変数
$b2 = 10;
}
ポインタ渡し ( ver.5.8 ではエラーになる。現在は使えないようだ)
&sub2(*a,*b);
sub sub2{
my(*c,*d) = @_;
$c = 10;
$d[0] = 1;
$d[1] = 2;
}
ファイルハンドルの引数渡し
&sub3(FP);
sub sub3{
my($FP) = @_;
$_ = <FP>;
print "file : $_\n";
}
サブルーチンからの戻り値
return 式;
複数の値を返すとき
($a,$b) = &sub4($a,$b)
sub sub4{
my($c,$d) = @_;
$c++;
$d++;
return ($c,$d);
}
普通の配列
$array[0] = 'abc';
$array[1] = 'def';
foreach $item ( @array ){
}
連想配列
$a{'aa'} = 'xx';
$a{'ab'} = 'yy';
forcach $item ( keys %a ){
}
forcach $item ( sort keys %a ){
}
$a = $b . $c; あるいは $a = "$b$c";
if ( $str =~ m/pattern/ ) m は省略可
if ( $str !~ m/pattern/ ) マッチングしない
if ( $str =~ m/pattern/i ) i : 大文字小文字を無視
if ( $str eq $str2 )
(注)if ( 'aaa' == 'bbb' ) は真となるので注意。文字列の比較は eq を使う
$str = "abc-def";
$str =~ m/(.*)-(.*)/; . は任意の1文字 * は 0 回以上の繰り返し
() はグループを表す $1 $2 $3 ... の順番に入る
print "$1 $2 \n"; $1 には abc $2 には def が入る
$_ = "abc-def"; 上の例の省略形
m/(.*)-(.*)/;
print "$1 $2 \n";
if ( $str =~ m/^\s*$/ ) 空行とのマッチング
$str の最後が "\n" があっても上の式はマッチングする。
文字列の最後に "\n" があることが確実な場合は、
if ( $str =~ m/^\s*\n/ )
の方が分かりやすいかもしれない。
$str =~ s/previous/after/; 文字変数 $str を置換した結果が $str に入る
s#previous#after#; / でなくてもよい。
s/previous/after/g; グローバルの略 マッチングするもの全て
g を付けない時、最初にマッチしたものだけ置き換える
s/previous/after/i; 大文字小文字区別せず
@list = split( ' ' , $str ); print "$list[0]\n";
$out = join(' ',@list);
print "out\n";
行末に改行記号がある場合、切り落とす
if ( $moji =~ m/\n$/ ){ chop($moji); }
長さの取得
$leng = length($a);
Basic の MID$
$in = '123456789';
$a = substr($in,0,4); 最初から 4 文字取る
$b = substr($in,4,5); 5 文字目から 5 文字取る
$c = substr($in,3); 4 文字目から最後まで
結果 : $a = "1234" $b = "56789" $c = "456789"
$list[0] = "yabu"; 普通の配列
@list = ( 1 , 2 , 3 );
@list 配列全体
$size = @list 配列のサイズを得る
$#list 配列の最後の要素番号 ( 要素は 0 から始まるので
サイズ-1 が得られる )
push(@list,element) 配列の最後に要素を一つ加える
$a = pop(@list) 配列の最後の要素を取り除き、その要素を返す
unshift(@list,element) 配列の最初に要素を一つ加える
$a = shift(@list) 配列の最初の要素を取り除き、その要素を返す。一つ前に詰められる
$list{yabu} = "tetsuro"; 連想配列
%list 配列全体
引数処理の例
while($arg = shift(@ARGV)){
if ( $arg =~ m/^-/ ){
push(@options,$arg);
} else {
$fname = $arg;
}
}
perl には 2 次元配列はないが、$a[$i] までを変数名と
見なすことにより、以下のように C と全く同じ構文で、
2 次元配列を実現することが出来る。
for($i = 0; $i < 3; $i++){
for($j = 0; $j < 4; $j++){
$a[$i][$j] = $i * 10 + $j;
}
}
for($i = 0; $i < 3; $i++){
for($j = 0; $j < 4; $j++){
printf("a[%d][%d] = %3d\n",$i,$j,$a[$i][$j]);
}
}
. 任意の1文字 x? 0 個あるいは 1 個の x x* 0 個以上の x x+ 1 個以上の x ^ 行の先頭 $ 行末 \s 空白文字 ( スペース、タブ、改行 ) \S 空白以外の文字 [0-9\-] 0 〜 9 の文字あるいは '-' 記号の固まり [^\"]+\" " 以外の文字の 1 つ以上の連続の後、" 文字
if ( 条件 || 条件 ) {
} elsif ( 条件 && 条件 ) {
} else {
}
$a == $b スカラ変数
$a != $b スカラ変数
$a eq $b 文字列
$a ne $b 文字列
$name{'yabu'} = "tetsuro";
$name{'sawa'} = "shinnosuke";
@list = sort keys %name;
@list2 = sort values %name;
seek(FP,0,0); 第 2 引数の 0 バイト目、第 3 引数の 0 はファイル先頭から
$loc = tell FP; ファイルポインタの位置を得る $line = <FP>; 読み込む seek(FP,$loc,0); 先程の位置にもどす
eof(FP) が 1 のときファイルエンドを表す
例 下の二つの例は同じ
while(1){
if ( eof(FP) == 1 ){
last;
}
$_ = <FP>;
print;
}
while(<FP>){
print;
}
( 注意 )
$_ = <FP> として最後の行を読み込んだ直後に
eof(FP) は 1 になるので、
$_ = <FP>;
if ( eof(FP) == 1 ){
last;
}
print;
ではダメである。ここは C の fgets とは感覚が
異なるところであるから注意すること。
sub find_header
{
my(*FP,$header) = @_;
seek(FP,0,0);
$flag = 0;
while(<FP>){
if ( m/^\s*$header/ ){
$flag = 1;
last;
}
}
if ( $flag == 0 ){
print "Cannot find header\n";
print "Exit.\n";
exit 1;
}
}
$hour = int( $min / 60 ); $min = $min % 60; また printf 文で実数型変数に対して %d を指定すると 小数部を切捨てて表示してくれる。
C 言語と同じ goto LABEL; LABEL:
opendir(DIR); @flist = readdir(DIR); closedir(DIR); chdir "/usr/local/bin";
if ( -d $fname ) $fname がディレクトリか否か if ( -f $fname ) $fname がファイルか否か if ( -l $fname ) $fname がシンボリックリンクか否か if ( -e $fname ) $fname が存在するか否か
$$ プロセス番号 $0 スクリプトファイルの名前(コマンドラインから打った値)
ctrl-C は 'INT' で表される。
SIGTERM でないのに注意!
( 例 )
$SIG{'INT'} = 'interrupt';
while(1){}
sub interrupt {
print "terminate\n";
exit 1;
}
2種類の書き方がある。 --------------------- print <<END_MARK << と END_MARK の間に空白を入れてはならない ..... $a 変数も使える ..... END_MARK ; このセミコロンを忘れないように --------------------- --------------------- print << "END_MARK"; ..... $a ..... END_MARK ---------------------
@result = grep /文字/, @list @result = sort @list
@result = sort @list 普通のソート
@result = sort {$a cmp $b} @list 上の内容を省略せずに書いたもの
sort コマンドは $a, $b という一時変数
を使う。{ } の中が -1 なら $a を前に
並べ、1 なら $b を前に並べる。
$a cmp $b は文字変数 $a と $b の大小関係
を調べ、$a < $b なら -1 、$a == $b なら 0
$a > $b なら 1 を返す
ただし、ここでの $a, $b はユーザーが
定義して使う変数 $a, $b とは別物である。
@result = sort {$b cmp $a} @list 逆順に並べる
@result = sort {$a <=> $b} @list 数値を小さい順から並べる
<=> は数値を比べる演算子
@result = sort {length($a) <=> length($b)} 文字長が短い順に並べる
@result = sort {length($b) <=> length($a)} 文字長が長い順に並べる
@all = <>; 入力を行で区切って配列 @all に入れる
$| = 1;
shift @list; $list[0] <-- $list[1] $list[1] <-- $list[2] $list[2] <-- $list[3] unshift(@list,"top_item"); $list[0] <-- "top_item" $list[1] <-- $list[0] $list[2] <-- $list[1]
$msgfile = "/tmp/$$.tmp";
open(FP,"> $msgfile");
print FP "xxx\n";
print FP "$0 is executed normally.\n";
close(FP);
system("/usr/bin/mail -s 'Report from $0' $ENV{USER} < $msgfile");
C と全く同じ
正常終了のとき返り値は 0
Command not found などで異常終了のとき返り値は -1
C-C で Abort したときの返り値は 2 65280 など。よくわからない。0 以外であることは間違いない。
エラー処理を付加した system 文の例
sub ysystem
{
my($command) = @_;
if ( system($command) != 0 ){
print STDERR "error occurs in executing : $command\n";
exit 1;
}
}
sleep 1 1 秒待つ select(undef, undef, undef, 0.1) 0.1 秒待つ
# 以降はコメント __END__ 以降は無視される
$host = "denki.nara-edu.ac.jp";
($hname,$aliases,$addrtyp,$length,@addrs) = gethostbyname($host);
$addr = "192.168.107.50";
$host = gethostbyaddr(pack("C4", split(/\./, $addr)), 2);
ディレクトリの新規作成の階層は 1 階層しかサポートしていない
sub command{
my($command) = @_;
print "$command\n";
system($command);
}
sub copy{
my($source_fname,$dist_fname) = @_;
if ( ! -e $source_fname ){
print "file $source_fname does not exist.\n";
return;
}
@stat1 = stat($source_fname); # $stat1[9] に更新時刻が入る
@stat2 = stat($dist_fname); # $stat2[9] に更新時刻が入る
if ( $stat1[9] > $stat2[9] ){
$dist_fname =~ m/(^\S+)\/(\S+)$/; # ファイルが格納されるディレクトリ
$dist_dir = $1;
$dist_dir =~ m/(^\S+)\/(\S+)$/;
$dist_dir1 = $1; # その親ディレクトリ
$dist_dir2 = $2; # ディレクトリ名のみ
if ( -e $dist_dir ){
} else {
command("cd $dist_dir1; mkdir $dist_dir2");
}
command("cp $source_fname $dist_fname");
}
}
active perl 64bit 版 5.14 をインストールすると C:\Perl64 以下にインストールされる。path 変数の先頭に C:\perl64\site\bin; C:\perl64\bin が加えられ、拡張子 pl に C:\perl64\bin\perl.exe が結びつけられる。 pl ファイルをダブルクリックするとエラーが発生しても エラーメッセージを見ることが出来ない (DOS 窓らしきものが一瞬表示されるが視認できない)。 DOS 窓から ...>perl script-name.pl として実行するのが良さそうだ。
引用元
# ファイルの場合
@stat = stat($fname);
@time = localtime($stat[9]);
# 現在時刻
@time = localtime;
# @time 配列の処理
@youbi = ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat');
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = @time;
$year += 1900;
$mon += 1;
$line = "$year/$mon/$mday $youbi[$wday] $hour:$min:$sec";
print "$line\n";