perl "or" 遍历列表

perl "or" to go through a list

我编写了一个小脚本,用于在三个不同的文件夹中查找具有特定 ID 号的文件。我第一次尝试这样做是这样的:

open my $fh, "<", "dir1/file.o$ARGV[0]"
or open my $fh, "<", "dir2/file.o$ARGV[0]"
or open my $fh, "<", "dir3/file.o$ARGV[0]"
     or die "Couldn't open `file.o$ARGV[0]' for reading: $!";

这导致我用于测试的 dir2 中的文件的文件句柄为空,现在我已经编写了一个详尽的 if(...) else if (...) 结构来执行我想要的操作。但我仍然不明白为什么我的第一种方法不起作用,所以我希望得到一些见解。

我的期望是它会尝试打开第一个文件,如果失败,请查看 or 之后的内容,尝试打开该文件,依此类推。我哪里错了?

奖金问题:有没有一种优雅的方法来做到这一点?

您正在复制 $fh 的声明。将其移出:

my $fh;

   open $fh, '<', 'test1'
or open $fh, '<', 'test2'
or open $fh, '<', 'test3'
or die "Can't open whatever: $!";

如果您启用警告,它会告诉您 "my" variable $fh masks earlier declaration in same statement

作为替代方案,您可以使用 foreach 循环遍历文件,

my @files = map "dir$_/file.o$ARGV[0]", 1 ..3;

my $fh;
for (@files) {
  open($fh, "<", $_) and last;
  undef $fh;
}
$fh or die $!;

"Is there an elegant way to do this?"

警告是因为 $fh 的多个声明,正如已经解释的那样,但我更希望看到单独选择的文件,因为

  • 可能有多个具有所需 ID 的文件

  • 如果文件在 dir1dir2open 由于某些其他原因失败,您的程序将继续尝试 dir3并误报No such file or directory

我建议这样

use strict;
use warnings;

my ($id) = @ARGV;

my $filename = do {
    my @files = grep -f, map "$_/file.o$id", qw/ dir1 dir2 dir3 /;
    die @files . " matching files found" unless @files == 1;
    $files[0];
};

open my $fh, '<', $filename or die qq{Couldn't open "$filename" for reading: $!};