ファイルハンドル

ファイルハンドルの概念がわかりにくいので、ちょっと説明。

ファイルハンドルの概念を理解する - Perlゼミ - Perl元気塾のPerl講座
ファイルハンドルと出力 - 2部 Perl言語仕様 - [SMART]

上記の記事にもあるように、ファイルハンドルは具体的な実体があるわけではなく、ファイルハンドルの条件に当てはまる部分をPerlコンパイラがファイルハンドルとして認識してる模様。
シンボルの回でも、ちょっと扱ったけど、ファイルハンドルはシンボルに限らない。
でもまずはシンボルから。
file_handle.plを開いて、

#!/usr/bin/perl

use strict; # 厳密な文法チェック.

# シンボルでファイルをオープン.
my $ret = open(OUT, ">", "test.txt"); # OUTは"test.txt"を指す.
# シンボルで書き込む.
if ($ret){ # trueの時.
  print OUT "ABCDE\n"; # OUTに"ABCDE\n"を書き込む.
  close(OUT); # OUTをクローズ.
}

シンボルOUTをファイルハンドルとして認識してる。

$ vi file_handle.pl
$ perl file_handle.pl
$ ls
file_handle.pl  test.txt
$ cat test.txt
ABCDE
$

シンボルはレキシカル変数ではないので、myを付けて宣言しなくても、コンパイルできるし、strictにも引っ掛からない。
続いて、Perl 5.6未満で、使われていたという、シンボルの型グロブ。

#!/usr/bin/perl

use strict; # 厳密な文法チェック.

# シンボルでファイルをオープン.
my $ret = open(OUT, ">", "test.txt"); # OUTは"test.txt"を指す.
# シンボルで書き込む.
if ($ret){ # trueの時.
  print OUT "ABCDE\n"; # OUTに"ABCDE\n"を書き込む.
  *new_name = *OUT; # 型グロブで*new_nameに引き渡す.
  print *new_name "FGHIJ\n"; # *new_nameに"FGHIJ\n"を書き込む.
  close(*new_name); # *new_nameをクローズ.
}

*OUTから*new_nameという別の型グロブに引き渡しても、書き込みできるか。

$ vi file_handle.pl
$ rm test.txt
$ ls
file_handle.pl
$ perl file_handle.pl
String found where operator expected at file_handle.pl line 11, near "*new_name "FGHIJ\n""
        (Missing operator before  "FGHIJ\n"?)
syntax error at file_handle.pl line 11, near "*new_name "FGHIJ\n""
Execution of file_handle.pl aborted due to compilation errors.
$

ダメだった。
printでコンパイルエラー。
もしかしてprintは型グロブ形式がダメなのかな。

#!/usr/bin/perl

use strict; # 厳密な文法チェック.

# シンボルでファイルをオープン.
my $ret = open(OUT, ">", "test.txt"); # OUTは"test.txt"を指す.
# シンボルで書き込む.
if ($ret){ # trueの時.
  print OUT "ABCDE\n"; # OUTに"ABCDE\n"を書き込む.
  *new_name = *OUT; # 型グロブで*new_nameに引き渡す.
  print new_name "FGHIJ\n"; # new_nameに"FGHIJ\n"を書き込む.(*は付けない.)
  close(*new_name); # *new_nameをクローズ.
}

*を外してみた。

$ vi file_handle.pl
$ ls
file_handle.pl
$ perl file_handle.pl
$ ls
file_handle.pl  test.txt
$ cat test.txt
ABCDE
FGHIJ
$

やっぱり・・・。

#!/usr/bin/perl

use strict; # 厳密な文法チェック.

# 型グロブでファイルをオープン.
my $ret = open(*OUT, ">", "test.txt"); # *OUTは"test.txt"を指す.
# 型グロブで書き込む.
if ($ret){ # trueの時.
  print *OUT "ABCDE\n"; # *OUTに"ABCDE\n"を書き込む.
  close(*OUT); # *OUTをクローズ.
}

openに*OUTという感じでファイルハンドルの型グロブを直接指定。

