Perl提供了这个非常好的功能:
while ( <> )
{
# do something
}
...允许将脚本用作script.pl <filename>
以及cat <filename> | script.pl
。
现在,有没有办法确定脚本是否以前一种方式被调用,如果是,那么文件名是什么?
我知道我曾经知道这一次,我知道我甚至使用了这个结构,但我不记得在哪里/如何。事实证明很难搜索'net for this(“perl stdin filename”?不......)。
请帮帮忙?
答案 0 :(得分:22)
变量$ARGV
保存当前正在处理的文件。
$ echo hello1 > file1
$ echo hello2 > file2
$ echo hello3 > file3
$ perl -e 'while(<>){s/^/$ARGV:/; print;}' file*
file1:hello1
file2:hello2
file3:hello3
答案 1 :(得分:4)
如果您想知道<>
何时切换到新文件(例如在我的情况下 - 我想记录新的文件名和行号),那么eof() function documentation提供了一个技巧:< / p>
# reset line numbering on each input file
while (<>) {
next if /^\s*#/; # skip comments
print "$.\t$_";
} continue {
close ARGV if eof; # Not eof()!
}
答案 2 :(得分:4)
I/O Operators section of perlop
对此非常有用。
基本上,第一次执行<>
时,-
会在@ARGV
开始为空时添加到-
。打开STDIN
可以克隆$ARGV
文件句柄,变量@ARGV
会在处理时设置为 while (<>) {
... # code for each line
}
的当前元素。
这是完整的剪辑。
null文件句柄&#34;&lt;&gt;&#34;很特别:它可以用来模仿 sed和awk的行为,以及任何其他需要的Unix过滤器程序 文件名列表,对所有输入的每一行都做同样的事情 他们。输入来自&#34;&lt;&gt;&#34;来自标准输入,或来自每个 命令行中列出的文件。以下是它的工作原理:第一次 &#34;&LT;&GT;&#34;进行评估,检查@ARGV数组,如果为空, $ ARGV [0]设置为&#34; - &#34;,打开时为您提供标准输入。该 然后将@ARGV数组作为文件名列表处理。循环
unshift(@ARGV, '-') unless @ARGV; while ($ARGV = shift) { open(ARGV, $ARGV); while (<ARGV>) { ... # code for each line } }
等效于以下类似Perl的伪代码:
class User < ActiveRecord::Base has_many :posts end class Post < ActiveRecord::Base belongs_to: user end
除了它说起来不那么麻烦,并且实际上会起作用。它 确实会移动@ARGV数组并将当前文件名放入 $ ARGV变量。它还在内部使用文件句柄 ARGV 。 &#34;&LT;&GT;&#34;只是 &#34;&lt; ARGV&gt;&#34;的同义词,这是神奇的。 (上面的伪代码不是 工作,因为它对待&#34;&lt; ARGV&gt;&#34;非魔法。)