在不使用 ARGV 的情况下将参数从 bash 传递给 perl
pass an argument from bash to perl without use of ARGV
非常简单的问题(我认为),令我惊讶的是我似乎找不到答案。所以到目前为止我有以下内容:
£ perl -ne 'print if /ENGPacific Beach\s\s/' 15AM171H0N15000GAJK5 \
| perl -ane 'print "$F[1]|";END{print "[=11=]"}' | xargs -i -0 echo {}
3346|10989|95459|139670|2239329|3195595|3210017|
所以....第一个管道是因为文件是 1.5G,所以最初不进行记录分离大大加快了速度。 xargs
部分是为了演示我正在尝试做什么。基本上是下面的
| xargs -i perl --setperlvar pipeContents={} -ane 'print if $F[3] =~ /$pipeContents/' 15AM171H0N15000GAJK5
1) 我知道我可以在脚本中使用 ARGV。我知道整个事情应该只是一个脚本。让我们忽略那些位。我对 -n
的爱是无止境的。
2) 抱歉,我自己找不到。我敢肯定它非常明显……不过,我在 perldoc 中进行了一些挖掘,但什么也没发现。
3) 我会对 bash/zsh 解决方案感兴趣,该解决方案强制 {}
也由 perl ticks 中间的 shell 解释。
开始前的两点注意事项:
- 模式中的尾部
|
将导致每一行都匹配。它需要被删除。
/3346|10989|95459|139670|2239329|3195595|3210017/
将匹配 9993346
,因此您需要锚定模式。
以下所有解决方案都修复了这些问题。
您可以通过
向程序传递数据
- 参数列表
- 环境
- 一个打开的文件描述符(例如 stdin,但也可以使用 fd 3 或更高版本)到管道
- 外部存储(文件、数据库、内存缓存守护进程等)
您仍然可以使用参数列表。您只需要在循环开始之前从 @ARGV
中删除参数,方法是使用 BEGIN
或避免使用 -n
.
perl -ne'print if /ENGPacific Beach\s\s/' 15AM171H0N15000GAJK5 |
perl -ane'push @p, $F[1]; END { print join "|", @p; }' |
xargs -i perl -ane'
BEGIN { $p = shift(@ARGV); }
print if $F[3] =~ /^(?:$p)\z/;
' {} 15AM171H0N15000GAJK5
Perl 也有一个内置的参数解析函数,您可以使用 -s
的形式。
perl -ne'print if /ENGPacific Beach\s\s/' 15AM171H0N15000GAJK5 |
perl -ane'push @p, $F[1]; END { print join "|", @p; }' |
xargs -i perl -sane'print if $F[3] =~ /^(?:$p)\z/' -- -p={} 15AM171H0N15000GAJK5
xargs
似乎没有设置环境变量的选项,因此采用该方法有点复杂。
perl -ne'print if /ENGPacific Beach\s\s/' 15AM171H0N15000GAJK5 |
perl -ane'push @p, $F[1]; END { print join "|", @p; }' |
xargs -i sh -c '
P="" perl -ane'\''print if $F[3] =~ /^(?:$ENV{P})\z/'\'' 15AM171H0N15000GAJK5
' dummy {}
单行涉及 xargs
很奇怪。如果我们避免 xargs
,我们可以把上面的(丑陋的)命令翻过来,给出一些相当不错的东西。
P="$(
perl -ne'print if /ENGPacific Beach\s\s/' 15AM171H0N15000GAJK5 |
perl -ane'push @p, $F[1]; END { print join "|", @p; }'
)" perl -ane'print if $F[3] =~ /^(?:$ENV{P})\z/' 15AM171H0N15000GAJK5
顺便说一下,您不需要第二个 perl
来只拆分匹配的行。
P="$(
perl -ne'
push @p, (split)[1] if /ENGPacific Beach\s\s/;
END { print join "|", @p; }
' 15AM171H0N15000GAJK5
)" perl -ane'print if $F[3] =~ /^(?:$ENV{P})\z/' 15AM171H0N15000GAJK5
也就是说,我认为应该避免重复使用 $ENV{P}
以加快速度。
P=... perl -ane'print if $F[3] =~ /^(?:$ENV{P})\z/o' 15AM171H0N15000GAJK5
从那里,我看到了两种可能的速度改进。 (测试确定。)
避免在最后perl
.
完全分裂
P=... perl -ne'
BEGIN { $re = qr/^(?:\S+\s+){3}(?:$ENV{P})\s/o; }
print if /$re/o;
' 15AM171H0N15000GAJK5
在最后perl
.
完全避免使用正则表达式
P=... perl -ane'
BEGIN { %h = map { $_ => 1 } split /\|/, $ENV{P} }
print if $h{$F[3]};
' 15AM171H0N15000GAJK5
一种方便的传递参数的方法是通过 -s
switch,它可以为程序启用命令行开关
perl -s -E'say $var' -- -var=value
程序后的--
标志着程序参数的开始。然后 -var
在程序中引入一个变量 $var
,并在 =
之后为其提供一个值; shell 首先扩展了那里的内容。只有 -var
变量 $var
得到值 1
.
任何此类选项都必须出现在可能的文件名之前,并且它们已从 @ARGV
中删除,以便程序可以正常处理提交的文件
perl -s -ne'...' -- -var="$SHELL_VAR" filename
其中 -var={}
也适用。在某些 shell 中(其中 tcsh
)可能需要转义,\{\}
。
不过,我也觉得还是不去xargs
比较好。请参阅 以了解非常全面的讨论和各种方式,以及他们在此 post 下方的评论以了解如何使用 -s
.
避免它
非常简单的问题(我认为),令我惊讶的是我似乎找不到答案。所以到目前为止我有以下内容:
£ perl -ne 'print if /ENGPacific Beach\s\s/' 15AM171H0N15000GAJK5 \
| perl -ane 'print "$F[1]|";END{print "[=11=]"}' | xargs -i -0 echo {}
3346|10989|95459|139670|2239329|3195595|3210017|
所以....第一个管道是因为文件是 1.5G,所以最初不进行记录分离大大加快了速度。 xargs
部分是为了演示我正在尝试做什么。基本上是下面的
| xargs -i perl --setperlvar pipeContents={} -ane 'print if $F[3] =~ /$pipeContents/' 15AM171H0N15000GAJK5
1) 我知道我可以在脚本中使用 ARGV。我知道整个事情应该只是一个脚本。让我们忽略那些位。我对 -n
的爱是无止境的。
2) 抱歉,我自己找不到。我敢肯定它非常明显……不过,我在 perldoc 中进行了一些挖掘,但什么也没发现。
3) 我会对 bash/zsh 解决方案感兴趣,该解决方案强制 {}
也由 perl ticks 中间的 shell 解释。
开始前的两点注意事项:
- 模式中的尾部
|
将导致每一行都匹配。它需要被删除。 /3346|10989|95459|139670|2239329|3195595|3210017/
将匹配9993346
,因此您需要锚定模式。
以下所有解决方案都修复了这些问题。
您可以通过
向程序传递数据- 参数列表
- 环境
- 一个打开的文件描述符(例如 stdin,但也可以使用 fd 3 或更高版本)到管道
- 外部存储(文件、数据库、内存缓存守护进程等)
您仍然可以使用参数列表。您只需要在循环开始之前从 @ARGV
中删除参数,方法是使用 BEGIN
或避免使用 -n
.
perl -ne'print if /ENGPacific Beach\s\s/' 15AM171H0N15000GAJK5 |
perl -ane'push @p, $F[1]; END { print join "|", @p; }' |
xargs -i perl -ane'
BEGIN { $p = shift(@ARGV); }
print if $F[3] =~ /^(?:$p)\z/;
' {} 15AM171H0N15000GAJK5
Perl 也有一个内置的参数解析函数,您可以使用 -s
的形式。
perl -ne'print if /ENGPacific Beach\s\s/' 15AM171H0N15000GAJK5 |
perl -ane'push @p, $F[1]; END { print join "|", @p; }' |
xargs -i perl -sane'print if $F[3] =~ /^(?:$p)\z/' -- -p={} 15AM171H0N15000GAJK5
xargs
似乎没有设置环境变量的选项,因此采用该方法有点复杂。
perl -ne'print if /ENGPacific Beach\s\s/' 15AM171H0N15000GAJK5 |
perl -ane'push @p, $F[1]; END { print join "|", @p; }' |
xargs -i sh -c '
P="" perl -ane'\''print if $F[3] =~ /^(?:$ENV{P})\z/'\'' 15AM171H0N15000GAJK5
' dummy {}
单行涉及 xargs
很奇怪。如果我们避免 xargs
,我们可以把上面的(丑陋的)命令翻过来,给出一些相当不错的东西。
P="$(
perl -ne'print if /ENGPacific Beach\s\s/' 15AM171H0N15000GAJK5 |
perl -ane'push @p, $F[1]; END { print join "|", @p; }'
)" perl -ane'print if $F[3] =~ /^(?:$ENV{P})\z/' 15AM171H0N15000GAJK5
顺便说一下,您不需要第二个 perl
来只拆分匹配的行。
P="$(
perl -ne'
push @p, (split)[1] if /ENGPacific Beach\s\s/;
END { print join "|", @p; }
' 15AM171H0N15000GAJK5
)" perl -ane'print if $F[3] =~ /^(?:$ENV{P})\z/' 15AM171H0N15000GAJK5
也就是说,我认为应该避免重复使用 $ENV{P}
以加快速度。
P=... perl -ane'print if $F[3] =~ /^(?:$ENV{P})\z/o' 15AM171H0N15000GAJK5
从那里,我看到了两种可能的速度改进。 (测试确定。)
避免在最后
完全分裂perl
.P=... perl -ne' BEGIN { $re = qr/^(?:\S+\s+){3}(?:$ENV{P})\s/o; } print if /$re/o; ' 15AM171H0N15000GAJK5
在最后
完全避免使用正则表达式perl
.P=... perl -ane' BEGIN { %h = map { $_ => 1 } split /\|/, $ENV{P} } print if $h{$F[3]}; ' 15AM171H0N15000GAJK5
一种方便的传递参数的方法是通过 -s
switch,它可以为程序启用命令行开关
perl -s -E'say $var' -- -var=value
程序后的--
标志着程序参数的开始。然后 -var
在程序中引入一个变量 $var
,并在 =
之后为其提供一个值; shell 首先扩展了那里的内容。只有 -var
变量 $var
得到值 1
.
任何此类选项都必须出现在可能的文件名之前,并且它们已从 @ARGV
中删除,以便程序可以正常处理提交的文件
perl -s -ne'...' -- -var="$SHELL_VAR" filename
其中 -var={}
也适用。在某些 shell 中(其中 tcsh
)可能需要转义,\{\}
。
不过,我也觉得还是不去xargs
比较好。请参阅 -s
.