Perl:使用<>构造时如何获取文件名?

Dev*_*lar 18 perl

Perl提供了这个非常好的功能:

while ( <> )
{
    # do something
}
Run Code Online (Sandbox Code Playgroud)

...允许脚本script.pl <filename>和...一样使用cat <filename> | script.pl.

现在,有没有办法确定脚本是否以前一种方式被调用,如果是,文件名是什么?

我知道我知道这一次,我知道我甚至使用了这个结构,但我不记得在哪里/如何.事实证明很难搜索'net for this("perl stdin filename"?不......).

请帮忙?

Igo*_*bin 23

该变量$ARGV保存正在处理的当前文件.

$ echo hello1 > file1
$ echo hello2 > file2
$ echo hello3 > file3
$ perl -e 'while(<>){s/^/$ARGV:/; print;}' file*
file1:hello1
file2:hello2
file3:hello3
Run Code Online (Sandbox Code Playgroud)


Bor*_*din 6

I/O 操作员部分perlop对此提供了非常丰富的信息。

本质上,第一次<>执行时,如果它开始为空,-则添加到@ARGV。Opening-具有克隆STDIN文件句柄的效果,并且该变量在处理时$ARGV设置为 的当前元素@ARGV

这是完整的剪辑。

空文件句柄“<>”是特殊的:它可以用来模拟 sed 和 awk 的行为,以及任何其他接受文件名列表的 Unix 过滤程序,对来自所有文件名的每一行输入执行相同的操作。"<>" 的输入来自标准输入,或来自命令行中列出的每个文件。这是它的工作原理:第一次计算“<>”时,检查@ARGV 数组,如果它为空,则 $ARGV[0] 设置为“-”,打开时为您提供标准输入。然后将@ARGV 数组作为文件名列表进行处理。循环

   while (<>) {
       ...                     # code for each line
   }
Run Code Online (Sandbox Code Playgroud)

等价于以下类似 Perl 的伪代码:

   unshift(@ARGV, '-') unless @ARGV;
   while ($ARGV = shift) {
       open(ARGV, $ARGV);
       while (<ARGV>) {
           ...         # code for each line
       }
   }
Run Code Online (Sandbox Code Playgroud)

除了说起来并没有那么麻烦,而且实际上会起作用。它确实移动了@ARGV 数组并将当前文件名放入 $ARGV 变量中。它还在内部使用文件句柄ARGV。“<>”只是“<ARGV>”的同义词,很神奇。(上面的伪代码不起作用,因为它将“<ARGV>”视为非魔法。)


Amo*_*ira 5

如果您想知道何时<>切换到新文件(例如,在我的情况下-我想记录新的文件名和行号),那么eof()函数文档提供了一个技巧:

# reset line numbering on each input file
while (<>) {
    next if /^\s*#/;  # skip comments
    print "$.\t$_";
} continue {
    close ARGV if eof;  # Not eof()!
}
Run Code Online (Sandbox Code Playgroud)