- 名前
- 説明
- 出力ファイルハンドルを flush/unbufferするには? なぜ私はこれをやらなければならないの?
- ファイルの一行を変更する/ファイルのある行を削除する/ファイルの中程で一行挿入する/ファイルの先頭に追加するには?
- あるファイルの行数を数えるには?
- How can I use Perl's
-i
option from within a program? - ファイルをコピーするには?
- 一時ファイルの名前を作り出すには?
- 固定長レコードのファイルを操作するには?
- ファイルハンドルをサブルーチンに局所化するには? サブルーチンにファイルハンドルを渡すには? ファイルハンドルの配列を作るには?
- ファイルハンドルを間接的に扱うには?
- write()と一緒に使うフッターのフォーマットのセットアップをする方法は?
- 文字列に対して write() するには?
- ファイルハンドルを文字列としてオープンするには?
- 出力する数字にカンマを付加するには?
- ファイル名の中にあるチルダ (~) を変換するには?
- ファイルを読み書きモードでオープンしたときに内容をクリアしてしまうのはなぜ?
- なぜ <*> を使ったときに "Argument list too long" (引数リストが長すぎる)となることがあるの?
- glob()に leak/bug はあるの?
- 名前の先頭に">"があったり末尾に空白があるようなファイルをオープンするには?
- 信頼性のあるファイルのリネームをするには?
- ファイルをロックするには?
- なぜ単に open(FH, ">file.lock")とできないの?
- まだロックができません。ただ単にファイルにある数値をインクリメントしたいだけなんだけど。どうすればいいの?
- ファイルの末尾にちょっとしたテキストを追加したいだけなんです。それでもロックが必要なの?
- バイナリファイルをランダムに更新するには?
- perl でファイルのタイムスタンプを取得するには?
- perl でファイルのタイムスタンプを設定するには?
- 複数のファイルを一度に表示するには?
- ファイル全体を一度に読みこむには?
- ファイルをパラグラフ毎に読み込むには?
- ファイルから 1 文字だけ読み出すには? キーボードからは?
- あるファイルハンドルが読み込み待ちの文字を待っているかどうかを知るには?
- How do I do a
tail -f
in perl? - Perl でファイルハンドルの dup() をするには?
- 数値によるファイル記述子をクローズするには?
- なぜ DOS のパスで "C:\temp\foo" が使えないの? なぜ `C:\temp\foo.exe` はうまくいかないの?
- なぜ glob("*.*") で全てのファイルを得られないの?
- Why does Perl let me delete read-only files? Why does
-i
clobber protected files? Isn't this a bug in Perl? - あるファイルからランダムに行を選択するには?
- 行の配列を出力したときになぜ余計なスペースがつくの?
- REVISION
- AUTHOR AND COPYRIGHT
名前¶
perlfaq5 - Files and Formats ($Revision$)
perlfaq5 - ファイルとフォーマット ($Revision$)
説明¶
This section deals with I/O and the "f" issues: filehandles, flushing, formats, and footers.
このセクションでは、入出力と“f”に関する事柄: ファイルハンドル (filehandle)、フラッシング(flushing)、フォーマット(format)、 フッター(footer)を扱います。
出力ファイルハンドルを flush/unbufferするには? なぜ私はこれをやらなければならないの?¶
Perl does not support truly unbuffered output (except insofar as you can syswrite(OUT, $char, 1)
), although it does support is "command buffering", in which a physical write is performed after every output command.
Perlは本当のバッファリングなし出力をサポートしてはいません (syswrite(OUT, $char, 1)
のようにできることは除きます)が、 “コマンドバッファリング”をサポートしています。 これは各コマンドの出力の後で物理的な書き出しが行われるというものです。
The C standard I/O library (stdio) normally buffers characters sent to devices so that there isn't a system call for each byte. In most stdio implementations, the type of output buffering and the size of the buffer varies according to the type of device. Perl's print()
and write()
functions normally buffer output, while syswrite()
bypasses buffering all together.
Cの標準入出力ライブラリ(stdio)は、通常はキャラクターをバッファリングして デバイスへ送出するので、バイト単位のシステムコールはありません。 大部分のstdioの実装では、バッファリングの方式とバッファのサイズは デバイスの型に従ったものになっています。 Perl の print()
関数と write()
関数は通常出力を バッファリングしますが、syswrite()
関数はバッファリングを バイパスします。
If you want your output to be sent immediately when you execute print()
or write()
(for instance, for some network protocols), you must set the handle's autoflush flag. This flag is the Perl variable $|
and when it is set to a true value, Perl will flush the handle's buffer after each print()
or write()
. Setting $|
affects buffering only for the currently selected default filehandle. You choose this handle with the one argument select()
call (see "$|" in perlvar and "select" in perlfunc).
(例えば、何らかのネットワークプロトコルのために) print()
や write()
の実行後直ちに出力したいなら、そのハンドルの 自動フラッシュフラグをセットしなければなりません。 このフラグは Perl 変数$|
で、これを真の値にセットすると、Perl は print()
や write()
の後にハンドルのバッファをフラッシュします。 $|
の設定は現在選択されているデフォルトファイルハンドルの バッファリングにのみ影響を与えます。 このハンドルは 1 引数の select()
呼び出しで選択します ("$|" in perlvar と "select" in perlfunc を参照してください)。
Use select()
to choose the desired handle, then set its per-filehandle variables.
目的のハンドルを選択するために select()
を使い、それからその ファイルハンドル単位の変数をセットします。
$old_fh = select(OUTPUT_HANDLE);
$| = 1;
select($old_fh);
Some modules offer object-oriented access to handles and their variables, although they may be overkill if this is the only thing you do with them. You can use IO::Handle
:
ハンドルとその変数にオブジェクト指向でアクセスできるようにするモジュールも ありますが、あなたが単にこれだけをしたいなら大仰過ぎるかもしれません。 IO::Handle
が使えます:
use IO::Handle;
open my( $printer ), ">", "/dev/printer"); # but is this?
$printer->autoflush(1);
or IO::Socket
(which inherits from IO::Handle
):
または、(IO::Handle
から継承された)IO::Socket
を使って:
use IO::Socket; # this one is kinda a pipe?
my $sock = IO::Socket::INET->new( 'www.example.com:80' );
$sock->autoflush();
You can also flush an IO::Handle
object without setting autoflush
. Call the flush
method to flush the buffer yourself:
autoflush
をセットせずに IO::Handle
オブジェクトをフラッシュできます。 バッファ自身をフラッシュするために flush
メソッドを呼び出してください:
use IO::Handle;
open my( $printer ), ">", "/dev/printer");
$printer->flush; # one time flush
ファイルの一行を変更する/ファイルのある行を削除する/ファイルの中程で一行挿入する/ファイルの先頭に追加するには?¶
(contributed by brian d foy)
(brian d foy によって寄贈されました)
The basic idea of inserting, changing, or deleting a line from a text file involves reading and printing the file to the point you want to make the change, making the change, then reading and printing the rest of the file. Perl doesn't provide random access to lines (especially since the record input separator, $/
, is mutable), although modules such as Tie::File
can fake it.
テキストファイルの行を挿入、変更、削除するための基本的な考え方は、 ファイルを変更したい地点まで読み込んで表示し、変更を行い、ファイルの 残りを読み込んで表示するというものです。 (特にレコード入力セパレータ $/
は変更可能なので) Perl は行に対する ランダムアクセスは提供していませんが、Tie::File
はそれを見せかけます。
A Perl program to do these tasks takes the basic form of opening a file, printing its lines, then closing the file:
この作業をする Perl プログラムは、ファイルを開いて、一行毎に表示し、 ファイルを閉じるという基本的な形をとります:
open my $in, '<', $file or die "Can't read old file: $!";
open my $out, '>', "$file.new" or die "Can't write new file: $!";
while( <$in> )
{
print $out $_;
}
close $out;
Within that basic form, add the parts that you need to insert, change, or delete lines.
基本形の中に、行の追加、修正、削除という必要な作業を追加します。
To prepend lines to the beginning, print those lines before you enter the loop that prints the existing lines.
先頭に追加するには、既存の行を表示するループに入る前に追加行を表示します。
open my $in, '<', $file or die "Can't read old file: $!";
open my $out, '>', "$file.new" or die "Can't write new file: $!";
print "# Add this line to the top\n"; # <--- HERE'S THE MAGIC
while( <$in> )
{
print $out $_;
}
close $out;
To change existing lines, insert the code to modify the lines inside the while
loop. In this case, the code finds all lowercased versions of "perl" and uppercases them. The happens for every line, so be sure that you're supposed to do that on every line!
既にある行を変更するには、while
の中に行を変更するコードを追加します。 今回の場合、コードは小文字の "perl" を探してそれを大文字にします。 これは全ての行に対して起こるので、全ての行に対してこれを行いたいということを 確認してください!
open my $in, '<', $file or die "Can't read old file: $!";
open my $out, '>', "$file.new" or die "Can't write new file: $!";
print "# Add this line to the top\n";
while( <$in> )
{
s/\b(perl)\b/Perl/g;
print $out $_;
}
close $out;
To change only a particular line, the input line number, $.
, is useful. First read and print the lines up to the one you want to change. Next, read the single line you want to change, change it, and print it. After that, read the rest of the lines and print those:
特定の行だけ変更するには、入力行番号 $.
が便利です。 まず、変更したい行まで読み込んで表示します。 次に、変更したい行を 1 行読んで、変更し、表示します。 その後、残りの行を読み込んで表示します:
while( <$in> ) # print the lines before the change
{
print $out $_;
last if $. == 4; # line number before change
}
my $line = <$in>;
$line =~ s/\b(perl)\b/Perl/g;
print $out $line;
while( <$in> ) # print the rest of the lines
{
print $out $_;
}
To skip lines, use the looping controls. The next
in this example skips comment lines, and the last
stops all processing once it encounters either __END__
or __DATA__
.
行を読み飛ばすには、ループ制御を使います。 この例の next
はコメント行を読み飛ばし、last
は、__END__
か __DATA__
のどちらかに出会った後は全ての処理を停止します。
while( <$in> )
{
next if /^\s+#/; # skip comment lines
last if /^__(END|DATA)__$/; # stop at end of code marker
print $out $_;
}
Do the same sort of thing to delete a particular line by using next
to skip the lines you don't want to show up in the output. This example skips every fifth line:
同じようなことは、next
を使って表示したくない行を飛ばすことで行えます。
while( <$in> )
{
next unless $. % 5;
print $out $_;
}
If, for some odd reason, you really want to see the whole file at once rather than processing line by line, you can slurp it in (as long as you can fit the whole thing in memory!):
もし、なんらかの変わった理由により、一行ずつ処理するのではなく、本当に ファイル全体を一度に読み込みたい場合、(メモリがあれば!)以下のようにして できます:
open my $in, '<', $file or die "Can't read old file: $!"
open my $out, '>', "$file.new" or die "Can't write new file: $!";
my @lines = do { local $/; <$in> }; # slurp!
# do your magic here
print $out @lines;
Modules such as File::Slurp
and Tie::File
can help with that too. If you can, however, avoid reading the entire file at once. Perl won't give that memory back to the operating system until the process finishes.
File::Slurp
や Tie::File
のようなモジュールもこの助けになります。 しかし、もし可能なら、ファイル全体を一度に読み込むのは避けてください。 Perl は OS から確保したメモリを、プロセスが終わるまで返しません。
You can also use Perl one-liners to modify a file in-place. The following changes all 'Fred' to 'Barney' in inFile.txt, overwriting the file with the new contents. With the -p
switch, Perl wraps a while
loop around the code you specify with -e
, and -i
turns on in-place editing. The current line is in $_
. With -p
, Perl automatically prints the value of $_
at the end of the loop. See perlrun for more details.
ファイルをその場で変更するために、Perl の一行野郎も使えます。 以下の例では、inFile.txt にある全ての 'Fred' を 'Barney' に変更し、 ファイルを新しい内容で上書きします。 -p
スイッチ付きの場合、-e
で指定したコードを while
ループで包み、 -i
はその場編集を有効にします。 現在行は $_
に入っています。 -p
があると、Perl はループの最後に $_
の値を自動的に表示します。 さらなる詳細については perlrun を参照してください。
perl -pi -e 's/Fred/Barney/' inFile.txt
To make a backup of inFile.txt
, give -i
a file extension to add:
inFile.txt
をバックアップするには、-i
で追加する拡張子を指定します:
perl -pi.bak -e 's/Fred/Barney/' inFile.txt
To change only the fifth line, you can add a test checking $.
, the input line number, then only perform the operation when the test passes:
5 行目だけを変更するには、入力行番号 $.
をチェックするテストを追加し、 テストに通過した場合にのみ操作を行います:
perl -pi -e 's/Fred/Barney/ if $. == 5' inFile.txt
To add lines before a certain line, you can add a line (or lines!) before Perl prints $_
:
特定の行の前に追加するには、Perl が $_
を表示する前に行を追加します:
perl -pi -e 'print "Put before third line\n" if $. == 3' inFile.txt
You can even add a line to the beginning of a file, since the current line prints at the end of the loop:
現在行はループの終わりに表示されるので、ファイルの先頭に行を 追加することもできます:
perl -pi -e 'print "Put before first line\n" if $. == 1' inFile.txt
To insert a line after one already in the file, use the -n
switch. It's just like -p
except that it doesn't print $_
at the end of the loop, so you have to do that yourself. In this case, print $_
first, then print the line that you want to add.
既にファイルにある行の後に行を追加するには、-n
スイッチを使います。 これは -p
と同様ですが、ループの終わりに $_
を表示しないので、 自分自身で表示する必要があります。 この場合、まず $_
を表示し、それから追加したい行を表示します。
perl -ni -e 'print; print "Put after fifth line\n" if $. == 5' inFile.txt
To delete lines, only print the ones that you want.
行を削除するには、必要なものだけを表示します:
perl -ni -e 'print unless /d/' inFile.txt
... or ...
perl -pi -e 'next unless /d/' inFile.txt
あるファイルの行数を数えるには?¶
One fairly efficient way is to count newlines in the file. The following program uses a feature of tr///, as documented in perlop. If your text file doesn't end with a newline, then it's not really a proper text file, so this may report one fewer line than you expect.
非常に効率の良いやり方の一つはファイルの改行の数を数えるというものです。 以下のプログラムはperlopで説明されているようなtr///の機能を使っています。 テキストファイルが改行で終わっていなければ、 それは適切なテキストファイルではありません。 そのため、期待しているよりも一少ない行数を報告するでしょう。
$lines = 0;
open(FILE, $filename) or die "Can't open `$filename': $!";
while (sysread FILE, $buffer, 4096) {
$lines += ($buffer =~ tr/\n//);
}
close FILE;
This assumes no funny games with newline translations.
これは改行に絡む妙な動作がないと仮定しています。
How can I use Perl's -i
option from within a program? ¶
(プログラム内から Perl の -i
オプションを使うには?)
-i
sets the value of Perl's $^I
variable, which in turn affects the behavior of <>
; see perlrun for more details. By modifying the appropriate variables directly, you can get the same behavior within a larger program. For example:
-i
は Perl の $^I
変数の値をセットし、これにより <>
の 振る舞いに影響を与えます; 更なる詳細については perlrun を 参照してください。 適切な変数を直接修正することによって、より大きなプログラムの中で同じ効果が 得られます。 例えば:
# ...
{
local($^I, @ARGV) = ('.orig', glob("*.c"));
while (<>) {
if ($. == 1) {
print "This line should appear at the top of each file\n";
}
s/\b(p)earl\b/${1}erl/i; # Correct typos, preserving case
print;
close ARGV if eof; # Reset $.
}
}
# $^I and @ARGV return to their old values here
This block modifies all the .c
files in the current directory, leaving a backup of the original data from each file in a new .c.orig
file.
このブロックはカレントディレクトリの全ての the .c
ファイルを修正し、 各ファイルの元データのバックアップを新しい .c.orig
ファイルに残します。
ファイルをコピーするには?¶
(contributed by brian d foy)
(brian d foy によって寄贈されました)
Use the File::Copy module. It comes with Perl and can do a true copy across file systems, and it does its magic in a portable fashion.
File::Copy モジュールをつかいましょう。 これは Perl に同梱されていて、ファイルシステム間で真のコピーが行われ、 移植性の面での細工がされています。
use File::Copy;
copy( $original, $new_copy ) or die "Copy failed: $!";
If you can't use File::Copy, you'll have to do the work yourself: open the original file, open the destination file, then print to the destination file as you read the original.
File::Copy が使えない場合、作業を自分自身でする必要があります: 元ファイルを開き、宛て先ファイルを開き、元ファイルから読んだものを宛て先 ファイルに書き込みます。
一時ファイルの名前を作り出すには?¶
If you don't need to know the name of the file, you can use open()
with undef
in place of the file name. The open()
function creates an anonymous temporary file.
もしファイル名を知る必要がないなら、open()
でファイル名の部分に undef
を指定します。 open()
関数は無名一時ファイルを作成します。
open my $tmp, '+>', undef or die $!;
Otherwise, you can use the File::Temp module.
さもなければ、File::Temp モジュールが使えます。
use File::Temp qw/ tempfile tempdir /;
$dir = tempdir( CLEANUP => 1 );
($fh, $filename) = tempfile( DIR => $dir );
# or if you don't need to know the filename
$fh = tempfile( DIR => $dir );
The File::Temp has been a standard module since Perl 5.6.1. If you don't have a modern enough Perl installed, use the new_tmpfile
class method from the IO::File module to get a filehandle opened for reading and writing. Use it if you don't need to know the file's name:
The File::Temp has been a standard module since Perl 5.6.1. If you don't have a modern enough Perl installed, IO::Fileモジュールにあるクラスメソッドnew_tmpfile
を使って 読み書きのためにオープンされたファイルハンドルを取得します。 ファイルがどんな名前なのかを知る必要がない場合はこれを使ってください。
use IO::File;
$fh = IO::File->new_tmpfile()
or die "Unable to make new temporary file: $!";
If you're committed to creating a temporary file by hand, use the process ID and/or the current time-value. If you need to have many temporary files in one process, use a counter:
一時ファイルの作成を手作業で行いたいのなら、 プロセスIDやその時点での時刻(あるいはこれら両方)を使用してください。 一つのプロセスで複数の一時ファイルを使用するのであれば、 カウンターを使用しましょう:
BEGIN {
use Fcntl;
my $temp_dir = -d '/tmp' ? '/tmp' : $ENV{TMPDIR} || $ENV{TEMP};
my $base_name = sprintf "%s/%d-%d-0000", $temp_dir, $$, time;
sub temp_file {
local *FH;
my $count = 0;
until( defined(fileno(FH)) || $count++ > 100 ) {
$base_name =~ s/-(\d+)$/"-" . (1 + $1)/e;
# O_EXCL is required for security reasons.
sysopen FH, $base_name, O_WRONLY|O_EXCL|O_CREAT;
}
if( defined fileno(FH) ) {
return (*FH, $base_name);
}
else {
return ();
}
}
}
固定長レコードのファイルを操作するには?¶
The most efficient way is using pack() and unpack(). This is faster than using substr() when taking many, many strings. It is slower for just a few.
最も効率的なやり方はpack() と unpack() を使うものです。 これは文字列が大量にあるときにはsubstr() を 使うよりも高速です。 速度低下もほとんどありません。
Here is a sample chunk of code to break up and put back together again some fixed-format input lines, in this case from the output of a normal, Berkeley-style ps:
以下に挙げたのは幾つかの固定フォーマットをした入力行に対して 分解を行ったり書き戻しをするコード片の例で、出力は Berkeley形式のpsに準じています。
# sample input line:
# 15158 p5 T 0:00 perl /home/tchrist/scripts/now-what
my $PS_T = 'A6 A4 A7 A5 A*';
open my $ps, '-|', 'ps';
print scalar <$ps>;
my @fields = qw( pid tt stat time command );
while (<$ps>) {
my %process;
@process{@fields} = unpack($PS_T, $_);
for my $field ( @fields ) {
print "$field: <$process{$field}>\n";
}
print 'line=', pack($PS_T, @process{@fields} ), "\n";
}
We've used a hash slice in order to easily handle the fields of each row. Storing the keys in an array means it's easy to operate on them as a group or loop over them with for. It also avoids polluting the program with global variables and using symbolic references.
それぞれの行のフィールドを簡単に扱うためにハッシュスライスを使いました。 キーを配列に保管するということは、これらをグループやループで簡単に扱えると いうことを意味します。 これはまた、グローバル変数とシンボリックリファレンスの使用でプログラムが 汚染されることを防ぎます。
ファイルハンドルをサブルーチンに局所化するには? サブルーチンにファイルハンドルを渡すには? ファイルハンドルの配列を作るには?¶
As of perl5.6, open() autovivifies file and directory handles as references if you pass it an uninitialized scalar variable. You can then pass these references just like any other scalar, and use them in the place of named handles.
perl5.6 から、open() にファイルハンドルやディレクトリハンドルとして未定義の スカラ変数を渡すと、これをリファレンスとして自動有効化します。 その後これらのリファレンスはその他のスカラと同じように扱え、名前付き ハンドルを指定する場所で使えます。
open my $fh, $file_name;
open local $fh, $file_name;
print $fh "Hello World!\n";
process_file( $fh );
If you like, you can store these filehandles in an array or a hash. If you access them directly, they aren't simple scalars and you need to give print
a little help by placing the filehandle reference in braces. Perl can only figure it out on its own when the filehandle reference is a simple scalar.
お好みなら、これらのファイルハンドルを配列やハッシュに保管することもできます。 これらを直接アクセスすると、これらは単なるスカラではないので、 ファイルハンドルを中かっこで囲むことで print
に少し助けを与える必要が あります。 Perl はファイルハンドルリファレンスが単純なスカラの場合にのみファイル ハンドルリファレンスと認識します。
my @fhs = ( $fh1, $fh2, $fh3 );
for( $i = 0; $i <= $#fhs; $i++ ) {
print {$fhs[$i]} "just another Perl answer, \n";
}
Before perl5.6, you had to deal with various typeglob idioms which you may see in older code.
perl5.6 より前では、古いコードにあるような、様々な型グロブの慣用法を 扱わなければなりません。
open FILE, "> $filename";
process_typeglob( *FILE );
process_reference( \*FILE );
sub process_typeglob { local *FH = shift; print FH "Typeglob!" }
sub process_reference { local $fh = shift; print $fh "Reference!" }
If you want to create many anonymous handles, you should check out the Symbol or IO::Handle modules.
大量の無名ハンドルを作りたいのであれば、 Symbol, FileHandle, IO::Handle といったモジュールを参照してください。
ファイルハンドルを間接的に扱うには?¶
An indirect filehandle is using something other than a symbol in a place that a filehandle is expected. Here are ways to get indirect filehandles:
間接ファイルハンドルは、あるファイルハンドルを期待している場所に置かれた シンボル以外のなにかを使っています。 以下に間接ファイルハンドルの例を挙げます:
$fh = SOME_FH; # bareword is strict-subs hostile
$fh = "SOME_FH"; # strict-refs hostile; same package only
$fh = *SOME_FH; # typeglob
$fh = \*SOME_FH; # ref to typeglob (bless-able)
$fh = *SOME_FH{IO}; # blessed IO::Handle from *SOME_FH typeglob
Or, you can use the new
method from one of the IO::* modules to create an anonymous filehandle, store that in a scalar variable, and use it as though it were a normal filehandle.
あるいは、FileHandleモジュールやIOモジュールのnew
メソッドを使い、 それをスカラー変数に格納してからそれを普通のファイルハンドルと 同じように扱います。
use IO::Handle; # 5.004 or higher
$fh = IO::Handle->new();
Then use any of those as you would a normal filehandle. Anywhere that Perl is expecting a filehandle, an indirect filehandle may be used instead. An indirect filehandle is just a scalar variable that contains a filehandle. Functions like print
, open
, seek
, or the <FH>
diamond operator will accept either a named filehandle or a scalar variable containing one:
上記のように作成して、後は普通のファイルハンドルと同じように使います。 Perlがファイルハンドルを期待しているところではどこでも 間接ファイルハンドルを使うことができるでしょう。 間接ファイルハンドルは、ファイルハンドルを保持しているスカラー変数に すぎません。print
, open
, seek
のような関数や、 ダイヤモンド演算子 <FH>
はファイルハンドルもファイルハンドルを 保持しているスカラー変数の両方とも受け付けます。
($ifh, $ofh, $efh) = (*STDIN, *STDOUT, *STDERR);
print $ofh "Type it: ";
$got = <$ifh>
print $efh "What was that: $got";
If you're passing a filehandle to a function, you can write the function in two ways:
ファイルハンドルを関数に渡した場合、渡される関数は二種類の書き方ができます:
sub accept_fh {
my $fh = shift;
print $fh "Sending to indirect filehandle\n";
}
Or it can localize a typeglob and use the filehandle directly:
型グロブを局所化して、ファイルハンドルを直接使うことも可能です:
sub accept_fh {
local *FH = shift;
print FH "Sending to localized filehandle\n";
}
Both styles work with either objects or typeglobs of real filehandles. (They might also work with strings under some circumstances, but this is risky.)
両方の形式とも、オブジェクトでも実際のファイルハンドルの型グロブでも動作します (ある場合においては文字列でも可能ですが、これはちょっとリスクがあります)。
accept_fh(*STDOUT);
accept_fh($handle);
In the examples above, we assigned the filehandle to a scalar variable before using it. That is because only simple scalar variables, not expressions or subscripts of hashes or arrays, can be used with built-ins like print
, printf
, or the diamond operator. Using something other than a simple scalar variable as a filehandle is illegal and won't even compile:
上の例では、ファイルハンドルを使う前にそれをスカラー変数に代入していました。 これは式でもなく、ハッシュや配列の添え字でもなく単純スカラ変数だけが print
やprintf
、ダイヤモンド演算子と一緒に使えるからです。 単純スカラ変数以外のものをファイルハンドルとして使うのは不正であり、 コンパイル時にエラーとなります:
@fd = (*STDIN, *STDOUT, *STDERR);
print $fd[1] "Type it: "; # WRONG
$got = <$fd[0]> # WRONG
print $fd[2] "What was that: $got"; # WRONG
With print
and printf
, you get around this by using a block and an expression where you would place the filehandle:
print
やprintf
の場合には、ブロックを使ってその中にファイルハンドルを 含む式を置くことによって対処することができます:
print { $fd[1] } "funny stuff\n";
printf { $fd[1] } "Pity the poor %x.\n", 3_735_928_559;
# Pity the poor deadbeef.
That block is a proper block like any other, so you can put more complicated code there. This sends the message out to one of two places:
これらのブロックは妥当なものですから、より複雑なコードをその中に 入れこむことができます。 以下の例はメッセージを二ヶ所のどちらかひとつに送り出します:
$ok = -x "/bin/cat";
print { $ok ? $fd[1] : $fd[2] } "cat stat $ok\n";
print { $fd[ 1+ ($ok || 0) ] } "cat stat $ok\n";
This approach of treating print
and printf
like object methods calls doesn't work for the diamond operator. That's because it's a real operator, not just a function with a comma-less argument. Assuming you've been storing typeglobs in your structure as we did above, you can use the built-in function named readline
to read a record just as <>
does. Given the initialization shown above for @fd, this would work, but only because readline() requires a typeglob. It doesn't work with objects or strings, which might be a bug we haven't fixed yet.
このアプローチはprint
やprintf
をオブジェクトメソッドの呼び出しのように 扱うものですが、これはダイヤモンド演算子には使えません。 なぜなら、ダイヤモンド演算子はカンマなしの引数を取る関数ではなくて本当の 演算子だからです。 さて、上記の例のように型グロブをあなたの作った構造に格納したとしましょう。 readline
という名前の組み込み関数を使って<>
が行うように レコードを読み込むことができます。 @fdを例にあったように初期化してやることでうまく動作します。 しかし、readline()は型グロブを要求するからです。 これはオブジェクトや文字列では動作しません。 このことはバグとも言えるもので現時点では修正されていません。
$got = readline($fd[0]);
Let it be noted that the flakiness of indirect filehandles is not related to whether they're strings, typeglobs, objects, or anything else. It's the syntax of the fundamental operators. Playing the object game doesn't help you at all here.
間接ファイルハンドルの妙な点はそれが文字列であるか、型グロブであるか、 オブジェクトであるか、はたまた別の何者であるかには関係しないということに 注意してください。 これは基本的な演算子の構文なのです。 オブジェクトをいじくりまわして遊ぶことはここでは何の助けにもなりません。
write()と一緒に使うフッターのフォーマットのセットアップをする方法は?¶
There's no builtin way to do this, but perlform has a couple of techniques to make it possible for the intrepid hacker.
これを行うための組み込みの方法はありません。 しかしperlformにはこれを可能にするための、大胆不敵なハッカー向けの いくつかのテクニックがあります。
文字列に対して write() するには?¶
See "Accessing Formatting Internals" in perlform for an swrite()
function.
"Accessing Formatting Internals" in perlformの swrite()
関数を参照してください。
ファイルハンドルを文字列としてオープンするには?¶
(contributed by Peter J. Holzer, [email protected])
(Peter J. Holzer, [email protected] によって寄贈されました)
Since Perl 5.8.0, you can pass a reference to a scalar instead of the filename to create a file handle which you can used to read from or write to a string:
Perl 5.8.0 から、文字列を読み書きできるファイルハンドルを作るために、 ファイル名の変わりにスカラへのリファレンスを渡せます:
open(my $fh, '>', \$string) or die "Could not open string for writing";
print $fh "foo\n";
print $fh "bar\n"; # $string now contains "foo\nbar\n"
open(my $fh, '<', \$string) or die "Could not open string for reading";
my $x = <$fh>; # $x now contains "foo\n"
With older versions of Perl, the IO::String
module provides similar functionality.
Perl のより古いバージョンでは、IO::String
モジュールが似たような機能を 提供します。
出力する数字にカンマを付加するには?¶
(contributed by brian d foy and Benjamin Goldberg)
(brian d foy と Benjamin Goldberg によって寄贈されました)
You can use Number::Format to separate places in a number. It handles locale information for those of you who want to insert full stops instead (or anything else that they want to use, really).
数値を区切るために Number::Format が使えます。 これは代わりにピリオド(または実際のところは使いたいもの何でも)を 挿入したい人のために、ロケール情報を扱います。
This subroutine will add commas to your number:
このサブルーチンは数値にカンマを追加します:
sub commify {
local $_ = shift;
1 while s/^([-+]?\d+)(\d{3})/$1,$2/;
return $_;
}
This regex from Benjamin Goldberg will add commas to numbers:
Benjamin Goldberg による正規表現は数値にカンマを追加します:
s/(^[-+]?\d+?(?=(?>(?:\d{3})+)(?!\d))|\G\d{3}(?=\d))/$1,/g;
It is easier to see with comments:
コメント付きで見ればより簡単になります:
s/(
^[-+]? # beginning of number.
\d+? # first digits before first comma
(?= # followed by, (but not included in the match) :
(?>(?:\d{3})+) # some positive multiple of three digits.
(?!\d) # an *exact* multiple, not x * 3 + 1 or whatever.
)
| # or:
\G\d{3} # after the last group, get three digits
(?=\d) # but they have to have more digits after them.
)/$1,/xg;
ファイル名の中にあるチルダ (~) を変換するには?¶
Use the <> (glob()) operator, documented in perlfunc. Older versions of Perl require that you have a shell installed that groks tildes. Recent perl versions have this feature built in. The File::KGlob module (available from CPAN) gives more portable glob functionality.
perlfuncで説明されている <> (glob()) を使います。 古いバージョンの Perl では、チルダを展開するシェルが既に インストールされていることを要求します。 最近のバージョンの Perl は内部にこの機能を持っています。 Glob::KGlob モジュール(CPANで入手可能)はより移植性のあるglob機能を提供します。
Within Perl, you may use this directly:
Perl を使えば、これを以下のように直接的に行えます。
$filename =~ s{
^ ~ # find a leading tilde
( # save this in $1
[^/] # a non-slash character
* # repeated 0 or more times (0 means me)
)
}{
$1
? (getpwnam($1))[7]
: ( $ENV{HOME} || $ENV{LOGDIR} )
}ex;
ファイルを読み書きモードでオープンしたときに内容をクリアしてしまうのはなぜ?¶
Because you're using something like this, which truncates the file and then gives you read-write access:
ファイルを切り詰めて、その後で読み書きアクセスを提供するようなものを 使おうとしたからです。
open(FH, "+> /path/name"); # WRONG (almost always)
Whoops. You should instead use this, which will fail if the file doesn't exist.
おっと。 ファイルがなかったときに失敗するような以下のやり方を使うべきでしょう。
open(FH, "+< /path/name"); # open for update
Using ">" always clobbers or creates. Using "<" never does either. The "+" doesn't change this.
">"を使うと常に切り詰めか作成が行われます。 "<"を使った場合にはどちらも行いません。 "+"はこれらを変更することはありません。
Here are examples of many kinds of file opens. Those using sysopen() all assume
ファイルをオープンする多くのやり方の例を以下に挙げます。 sysopenを使っているものはすべてを以下をしているものと仮定します。
use Fcntl;
To open file for reading:
ファイルを読み込みのためにオープンするには:
open(FH, "< $path") || die $!;
sysopen(FH, $path, O_RDONLY) || die $!;
To open file for writing, create new file if needed or else truncate old file:
ファイルを書き出しのためにオープンし、ファイルがなければ新しく作り あれば古いファイルを切り詰めるには:
open(FH, "> $path") || die $!;
sysopen(FH, $path, O_WRONLY|O_TRUNC|O_CREAT) || die $!;
sysopen(FH, $path, O_WRONLY|O_TRUNC|O_CREAT, 0666) || die $!;
To open file for writing, create new file, file must not exist:
ファイルを書き出しのためにオープンし、ファイルを新たに作成するが 慈善に存在していてはいけない場合:
sysopen(FH, $path, O_WRONLY|O_EXCL|O_CREAT) || die $!;
sysopen(FH, $path, O_WRONLY|O_EXCL|O_CREAT, 0666) || die $!;
To open file for appending, create if necessary:
ファイルを追加のためにオープンし、必要があればファイルを作成するには:
open(FH, ">> $path") || die $!;
sysopen(FH, $path, O_WRONLY|O_APPEND|O_CREAT) || die $!;
sysopen(FH, $path, O_WRONLY|O_APPEND|O_CREAT, 0666) || die $!;
To open file for appending, file must exist:
ファイルを追加のためにオープンするが、ファイルが事前になければいけない場合:
sysopen(FH, $path, O_WRONLY|O_APPEND) || die $!;
To open file for update, file must exist:
ファイルを更新のためにオープンするが、ファイルが事前になければいけない場合:
open(FH, "+< $path") || die $!;
sysopen(FH, $path, O_RDWR) || die $!;
To open file for update, create file if necessary:
ファイルを更新のためにオープンし、必要があればファイルを作成する場合:
sysopen(FH, $path, O_RDWR|O_CREAT) || die $!;
sysopen(FH, $path, O_RDWR|O_CREAT, 0666) || die $!;
To open file for update, file must not exist:
ファイルを更新のためにオープンするが、ファイルが事前に存在してはいけない場合:
sysopen(FH, $path, O_RDWR|O_EXCL|O_CREAT) || die $!;
sysopen(FH, $path, O_RDWR|O_EXCL|O_CREAT, 0666) || die $!;
To open a file without blocking, creating if necessary:
ブロッキングなしでフィルをオープンし、必要があれば作成するには:
sysopen(FH, "/foo/somefile", O_WRONLY|O_NDELAY|O_CREAT)
or die "can't open /foo/somefile: $!":
Be warned that neither creation nor deletion of files is guaranteed to be an atomic operation over NFS. That is, two processes might both successfully create or unlink the same file! Therefore O_EXCL isn't as exclusive as you might wish.
ファイルの作成や削除はNFS越しの場合にはアトミックな操作ではないことに 注意してください。 つまり、二つのプロセスが同じファイルの作成や削除に成功するかもしれないのです! したがってO_EXCLはあなたが期待しているようには排他的ではないのです。
See also the new perlopentut if you have it (new for 5.6).
もしあれば 新しい perlopentut (5.6 対応) も参照して下さい。
なぜ <*> を使ったときに "Argument list too long" (引数リストが長すぎる)となることがあるの?¶
The <>
operator performs a globbing operation (see above). In Perl versions earlier than v5.6.0, the internal glob() operator forks csh(1) to do the actual glob expansion, but csh can't handle more than 127 items and so gives the error message Argument list too long
. People who installed tcsh as csh won't have this problem, but their users may be surprised by it.
<*> 演算子はグロブ操作(globbing operation)を行います。 v5.6.0 以前の Perl では、glob() はcsh(1)を起動して、 実際のグロブを行います。 しかし、cshは127を越えるアイテムを扱うことができないので、 そういったエラーメッセージ Argument list too long
となるのです。 cshをcshとしてインストールしている人はこの問題に直面することはないでしょうが、 ユーザーがびっくりすることがあるかもしれません。
To get around this, either upgrade to Perl v5.6.0 or later, do the glob yourself with readdir() and patterns, or use a module like File::KGlob, one that doesn't use the shell to do globbing.
これに対処するには、Perl v5.6.0 以降にアップグレードするか グロブをreaddir()とパターンを使って 自分自身で実行するか、あるいはGlob::KGlobのようなモジュールを使って、 シェルによるグロブを行わないようにします。
glob()に leak/bug はあるの?¶
Due to the current implementation on some operating systems, when you use the glob() function or its angle-bracket alias in a scalar context, you may cause a memory leak and/or unpredictable behavior. It's best therefore to use glob() only in list context.
一部のオペレーティングシステム上の実装のために、 glob()関数やスカラーコンテキストでのアングルブラケットによる そのエイリアスを使った場合、メモリリークや予測できない振る舞いを 引き起こす可能性があります。 したがって、glob()はリストコンテキストでのみ使うのが最善です。
名前の先頭に">"があったり末尾に空白があるようなファイルをオープンするには?¶
(contributed by Brian McCauley)
(Brian McCauley によって寄贈されました)
The special two argument form of Perl's open() function ignores trailing blanks in filenames and infers the mode from certain leading characters (or a trailing "|"). In older versions of Perl this was the only version of open() and so it is prevalent in old code and books.
Perl の open() 関数の特殊な 2 引数形式はファイル名の末尾の空白を無視し、 先頭の文字 (あるいは末尾の "|") からモードを推論します。 古いバージョンの Perl ではこれが open() の唯一の形式なので、古いコードや 本には普及しています。
Unless you have a particular reason to use the two argument form you should use the three argument form of open() which does not treat any characters in the filename as special.
2 引数形式を使う特有の理由がない限り、ファイル名のどの文字も特別なものとして 扱わない 3 引数形式の open() を使うべきです。
open FILE, "<", " file "; # filename is " file "
open FILE, ">", ">file"; # filename is ">file"
信頼性のあるファイルのリネームをするには?¶
If your operating system supports a proper mv(1) utility or its functional equivalent, this works:
あなたの使っているオペレーティングシステムが、適切な mv(1) あるいは それと機能的に等価なプログラムをサポートしているのなら以下のような やり方が使えるでしょう:
rename($old, $new) or system("mv", $old, $new);
It may be more portable to use the File::Copy module instead. You just copy to the new file to the new name (checking return values), then delete the old one. This isn't really the same semantically as a rename(), which preserves meta-information like permissions, timestamps, inode info, etc.
File::Copy モジュールを使うのが、より移植性があるかもしれません。 新しい名前で新しいファイルにコピーして(ここで戻り値をチェック)、 古いものを削除するだけです。 ただし、これはパーミッション、タイムスタンプ、inode情報といった メタ情報が保存されないので、rename() と同じにはなりません。
Newer versions of File::Copy export a move() function.
新しいバージョンのFile::Copyは関数move()をエクスポートしています。
ファイルをロックするには?¶
Perl's builtin flock() function (see perlfunc for details) will call flock(2) if that exists, fcntl(2) if it doesn't (on perl version 5.004 and later), and lockf(3) if neither of the two previous system calls exists. On some systems, it may even use a different form of native locking. Here are some gotchas with Perl's flock():
Perlに組み込みの flock関数(詳しくはperlfuncを参照)は、flock(2)が あればそれを、なければfcntl(2)を呼び出します(5.004以降の場合)。 そして、これら二つのシステムコールのいずれもない場合にはlockf(3)を 呼び出します。 一部のシステムでは、ネイティブなロッキングとは異なった使い方を するかもしれません。 以下に、Perlのflock()に関する罠(gotchas)を挙げておきます:
-
Produces a fatal error if none of the three system calls (or their close equivalent) exists.
三つのシステムコールがどれもなければ(もしくは等価なものがなければ)、 致命的エラーを生成します。
-
lockf(3) does not provide shared locking, and requires that the filehandle be open for writing (or appending, or read/writing).
lockf(3)は共有ロックをサポートしません。そして、書き込み用に(もしくは 追加モードか読み書きモード)オープンされているファイルハンドルを要求します。
-
Some versions of flock() can't lock files over a network (e.g. on NFS file systems), so you'd need to force the use of fcntl(2) when you build Perl. But even this is dubious at best. See the flock entry of perlfunc and the INSTALL file in the source distribution for information on building Perl to do this.
flock()の一部のバージョンはネットワーク越し(NFSファイルシステムなど)に ファイルをロックすることはできません。 このため、Perlをビルドするときにfcntl(2)を使うように強制する必要が あるかもしれません。しかしこれでも最善かどうかは疑わしいです。 perlfuncのflock()のエントリと、そのためのPerlをビルドする 情報のある、ソース配布中にあるINSTALLというファイルを参照してください。
Two potentially non-obvious but traditional flock semantics are that it waits indefinitely until the lock is granted, and that its locks are merely advisory. Such discretionary locks are more flexible, but offer fewer guarantees. This means that files locked with flock() may be modified by programs that do not also use flock(). Cars that stop for red lights get on well with each other, but not with cars that don't stop for red lights. See the perlport manpage, your port's specific documentation, or your system-specific local manpages for details. It's best to assume traditional behavior if you're writing portable programs. (If you're not, you should as always feel perfectly free to write for your own system's idiosyncrasies (sometimes called "features"). Slavish adherence to portability concerns shouldn't get in the way of your getting your job done.)
二つの潜在的に明らかでないけれども、伝統的な flock の手法があります。 一つはロックが与えられるまで無限に待ち、そしてそのロックは めったに忠告されません。このような自由度の高いロックはより柔軟ですが、 得るものはより少ないです。 つまり、 flock() でロックされたファイルは flock() を使っていない プログラムによって修正される可能性があるからです。 赤信号で止まる車同士ならうまくいきますが、片方が信号を守らないなら うまくいかないということです。 詳細については perlport man ページ、使っているバージョン独自のドキュメント、 システム独自のローカルな man ページを参照してください。 移植性のあるプログラムのためには、伝統的な振る舞いを仮定するのが最善です。 (そうしないなら、あなたは自分のシステムの癖(「仕様」とも呼ばれます)に 合わせて書くことをいつでも気にしないようにするべきです。 あなたの仕事をやり遂げる時に、盲目的に移植性を考慮するべきではありません。)
For more information on file locking, see also "File Locking" in perlopentut if you have it (new for 5.6).
ファイルのロッキングに関する詳細は<perlopentut/"FileLocking">を 参照してください(5.6 対応)。
なぜ単に open(FH, ">file.lock")とできないの?¶
A common bit of code NOT TO USE is this:
以下のようなことを してはいけません:
sleep(3) while -e "file.lock"; # PLEASE DO NOT USE
open(LCK, "> file.lock"); # THIS BROKEN CODE
This is a classic race condition: you take two steps to do something which must be done in one. That's why computer hardware provides an atomic test-and-set instruction. In theory, this "ought" to work:
これは古典的な競合状態です: あなたはここで、 一つのステップでやらなければならないことを二つのステップでやっています。 つまりこれが、コンピューターのハードウェアがアトミックな test-and-set の命令を備えている理由です。 理論的には、これを動作するにさせるには:
sysopen(FH, "file.lock", O_WRONLY|O_EXCL|O_CREAT)
or die "can't open file.lock: $!";
except that lamentably, file creation (and deletion) is not atomic over NFS, so this won't work (at least, not every time) over the net. Various schemes involving link() have been suggested, but these tend to involve busy-wait, which is also less than desirable.
残念なことに、NFSを通じた場合にはファイルの作成(と削除)は アトミックではありません。 このため、この例はネットワークを通した場合にはうまく動きません (少なくとも失敗する可能性があります)。 link()を含め、様々なやり方が既に提案されていますが、これらは busy-waitを 伴うものでありあまり望ましいものではありません。
まだロックができません。ただ単にファイルにある数値をインクリメントしたいだけなんだけど。どうすればいいの?¶
Didn't anyone ever tell you web-page hit counters were useless? They don't count number of hits, they're a waste of time, and they serve only to stroke the writer's vanity. It's better to pick a random number; they're more realistic.
これまでただの一人もあなたにwebページのヒットカウンターは役たたずなんだと いうことを言わなかったんですか? ヒットカウンターはヒットした数は数えず、時間を浪費し、さらに言えば 作者のうぬぼれを叩くのに役立つだけです。 乱数を取り出したほうがよっぽどましです。
Anyway, this is what you can do if you can't help yourself.
まあいずれにしろ、以下のようにしてやります:
use Fcntl qw(:DEFAULT :flock);
sysopen(FH, "numfile", O_RDWR|O_CREAT) or die "can't open numfile: $!";
flock(FH, LOCK_EX) or die "can't flock numfile: $!";
$num = <FH> || 0;
seek(FH, 0, 0) or die "can't rewind numfile: $!";
truncate(FH, 0) or die "can't truncate numfile: $!";
(print FH $num+1, "\n") or die "can't write numfile: $!";
close FH or die "can't close numfile: $!";
Here's a much better web-page hit counter:
以下の例はもっと良い web ページヒットカウンターです:
$hits = int( (time() - 850_000_000) / rand(1_000) );
If the count doesn't impress your friends, then the code might. :-)
カウントがあなたの友達を感心させないのなら、このコードもそうでしょうね :-)
ファイルの末尾にちょっとしたテキストを追加したいだけなんです。それでもロックが必要なの?¶
If you are on a system that correctly implements flock() and you use the example appending code from "perldoc -f flock" everything will be OK even if the OS you are on doesn't implement append mode correctly (if such a system exists.) So if you are happy to restrict yourself to OSs that implement flock() (and that's not really much of a restriction) then that is what you should do.
もし flock() が正しく実装されているシステムを使っていて、 "perldoc -f flock" にある追加コードの例を使っているなら、たとえ使っている OS が追加モードを正しく実装していない(もしそのようなシステムがあれば) 場合でも、全てうまくいきます。 従って、実行する OS を flock() が実装されているものに制限してもよいなら (これは実際のところそれほど大きな制限ではありません)、そうするべきです。
If you know you are only going to use a system that does correctly implement appending (i.e. not Win32) then you can omit the seek() from the code in the previous answer.
正しく追加を実装している(つまり Win32 ではない)システムを 利用しているとわかっている場合のみ、以前の答えのコードから seek() を 省略できます。
If you know you are only writing code to run on an OS and filesystem that does implement append mode correctly (a local filesystem on a modern Unix for example), and you keep the file in block-buffered mode and you write less than one buffer-full of output between each manual flushing of the buffer then each bufferload is almost guaranteed to be written to the end of the file in one chunk without getting intermingled with anyone else's output. You can also use the syswrite() function which is simply a wrapper around your systems write(2) system call.
追加モードを正しく実装している OS とファイルシステム(例えば最近の Unix の ローカルファイルシステム)でのみ実行されることがわかっていて、 ファイルをブロックバッファモードのままに維持していて、 手動でのバッファのフラッシュの間にバッファがいっぱいになるほどの 書き込みを行わない場合は、それぞれのバッファは他からの出力が混ざることなく、 ファイルの末尾にひとつの塊で書き込まれることがほとんど保証されます write(2) システムコールの単なるラッパである syswrite() を使うことも できます。
There is still a small theoretical chance that a signal will interrupt the system level write() operation before completion. There is also a possibility that some STDIO implementations may call multiple system level write()s even if the buffer was empty to start. There may be some systems where this probability is reduced to zero.
未だに、理論的にはシステムレベルの write() 操作が終了前にシグナルが割り込む 可能性が少しあります。 STDIO の実装によっては、バッファが空からスタートしても、複数のシステム レベルの write() を呼び出すものがある可能性があります。 この確率を 0 にしているシステムもあるかもしれません。
バイナリファイルをランダムに更新するには?¶
If you're just trying to patch a binary, in many cases something as simple as this works:
単にバイナリにパッチをあてたいというのなら、多くの場合は以下のように 単純にできます:
perl -i -pe 's{window manager}{window mangler}g' /usr/bin/emacs
However, if you have fixed sized records, then you might do something more like this:
もし固定サイズのレコードを持っているのなら、以下のようにして行うことも できます:
$RECSIZE = 220; # size of record, in bytes
$recno = 37; # which record to update
open(FH, "+<somewhere") || die "can't update somewhere: $!";
seek(FH, $recno * $RECSIZE, 0);
read(FH, $record, $RECSIZE) == $RECSIZE || die "can't read record $recno: $!";
# munge the record
seek(FH, -$RECSIZE, 1);
print FH $record;
close FH;
Locking and error checking are left as an exercise for the reader. Don't forget them or you'll be quite sorry.
ロックとエラーチェックは読者の練習として残してあります。 これらを行うことを忘れてはいけません。 さもなくばとても後悔することになるでしょう。
perl でファイルのタイムスタンプを取得するには?¶
If you want to retrieve the time at which the file was last read, written, or had its meta-data (owner, etc) changed, you use the -A, -M, or -C file test operations as documented in perlfunc. These retrieve the age of the file (measured against the start-time of your program) in days as a floating point number. Some platforms may not have all of these times. See perlport for details. To retrieve the "raw" time in seconds since the epoch, you would call the stat function, then use localtime(), gmtime(), or POSIX::strftime() to convert this into human-readable form.
そのファイルが最後に読み込まれ、書き出され、そのメタデータ(所有者など)が 変更された時刻を取得したいのであれば、perlfuncに説明がある -A, -M, -C といったファイルテスト演算子を使います。 これらはファイルの年齢(あなたのプログラムの実行開始に対するもの)を 浮動小数点数で表現された日数で取得します。 プラットフォームによってはこれら全ては利用できないものもあります。 紀元からの経過秒数による“生の”時間を得るためには、 stat関数を呼び出して、その値をlocaltime()、gmtime()、POSIX::strftime()を 使って人が読めるような形へ変換します。
Here's an example:
例を挙げましょう:
$write_secs = (stat($file))[9];
printf "file %s updated at %s\n", $file,
scalar localtime($write_secs);
If you prefer something more legible, use the File::stat module (part of the standard distribution in version 5.004 and later):
もっと読みやすいものがお好みなら、File::statモジュールを使います (これは5.004以降の標準配布キットに含まれています)。
# error checking left as an exercise for reader.
use File::stat;
use Time::localtime;
$date_string = ctime(stat($file)->mtime);
print "file $file updated at $date_string\n";
The POSIX::strftime() approach has the benefit of being, in theory, independent of the current locale. See perllocale for details.
POSIX::strftime()アプローチは理論的にはロカール非依存で、 使う価値があります。詳しくはperllocaleを参照してください。
perl でファイルのタイムスタンプを設定するには?¶
You use the utime() function documented in "utime" in perlfunc. By way of example, here's a little program that copies the read and write times from its first argument to all the rest of them.
"utime" in perlfuncで説明されているutime()という関数を使います。 例として、引数の最初のファイルのread and write 時刻を読んで、 残りのファイルにその時刻を設定する小さなプログラムを挙げましょう。
if (@ARGV < 2) {
die "usage: cptimes timestamp_file other_files ...\n";
}
$timestamp = shift;
($atime, $mtime) = (stat($timestamp))[8,9];
utime $atime, $mtime, @ARGV;
Error checking is, as usual, left as an exercise for the reader.
例によって、エラーチェックは読者の練習として残してあります。
The perldoc for utime also has an example that has the same effect as touch(1) on files that already exist.
utime の perldoc には、既にある ファイルに対する touch(1) と同じ 効果のある例があります。
Certain file systems have a limited ability to store the times on a file at the expected level of precision. For example, the FAT and HPFS filesystem are unable to create dates on files with a finer granularity than two seconds. This is a limitation of the filesystems, not of utime().
予測されたレベルの制度でファイルの時刻を保存する能力が制限された ファイルシステムもあります。 例えば、FAT と HPFS は 2 秒よりも細かい精度でファイルの作成時刻を 設定できません。 これはファイルシステムの制限であり、utime() での問題でありません。
複数のファイルを一度に表示するには?¶
To connect one filehandle to several output filehandles, you can use the IO::Tee or Tie::FileHandle::Multiplex modules.
一つのファイルハンドルを複数の出力ファイルハンドルに接続するには、 IO::Tee や Tie::FileHandle::Multiplex のモジュールが使えます。
If you only have to do this once, you can print individually to each filehandle.
これをする必要があるのが一回だけなら、以下のようにしてできます:
for $fh (FH1, FH2, FH3) { print $fh "whatever\n" }
ファイル全体を一度に読みこむには?¶
You can use the File::Slurp module to do it in one step.
これを 1 ステップで行うためには、File::Slurp モジュールが使えます。
use File::Slurp;
$all_of_it = read_file($filename); # entire file in scalar
@all_lines = read_file($filename); # one line perl element
The customary Perl approach for processing all the lines in a file is to do so one line at a time:
Perl においてファイルの全ての行を処理するための慣例的な手法は 1 行ずつ読みこむことです:
open (INPUT, $file) || die "can't open $file: $!";
while (<INPUT>) {
chomp;
# do something with $_
}
close(INPUT) || die "can't close $file: $!";
This is tremendously more efficient than reading the entire file into memory as an array of lines and then processing it one element at a time, which is often--if not almost always--the wrong approach. Whenever you see someone do this:
これはファイル全体を行の配列として読みこんでから1行ずつ処理するという (ほとんど常に、でないのなら)しばしば誤った手法よりも 遥かに効率的です。 それでもファイル全体を読み込みたいなら以下のようにします:
@lines = <INPUT>;
you should think long and hard about why you need everything loaded at once. It's just not a scalable solution. You might also find it more fun to use the standard Tie::File module, or the DB_File module's $DB_RECNO bindings, which allow you to tie an array to a file so that accessing an element the array actually accesses the corresponding line in the file.
本当に全てを一度に読み込む必要があるのかを良く考えるべきです。 これは単にスケールの問題ではありません。 標準の Tie::File モジュールか DB_File モジュールの $DB_RECNO バインディングの方がより好ましいと考えるかもしれません。 これは配列とファイルを結び付けるので、配列にアクセスすると、実際には ファイルの対応する行にアクセスすることになります。
You can read the entire filehandle contents into a scalar.
ファイルハンドルの内容全体を一つのスカラ変数に読み込むことができます。
{
local(*INPUT, $/);
open (INPUT, $file) || die "can't open $file: $!";
$var = <INPUT>;
}
That temporarily undefs your record separator, and will automatically close the file at block exit. If the file is already open, just use this:
これは一時的にレコードセパレータを未定義にし、ブロックを出るときに 自動的にファイルをクローズします。ファイルが既にオープンしているなら、 単に以下のようにします:
$var = do { local $/; <INPUT> };
For ordinary files you can also use the read function.
通常のファイルの場合は read 関数も使えます。
read( INPUT, $var, -s INPUT );
The third argument tests the byte size of the data on the INPUT filehandle and reads that many bytes into the buffer $var.
3 番目の引数は INPUT ファイルハンドルのデータのバイトサイズをテストし、 そのバイト数だけバッファ $var に読み込みます。
ファイルをパラグラフ毎に読み込むには?¶
Use the $/
variable (see perlvar for details). You can either set it to ""
to eliminate empty paragraphs ("abc\n\n\n\ndef"
, for instance, gets treated as two paragraphs and not three), or "\n\n"
to accept empty paragraphs.
$/
という変数を使います(詳しくはperlvarを参照してください)。 たとえば ("abc\n\n\n\ndef"
で三つではなく二つのパラグラフを受 け取る、つまり空のパラグラフを除去するには""
を設定します。空 のパラグラフを受け付けるには"\n\n"
を設定します。
Note that a blank line must have no blanks in it. Thus "fred\n \nstuff\n\n"
is one paragraph, but "fred\n\nstuff\n\n"
is two.
空行はブランクを持っていてはいけないということに注意しましょう。 このため、"fred\n \nstuff\n\n"
は一つのパラグラフですが "fred\n\nstuff\n\n"
は二つのパラグラフです。
ファイルから 1 文字だけ読み出すには? キーボードからは?¶
You can use the builtin getc()
function for most filehandles, but it won't (easily) work on a terminal device. For STDIN, either use the Term::ReadKey module from CPAN or use the sample code in "getc" in perlfunc.
ほとんどのファイルハンドルに対してはgetc()
という組み込み関数を 使うことができますが、これはターミナルデバイスに対してはうまくいきません。 STDIN に対しては、CPAN にある Term::ReadKey を使うか "getc" in perlfuncにあるサンプルコードを使います。
If your system supports the portable operating system programming interface (POSIX), you can use the following code, which you'll note turns off echo processing as well.
あなたの使っているシステムがPOSIXをサポートしているのなら、echo を オフにしているのを気をつけながら以下のようなコードでできます。
#!/usr/bin/perl -w
use strict;
$| = 1;
for (1..4) {
my $got;
print "gimme: ";
$got = getone();
print "--> $got\n";
}
exit;
BEGIN {
use POSIX qw(:termios_h);
my ($term, $oterm, $echo, $noecho, $fd_stdin);
$fd_stdin = fileno(STDIN);
$term = POSIX::Termios->new();
$term->getattr($fd_stdin);
$oterm = $term->getlflag();
$echo = ECHO | ECHOK | ICANON;
$noecho = $oterm & ~$echo;
sub cbreak {
$term->setlflag($noecho);
$term->setcc(VTIME, 1);
$term->setattr($fd_stdin, TCSANOW);
}
sub cooked {
$term->setlflag($oterm);
$term->setcc(VTIME, 0);
$term->setattr($fd_stdin, TCSANOW);
}
sub getone {
my $key = '';
cbreak();
sysread(STDIN, $key, 1);
cooked();
return $key;
}
}
END { cooked() }
The Term::ReadKey module from CPAN may be easier to use. Recent versions include also support for non-portable systems as well.
CPAN にある Term::ReadKey モジュールならもっと簡単に使えます。 最新のバージョンでは non-portable システムのサポートも含まれています:
use Term::ReadKey;
open(TTY, "</dev/tty");
print "Gimme a char: ";
ReadMode "raw";
$key = ReadKey 0, *TTY;
ReadMode "normal";
printf "\nYou said %s, char number %03d\n",
$key, ord $key;
あるファイルハンドルが読み込み待ちの文字を待っているかどうかを知るには?¶
The very first thing you should do is look into getting the Term::ReadKey extension from CPAN. As we mentioned earlier, it now even has limited support for non-portable (read: not open systems, closed, proprietary, not POSIX, not Unix, etc) systems.
あなたがすべき第一のことは、CPAN にある Term::ReadKey を入手することです。 今では閉鎖的な独占システム (オープンなシステムではない、POSIX でもなく、UNIX でもないような…)に 対する限定的なサポートさえあります。
You should also check out the Frequently Asked Questions list in comp.unix.* for things like this: the answer is essentially the same. It's very system dependent. Here's one solution that works on BSD systems:
comp.unix.* の Frequently Asked Questions(しばしば尋ねられる質問)リストで、 同じようなものをチェックすべきでしょう: この答えは本質的に同じものです。 つまり、非常にシステム依存なものです。 以下に挙げたのは、BSDシステムで動作する解決策の一つです。
sub key_ready {
my($rin, $nfd);
vec($rin, fileno(STDIN), 1) = 1;
return $nfd = select($rin,undef,undef,0);
}
If you want to find out how many characters are waiting, there's also the FIONREAD ioctl call to be looked at. The h2ph tool that comes with Perl tries to convert C include files to Perl code, which can be require
d. FIONREAD ends up defined as a function in the sys/ioctl.ph file:
どの位のキャラクターが待っているのかを知りたいのであれば、 FIONREAD ioctl 呼び出しを使うことができます。 h2phツールは C のインクルードファイルを Perl に変換するもので、その結果は require
によって呼び出すことが可能です。 FIONREAD は sys/ioctl.ph にある関数として定義されます。
require 'sys/ioctl.ph';
$size = pack("L", 0);
ioctl(FH, FIONREAD(), $size) or die "Couldn't call ioctl: $!\n";
$size = unpack("L", $size);
If h2ph wasn't installed or doesn't work for you, you can grep the include files by hand:
h2ph がインストールされていないか、うまく動作しなかったのであれば、 以下のようにできます。
% grep FIONREAD /usr/include/*/*
/usr/include/asm/ioctls.h:#define FIONREAD 0x541B
Or write a small C program using the editor of champions:
あるいはエディターの王様を使って小さな C プログラムを書きます:
% cat > fionread.c
#include <sys/ioctl.h>
main() {
printf("%#08x\n", FIONREAD);
}
^D
% cc -o fionread fionread.c
% ./fionread
0x4004667f
And then hard code it, leaving porting as an exercise to your successor.
その後でその値をハードコードしてやって、あなたの仕事を引き継ぐ人のための 練習として移植をさぼります。
$FIONREAD = 0x4004667f; # XXX: opsys dependent
$size = pack("L", 0);
ioctl(FH, $FIONREAD, $size) or die "Couldn't call ioctl: $!\n";
$size = unpack("L", $size);
FIONREAD requires a filehandle connected to a stream, meaning that sockets, pipes, and tty devices work, but not files.
FIONREAD はストリームに接続されたファイルハンドルを要求します。 これはソケット、パイプ、あるいは tty デバイスではうまく動作しますが、 ファイルに対してはうまく行きません。
How do I do a tail -f
in perl? ¶
(perlで tail -f
をするには?)
First try
まず最初に以下のものを試してみてください
seek(GWFILE, 0, 1);
The statement seek(GWFILE, 0, 1)
doesn't change the current position, but it does clear the end-of-file condition on the handle, so that the next <GWFILE>
makes Perl try again to read something.
seek(GWFILE, 0, 1)
という文はカレントの位置を変更しませんが、 そのファイルハンドルにおける end-fo-file 状態を解除します。 このため、次に <GWFILE>
とすると Perl は再度何かを読もうとするのです。
If that doesn't work (it relies on features of your stdio implementation), then you need something more like this:
このやり方がうまくいかない(これはあなたの使っている stdio が実装している 機能に依存しています)のなら、以下のようにする必要があるでしょう:
for (;;) {
for ($curpos = tell(GWFILE); <GWFILE>; $curpos = tell(GWFILE)) {
# search for some stuff and put it into files
}
# sleep for a while
seek(GWFILE, $curpos, 0); # seek to where we had been
}
If this still doesn't work, look into the clearerr
method from IO::Handle
, which resets the error and end-of-file states on the handle.
これでもうまく行かなければ、IO::Handle
の clearerr
メソッドを 検討してください; これはハンドルのエラーと end-of-file 状態をリセットします。
There's also a File::Tail
module from CPAN.
CPANには File::Tail
モジュールがあります。
Perl でファイルハンドルの dup() をするには?¶
If you check "open" in perlfunc, you'll see that several of the ways to call open() should do the trick. For example:
"open" in perlfunc を見れば、それを行うための open() の呼び出し方が 何通りもあることに気がつくでしょう。例を挙げます:
open(LOG, ">>/foo/logfile");
open(STDERR, ">&LOG");
Or even with a literal numeric descriptor:
あるいは、リテラルの数値記述子を使います:
$fd = $ENV{MHCONTEXTFD};
open(MHCONTEXT, "<&=$fd"); # like fdopen(3S)
Note that "<&STDIN" makes a copy, but "<&=STDIN" make an alias. That means if you close an aliased handle, all aliases become inaccessible. This is not true with a copied one.
"<&STDIN" はコピーを作成し、"<&=STDIN" がエイリアスを作成するということに 注意してください。 これはつまり、あなたがエイリアスが作成されたファイルハンドルを クローズすると、エイリアスはすべてアクセスできなくなります。 これはコピーの場合にはそうはなりません。
Error checking, as always, has been left as an exercise for the reader.
エラーチェックはいつものように読者の練習のために残してあります。
数値によるファイル記述子をクローズするには?¶
If, for some reason, you have a file descriptor instead of a filehandle (perhaps you used POSIX::open
), you can use the close()
function from the POSIX
module:
もし、何らかの理由で、ファイルハンドルではなくファイル記述子を持っている場合 (おそらく POSIX::open
を使ったのでしょう)、POSIX
モジュールの close()
関数が使えます:
use POSIX ();
POSIX::close( $fd );
This should rarely be necessary, as the Perl close()
function is to be used for things that Perl opened itself, even if it was a dup of a numeric descriptor as with MHCONTEXT
above. But if you really have to, you may be able to do this:
Perl の close()
関数は、先の例にあった MHCNOTEXT
のように数値 記述子を使って dup したものでさえも含めて、 Perl 自身がオープンしたものに対して使うことができますから、 その必要はほとんどないはずです。 しかし本当にそうする必要があるのなら、以下のようにできるでしょう:
require 'sys/syscall.ph';
$rc = syscall(&SYS_close, $fd + 0); # must force numeric
die "can't sysclose $fd: $!" unless $rc == -1;
Or, just use the fdopen(3S) feature of open()
:
あるいは、単に open()
の fdopen(3S) 機能を使います:
{
open my( $fh ), "<&=$fd" or die "Cannot reopen fd=$fd: $!";
close $fh;
}
なぜ DOS のパスで "C:\temp\foo" が使えないの? なぜ `C:\temp\foo.exe` はうまくいかないの?¶
Whoops! You just put a tab and a formfeed into that filename! Remember that within double quoted strings ("like\this"), the backslash is an escape character. The full list of these is in "Quote and Quote-like Operators" in perlop. Unsurprisingly, you don't have a file called "c:(tab)emp(formfeed)oo" or "c:(tab)emp(formfeed)oo.exe" on your legacy DOS filesystem.
おーっと! ファイル名にタブや改ページを入れてしまいましたね! "like\this"のようにダブルクォートで括られた文字列の中では、 バックスラッシュはエスケープキャラクターであるということを思い出してください。 エスケープキャラクター全てのリストは "Quote and Quote-like Operators" in perlopにあります。 当然のことでしょうが、あなたの使っているDOSのファイルシステムでは "c:(tab)emp(formfeed)oo" とか "c:(tab)emp(formfeed)oo.exe" なんて名前のファイルはできませんよね。
Either single-quote your strings, or (preferably) use forward slashes. Since all DOS and Windows versions since something like MS-DOS 2.0 or so have treated /
and \
the same in a path, you might as well use the one that doesn't clash with Perl--or the POSIX shell, ANSI C and C++, awk, Tcl, Java, or Python, just to mention a few. POSIX paths are more portable, too.
文字列を括るのにシングルクォートを使うか、もしくは(こちらが好ましい) スラッシュを使ってください。 全てのDOSおよびWindowsは、MS-DOS 2.0以降、パス中にある/
と \
を 同じに扱いますから、あなたはPerlを壊すことなく使えます。 もしくは POSIXシェル、ANSI CとC++、awk、tcl、Java、Python を考慮してください。 POSIXパスはより移植性に富んでいます。
なぜ glob("*.*") で全てのファイルを得られないの?¶
Because even on non-Unix ports, Perl's glob function follows standard Unix globbing semantics. You'll need glob("*")
to get all (non-hidden) files. This makes glob() portable even to legacy systems. Your port may include proprietary globbing functions as well. Check its documentation for details.
非 UNIX システムに対する移植であっても、Perl の glob 関数は UNIX の標準的な グロブの振る舞いに従うからです。 全ての(隠し属性でない)ファイルを得るには glob("*")
とする必要があります。 これは glob() の移植性を高めます。 あなたの使っている Perl が独自のグロブ関数をサポートしているかもしれません。 詳しくはドキュメントを参照してください。
Why does Perl let me delete read-only files? Why does -i
clobber protected files? Isn't this a bug in Perl?¶
(なぜ Perl は読みとり専用ファイルを削除してしまうの? なぜ-i
clobberはファイルをプロテクトするの? これは Perl のバグじゃないの?)
This is elaborately and painstakingly described in the file-dir-perms article in the "Far More Than You Ever Wanted To Know" collection in http://www.cpan.org/misc/olddoc/FMTEYEWTK.tgz .
http://www.cpan.org/misc/olddoc/FMTEYEWTK.tgz の "Far More Than You Ever Wanted To Know" にあるfile-dir-perms の 記事が教育的、かつ懇切丁寧にこの問題を説明しています。
The executive summary: learn how your filesystem works. The permissions on a file say what can happen to the data in that file. The permissions on a directory say what can happen to the list of files in that directory. If you delete a file, you're removing its name from the directory (so the operation depends on the permissions of the directory, not of the file). If you try to write to the file, the permissions of the file govern whether you're allowed to.
簡単なまとめ: あなたの使っているファイルシステムがどのように動作しているのかを 考えてください。 ファイルに対するパーミッションはそのファイルにあるデータに何が できるかということを表しています。 ディレクトリに対するパーミッションは、そのディレクトリにあるファイルリストに 対して何ができるのかということを表しています。 ファイルを削除したとき、そのファイルに対する名前がディレクトリから 取り除かれます(したがってこの操作はファイルに対するパーミッションでは なく、ディレクトリに対するパーミッションに依存しているのです)。 ファイルに対して書き込みを行おうとすると、ファイルに対するパーミッションが それができるかどうかを決定します。
あるファイルからランダムに行を選択するには?¶
Here's an algorithm from the Camel Book:
以下に示すのは らくだ本にあったアルゴリズムです:
srand;
rand($.) < 1 && ($line = $_) while <>;
This has a significant advantage in space over reading the whole file in. You can find a proof of this method in The Art of Computer Programming, Volume 2, Section 3.4.2, by Donald E. Knuth.
これは、ファイル全体を読み込んで処理するやり方に比べて使用する空間の 大きさにおいて明らかなアドバンテージがあります。 この手法の証明は Donald E. Knuth の The Art of Computer Programming, Volume 2, Section 3.4.2 に あります。
You can use the File::Random module which provides a function for that algorithm:
このアルゴリズムの関数を提供する File::Random モジュールが使えます:
use File::Random qw/random_line/;
my $line = random_line($filename);
Another way is to use the Tie::File module, which treats the entire file as an array. Simply access a random array element.
もう一つの方法は Tie::File モジュールを使うことで、これはファイル全体を 配列として扱います。 単にランダムな配列にアクセスしてください。
行の配列を出力したときになぜ余計なスペースがつくの?¶
Saying
以下のようにすると:
print "@lines\n";
joins together the elements of @lines
with a space between them. If @lines
were ("little", "fluffy", "clouds")
then the above statement would print
@line
の要素を繋ぎあわせ、その間に空白を置きます。 @lines
が ("little", "fluffy", "clouds")
だったとすると、 先のやり方で出力した場合以下のようになります:
little fluffy clouds
but if each element of @lines
was a line of text, ending a newline character ("little\n", "fluffy\n", "clouds\n")
then it would print:
しかし、@lines
の各要素がテキストの行であって終端に改行がある ("little\n", "fluffy\n", "clouds\n")
のようなものだっとすると その結果は以下のようになります:
little
fluffy
clouds
If your array contains lines, just print them:
配列が行から構成されているのなら、出力するには単に以下のようにします:
print @lines;
REVISION¶
Revision: $Revision$
Date: $Date$
See perlfaq for source control details and availability.
AUTHOR AND COPYRIGHT¶
Copyright (c) 1997-2007 Tom Christiansen, Nathan Torkington, and other authors as noted. All rights reserved.
This documentation is free; you can redistribute it and/or modify it under the same terms as Perl itself.
Irrespective of its distribution, all code examples here are in the public domain. You are permitted and encouraged to use this code and any derivatives thereof in your own programs for fun or for profit as you see fit. A simple comment in the code giving credit to the FAQ would be courteous but is not required.