$ vi file_handle.pl
$ rm test.txt
$ ls
file_handle.pl
$ perl file_handle.pl
String found where operator expected at file_handle.pl line 9, near "*OUT "ABCDE\n""
        (Missing operator before  "ABCDE\n"?)
syntax error at file_handle.pl line 9, near "*OUT "ABCDE\n""
Execution of file_handle.pl aborted due to compilation errors.
$

エラーは出てるけど、これprintだけでは。

#!/usr/bin/perl

use strict; # 厳密な文法チェック.

# 型グロブでファイルをオープン.
my $ret = open(*OUT, ">", "test.txt"); # *OUTは"test.txt"を指す.
# 型グロブで書き込む.
if ($ret){ # trueの時.
  #print *OUT "ABCDE\n"; # *OUTに"ABCDE\n"を書き込む.
  print "open success!\n";
  close(*OUT); # *OUTをクローズ.
}

printに渡すのは止めて、openとcloseだけ確認。

$ vi file_handle.pl
$ perl file_handle.pl
open success!
$

これもか・・・。
つまり、printだけファイルハンドルの型グロブがダメと。
Perl 5.6未満は、ファイルハンドルを変数に入れるのに型ブログに変換していたらしいので、それをやってみる。

#!/usr/bin/perl

use strict; # 厳密な文法チェック.

# 型グロブを変数に代入.
my $tgfh = *OUT;
# その変数でファイルをオープン.
my $ret = open($tgfh, ">", "test.txt"); # $tgfhは"test.txt"を指す.
# 書き込む.
if ($ret){ # trueの時.
  print $tgfh "ABCDE\n"; # $tgfhに"ABCDE\n"を書き込む.
  close($tgfh); # $tgfhをクローズ.
}

こうすると、

$ vi file_handle.pl
$ rm test.txt
$ perl file_handle.pl
$ cat test.txt
ABCDE
$

今度は、printでも問題なく通った。
型グロブにして変数に入れればいいのか。
さて、型ブログのリファレンスという方法もある。

#!/usr/bin/perl

use strict; # 厳密な文法チェック.

# 型グロブのリファレンスを変数に代入.
my $rtgfh = \*OUT;
# その変数でファイルをオープン.
my $ret = open($rtgfh, ">", "test.txt"); # $rtgfhは"test.txt"を指す.
# 書き込む.
if ($ret){ # trueの時.
  print $rtgfh "ABCDE\n"; # $rtgfhに"ABCDE\n"を書き込む.
  close($rtgfh); # $rtgfhをクローズ.
}

これも、

$ vi file_handle.pl
$ rm test.txt
$ perl file_handle.pl
$ cat test.txt
ABCDE
$

通る。
で、今は5.6以上なので、普通のスカラ変数でも通るのでは。

#!/usr/bin/perl

use strict; # 厳密な文法チェック.

# シンボルを変数に代入.
my $symbol = OUT;
# その変数でファイルをオープン.
my $ret = open($symbol, ">", "test.txt"); # $symbolは"test.txt"を指す.
# 書き込む.
if ($ret){ # trueの時.
  print $symbol "ABCDE\n"; # $symbolに"ABCDE\n"を書き込む.
  close($symbol); # $symbolをクローズ.
}

こうすると、

$ vi file_handle.pl
$ rm test.txt
$ perl file_handle.pl
Bareword "OUT" not allowed while "strict subs" in use at file_handle.pl line 6.
Execution of file_handle.pl aborted due to compilation errors.
$

ダメか。
でも、strictって出てるから、外せばいけるのでは。

"use strict;"コメントしたら、

$ vi file_handle.pl
$ perl file_handle.pl
$ cat test.txt
ABCDE
$

通った。
というわけで、シンボル、型グロブ、型グロブのリファレンス、という3パターンが、(一部の例外を除いて)ファイルハンドルとして認識されるのがわかった。
あと2つあったり、5.6以降の現代的な書き方があったりするけど、それは次以降で。

Sample/perl/file_handle/file_handle/src/file_handle at master · bg1bgst333/Sample · GitHub