Files

Perl opendir() 只允許一個操作?

  • February 2, 2020

我發現 perl 的opendir()函式有一個奇怪的問題,對我來說絕對是零意義。

在以下範例中 perl 將打開 $path 指定的目錄並提取所有子目錄名稱:

opendir(my $dh, $path) or die "can't opendir $path: $!";
my @dirs = grep { ! /^[\.]{1,2}$/ && -d "$path/$_" } readdir($dh);
closedir($dh);
foreach my $d (@dirs) {
  print $encoder->encode($d);
}

在本例中,perl 將打開 $path 指定的目錄並提取所有文件名:

opendir(my $dh, $path) or die "can't opendir $path: $!";
my @files = grep { ! /^[\.]{1,2}$/ && -f "$path/$_" } readdir($dh);
closedir($dh);
foreach my $f (@files) {
  print $encoder->encode($f);
}

但是,我發現以下程式碼列印目錄:

opendir(my $dh, $path) or die "can't opendir $path: $!";
my @dirs = grep { ! /^[\.]{1,2}$/ && -d "$path/$_" } readdir($dh);
my @files = grep { ! /^[\.]{1,2}$/ && -f "$path/$_" } readdir($dh);
closedir($dh);

foreach my $f (@files) {
  print $encoder->encode($f);
}
foreach my $d (@dirs) {
  print $encoder->encode($d);
}

grep當在上面的例子中切換兩行時,perl@files首先分配,perl 將列印文件。

怎麼回事?!

我找到了一種解決方法,可以使用以下程式碼列印文件和目錄:

opendir(my $dh, $path) or die "can't opendir $path: $!";
my @dirs = grep { ! /^[\.]{1,2}$/ && -d "$path/$_" } readdir($dh);
closedir($dh);

opendir(my $dh, $path) or die "can't opendir $path: $!";
my @files = grep { ! /^[\.]{1,2}$/ && -f "$path/$_" } readdir($dh);
closedir($dh);

foreach my $f (@files) {
  print $encoder->encode($f);
}
foreach my $d (@dirs) {
  print $encoder->encode($d);
}

但是,雖然我可以讓我的腳本工作,但我仍然不知道為什麼perl 會以它在這裡的方式執行。據我了解,opendir()打開一個目錄並為第一個參數分配一個句柄,該參數由closedir(). $dh那麼,如果是這種情況,如果句柄從未關閉,為什麼我不能執行多項操作?

額外資訊:

$ perl --version
This is perl 5, version 26, subversion 1 (v5.26.1) built for x86_64-linux-gnu-thread-multi

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 18.04.4 LTS
Release:        18.04
Codename:       bionic

我在適用於 Windows 的 Linux 子系統上執行此程式碼

我會rewinddir在兩次掃描之間使用。

Perl 的目錄掃描功能(就像 Perl 中的許多其他功能一樣)是 C 執行時之上的一個薄層。 打開目錄流可讓您一次讀取一個或多個目錄中的條目。但是一旦閱讀,這些就完成了。如果你想再次讀取目錄,rewinddir是要做的事情。

為了比較,這裡是指向 POSIX (C opendir)readdirrewinddir.

引用自:https://unix.stackexchange.com/questions/565342