我有一个用-p和-f选项调用的perl脚本。我想在脚本中将命令行参数传递给ARGV。
例如,opl.pl
是一个脚本,它将不是以 xx 开头的每一行连接到以 xx 开头的前一行,并以<在标记预先存在的'#'字符后,将em>'#'作为分隔符:
# Usage: perl -pf opl.pl file.txt
BEGIN {$recmark = @ARGV[0] if $#ARGV; }
$recmark = "xx" if (! defined $recmark);
chomp;
print "\n" if /$recmark/;
s/#/\_\_hash\_\_/g;
$_ .= "#"
当命令行上没有其他参数时,脚本将起作用。例如,perl -pf oplx.pl filexx.txt
和filexx.txt
:
xx line #1
line 2
line 3
xx line 4
line 5
产生(大约):
xx line __hash__1#line 2#line 3
xx line 4#line 5
我想将perl -pf oplx.pl filexyy.txt yy
与fileyy.txt
一起使用:
yy line #1
line 2
line 3
yy line 4
line 5
(大约)产生:
yy line __hash__1#line 2#line 3
yy line 4#line 5
不幸的是,perl将命令行参数yy
解析为文件名,而不是参数。
答案 0 :(得分:1)
使Perl在您的程序周围假设以下循环,从而使其遍历文件名参数,例如
sed -n
或awk
:LINE: while (<>) { ... # your program goes here }
<>
filehandle特别之处
<>
的输入来自标准输入或命令行中列出的每个文件。
换句话说,它从命令行上给定的所有文件中读取行。 -p
的作用相同,只是每次也打印$_
。
可以在@ARGV
variable中找到这些文件名,在您的示例中,它们具有filexyy.txt
和yy
,因此被视为文件名。
一种解决方案:在yy
块中,从@ARGV
删除所需的参数(此处为BEGIN
)。这样,<>
的操作确实将只有文件名可以使用。
这提出了程序所需界面的问题。如果您希望最后在命令行上提供该参数
my $param;
BEGIN {
$param = pop @ARGV;
}
因为pop从数组的后面删除;如果要先给出参数,则使用shift。请注意,您的$recmark
也必须从@ARGV
中删除。
跟踪所有这些信息容易出错,使用和后续工作都不方便。
最好使用Getopt::Long之类的优质模块来处理这些参数。然后,您可以给它们命名,并在需要时轻松更改接口,并由模块正确检查每个调用。
还请注意,@ARGV
中的文件名(使用Getopt::Long
完成选项后剩下的文件名)可以处理内部所有文件中的所有行
while (<>) { ... }
使用与上述相同的<>
。在脚本内部,这比-p
好得多。
答案 1 :(得分:1)
在perlrun(1)
手册页中:
-p
使Perl在您的程序周围假设以下循环,从而使其遍历文件名参数,例如sed
:LINE: while (<>) { ... # your program goes here } continue { print or die "-p destination: $!\n"; }
-p
开关最适合用于单行代码,其中每个文件参数逐行依次处理,并将程序执行的结果打印到stdout。
由-p
开关隐式添加的Perl尖括号,将一个文件句柄作为输入,并遍历每一行直到到达EOF:
while(<$opened_file_handle>) {
…
}
如何,如果未传递任何文件句柄,则尖括号将默认为@ARGV
,并将每个可用参数都视为文件名。如果@ARGV为空,则<>
将退回到标准输入(等效于使用<STDIN>
)。
如果要在命令行上同时传递参数和文件名,则有两种选择:
对参数进行排序,使与文件无关的args优先出现,如下所示:
perl -f opt.pl ABC XYZ file1.txt file2.txt
在您的脚本中:
my $first = shift; # Modifies @ARGV in-place, placing "ABC" in $first
my $second = shift; # Same again, this time plucking "XYZ" from @ARGV and putting it in `$second`
或者,使用Getopt::Long
模块将非文件名参数作为开关(或“选项”)传递:
perl -f opt.pl --foo ABC --bar XYZ file1.txt file2.txt …
执行此操作的Perl代码:
use Getopt::Long;
my $foo = "";
my $bar = "";
GetOptions("foo=s" => \$foo, "bar=s" => \$bar);
使用Getopt::Long
是在处理文件列表时传递参数的更简洁的方法(也是推荐的方法)。
希望这会有所帮助!
答案 2 :(得分:1)
考虑使用环境变量来代替命令行参数。
recmark=yy perl -pf opl.pl file1 file2 ...
BEGIN { $recmark = $ENV{recmark} // "xx" };
...