File handle is always global in Perl

Perl 的 file handle 及 directory handle 一定是 global 的,無法宣告成 local

一般使用上沒有大問題,但是當用在遞迴式呼叫時,就會產生錯誤了,下面是一個把目錄下包含子目錄中所有檔案列出來的 perl 程式,採用遞迴式呼叫。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/usr/bin/perl
die "Usage: $0 [directory]\n" unless @ARGV == 1;
die "ERROR: $ARGV[0] is not a directory\n" unless -d $ARGV[0];
&show_dir($ARGV[0]);
exit;
sub show_dir
{
        my( $dir ) = @_;
        my( $fname );
        opendir( DIR, $dir );
        while( $fname = readdir(DIR) )
        {
                next if $fname eq '.' || $fname eq '..';
                if( -d "$dir/$fname" ) {
                        &show_dir("$dir/$fname");
                }
                else {
                        print "$dir/$fname\n";
                }
        }
        closedir(DIR);
}

由於 DIR 這個 directory-handle 會被當成 global 變數,因此這段程式會出錯,無法列出所有檔案。

解決方法是把 DIR 這一個 directory-handle 直接用 $dir 來代替,這樣在遞迴的時候就不會因為重複使用而造成錯誤了,下面是改過的程式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/usr/bin/perl
die "Usage: $0 [directory]\n" unless @ARGV == 1;
die "ERROR: $ARGV[0] is not a directory\n" unless -d $ARGV[0];
&show_dir($ARGV[0]);
exit;
sub show_dir
{
        my( $dir ) = @_;
        my( $fname );
        opendir( $dir, $dir );
        while( $fname = readdir($dir) )
        {
                next if $fname eq '.' || $fname eq '..';
                if( -d "$dir/$fname" ) {
                        &show_dir("$dir/$fname");
                }
                else {
                        print "$dir/$fname\n";
                }
        }
        closedir($dir);
}

歡迎留下您的意見