Perl 在使用 -p 和 -f 选项调用的脚本中处理 ARGV
Perl process ARGV in a script called with -p and -f options
我有一个使用 -p 和 -f 选项调用的 perl 脚本。我想在脚本中将命令行参数传递给 ARGV。
例如,opl.pl
是一个脚本,它将不以 xx 开头的每一行连接到以 xx 开头的前一行,以 '#' 作为分隔符,标记预先存在的 '#' 字符后:
# 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
解析为文件名,而不是参数。
causes Perl to assume the following loop around your program, which makes it iterate over filename arguments somewhat like sed -n
or awk
:
LINE:
while (<>) {
... # your program goes here
}
其中 <>
filehandle 与
不同
Input from <>
comes either from standard input, or from each file listed on the command line.
换句话说,它从命令行中给定的所有文件中读取行。 -p
做同样的事情,只是它每次都打印 $_
。
这些文件名在 @ARGV
variable 中找到,在您的示例中有 filexyy.txt
和 yy
,因此被视为文件名。
一个解决方案:在 BEGIN
块中从 @ARGV
中删除所需的参数(此处为 yy
)。然后 <>
的操作确实只有文件名可以使用。
这提出了您的程序所需界面的问题。如果您希望在命令行最后提供该参数
my $param;
BEGIN {
$param = pop @ARGV;
}
自 pop removes from the back of an array; if you want the parameter to be given first then use shift。请注意,您的 $recmark
也必须从 @ARGV
.
中删除
跟踪所有这些很容易出错,而且不方便使用和进一步工作。
最好使用一个好的模块来处理这些参数,例如 Getopt::Long。然后您可以给它们命名,根据需要轻松更改接口,并让模块正确检查每个调用。
另请注意,@ARGV
中的文件名是您(或 Getopt::Long
)完成选项后剩下的内容,您可以处理 [=40= 中所有文件的所有行]
while (<>) { ... }
使用与上述相同的 <>
。在脚本中,这比 -p
.
好得多
来自 perlrun(1)
手册页:
-p
causes Perl to assume the following loop around your program, which makes it iterate over filename arguments somewhat like sed
:
LINE:
while (<>) {
... # your program goes here
} continue {
print or die "-p destination: $!\n";
}
-p
开关最合适的用法是单行,其中每个文件参数依次逐行处理,并将程序执行的结果打印到标准输出。
Perl 的尖括号,由 -p
开关隐式添加,将文件句柄作为输入,并遍历每一行直到到达 EOF:
while(<$opened_file_handle>) {
…
}
HOWEVER,如果没有传递文件句柄,尖括号将默认为 @ARGV
,将每个可用参数视为文件名。如果@ARGV 为空,<>
回退到标准输入(相当于使用 <STDIN>
)。
如果您想在命令行上同时传递参数 和 文件名,您有两个选择:
对参数进行排序,使与文件无关的参数排在第一位,如下所示:
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
模块将非文件名参数作为开关传递(或 "options"):
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
是在处理文件列表时传递参数的更简洁(也是推荐的方式)。
希望对您有所帮助!
考虑使用环境变量来代替处理命令行参数。
recmark=yy perl -pf opl.pl file1 file2 ...
BEGIN { $recmark = $ENV{recmark} // "xx" };
...
我有一个使用 -p 和 -f 选项调用的 perl 脚本。我想在脚本中将命令行参数传递给 ARGV。
例如,opl.pl
是一个脚本,它将不以 xx 开头的每一行连接到以 xx 开头的前一行,以 '#' 作为分隔符,标记预先存在的 '#' 字符后:
# 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
解析为文件名,而不是参数。
causes Perl to assume the following loop around your program, which makes it iterate over filename arguments somewhat like
sed -n
orawk
:LINE: while (<>) { ... # your program goes here }
其中 <>
filehandle 与
Input from
<>
comes either from standard input, or from each file listed on the command line.
换句话说,它从命令行中给定的所有文件中读取行。 -p
做同样的事情,只是它每次都打印 $_
。
这些文件名在 @ARGV
variable 中找到,在您的示例中有 filexyy.txt
和 yy
,因此被视为文件名。
一个解决方案:在 BEGIN
块中从 @ARGV
中删除所需的参数(此处为 yy
)。然后 <>
的操作确实只有文件名可以使用。
这提出了您的程序所需界面的问题。如果您希望在命令行最后提供该参数
my $param;
BEGIN {
$param = pop @ARGV;
}
自 pop removes from the back of an array; if you want the parameter to be given first then use shift。请注意,您的 $recmark
也必须从 @ARGV
.
跟踪所有这些很容易出错,而且不方便使用和进一步工作。
最好使用一个好的模块来处理这些参数,例如 Getopt::Long。然后您可以给它们命名,根据需要轻松更改接口,并让模块正确检查每个调用。
另请注意,@ARGV
中的文件名是您(或 Getopt::Long
)完成选项后剩下的内容,您可以处理 [=40= 中所有文件的所有行]
while (<>) { ... }
使用与上述相同的 <>
。在脚本中,这比 -p
.
来自 perlrun(1)
手册页:
-p
causes Perl to assume the following loop around your program, which makes it iterate over filename arguments somewhat likesed
:LINE: while (<>) { ... # your program goes here } continue { print or die "-p destination: $!\n"; }
-p
开关最合适的用法是单行,其中每个文件参数依次逐行处理,并将程序执行的结果打印到标准输出。
Perl 的尖括号,由 -p
开关隐式添加,将文件句柄作为输入,并遍历每一行直到到达 EOF:
while(<$opened_file_handle>) {
…
}
HOWEVER,如果没有传递文件句柄,尖括号将默认为 @ARGV
,将每个可用参数视为文件名。如果@ARGV 为空,<>
回退到标准输入(相当于使用 <STDIN>
)。
如果您想在命令行上同时传递参数 和 文件名,您有两个选择:
对参数进行排序,使与文件无关的参数排在第一位,如下所示:
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
模块将非文件名参数作为开关传递(或 "options"):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
是在处理文件列表时传递参数的更简洁(也是推荐的方式)。
希望对您有所帮助!
考虑使用环境变量来代替处理命令行参数。
recmark=yy perl -pf opl.pl file1 file2 ...
BEGIN { $recmark = $ENV{recmark} // "xx" };
...