【问题标题】:pass an argument from bash to perl without use of ARGV在不使用 ARGV 的情况下将参数从 bash 传递到 perl
【发布时间】:2019-01-20 15:31:25
【问题描述】:

非常简单的问题(我认为)我很惊讶我似乎找不到答案。所以到目前为止我有以下内容:

£ perl -ne 'print if /ENGPacific Beach\s\s/' 15AM171H0N15000GAJK5 \
| perl -ane 'print "$F[1]|";END{print "\0"}' | 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) 我对强制 {} 在 perl 刻度中间由 shell 解释的 bash/zsh 解决方案感兴趣。

【问题讨论】:

  • 我不确定您的管道中涉及的所有内容,但请参阅 this post 中将参数从 bash 传递到 Perl 单行器的三种方法
  • 提案(3)是主要安全漏洞的来源。在现实世界中实际利用的安全漏洞——搜索“shell injection”;将数据作为代码注入 perl 解释器与将其注入 shell 一样糟糕。不要这样做,尤其是当您处理 1.5GB 的数据并且无法手动读取它以查找任何 "+system("rm -rf ~")+" 子字符串时。
  • (就此而言,xargs 没有 -0-d $'\n' 在 bash 世界中也被认为是不好的做法,因为一些相当好的原因;请参阅 the "Actions in Bulk" section of Using Find)。
  • --setvar 是一个东西,还是你编造的?
  • 感谢您的解释 -- 是的,我知道 xargs 但我不确定它是否是您想要的内容的一部分,或者仅用于“演示...我>”。我也不确定目标到底是什么。但现在一切都很好,你已经得到了来自 ikegami 的非常彻底的分析 :)

标签: bash perl xargs


【解决方案1】:

开始之前的两个注意事项:

  • 模式中的尾随| 将导致每一行都匹配。它需要被移除。
  • /3346|10989|95459|139670|2239329|3195595|3210017/ 将匹配 9993346,因此您需要锚定模式。

以下所有解决方案都针对这些问题进行了修复。


您可以通过以下方式将数据传递给程序

  • 参数列表
  • 环境
  • 一个打开的文件描述符(例如标准输入,但也可以使用 fd 3 或更高版本)到管道
  • 外部存储(文件、数据库、内存缓存守护进程等)

您仍然可以使用参数列表。您只需要在循环开始之前使用BEGIN 或避免使用-n,从@ARGV 中删除参数。

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="$1" 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

从那里,我看到了两个可能的速度改进。 (测试确定。)

  1. 避免在最后一个perl中完全拆分。

    P=... perl -ne'
       BEGIN { $re = qr/^(?:\S+\s+){3}(?:$ENV{P})\s/o; }
       print if /$re/o;
    ' 15AM171H0N15000GAJK5
    
  2. 在最后一个perl 中完全避免正则表达式。

    P=... perl -ane'
       BEGIN { %h = map { $_ => 1 } split /\|/, $ENV{P} }
       print if $h{$F[3]};
    ' 15AM171H0N15000GAJK5
    

【讨论】:

  • 我将在一天左右的时间里处理这个答案:) 关于要点 #2 ......这是一个很好的观点。我真的什至不需要最后一点的正则表达式......只需直接比较或“字符串开头”。也就是说,一些额外的结果很好。他们要去一个终端,我在那里手工检查他们。我基本上是在查看 SQL 风格数据库的文本转储……或多或少地手动检查数据。
  • 对答案中的细节表示赞赏。
【解决方案2】:

传递参数的一种便捷方式是通过-s switch,它可以为程序启用命令行切换

perl -s -E'say $var' -- -var=value

程序后面的-- 标志着程序参数的开始。然后-var 将变量$var 引入程序,并在= 之后为其提供值;首先由外壳扩展。仅使用-var 变量$var 获取值1

任何此类选项都必须出现在可能的文件名之前,并且它们会从@ARGV 中删除,以便程序可以正常处理提交的文件

perl -s -ne'...' -- -var="$SHELL_VAR" filename

-var={} 也可以工作。在某些 shell(tcsh 一个)中,它可能需要被转义,\{\}

不过,我也认为最好不要去xargs。请参阅ikegami's answer 进行非常全面的讨论和各种方式,以及他们在这篇文章下方的评论,了解如何使用-s 避免它。

【讨论】:

  • 好主意。在我的答案中添加了-s。 (呵呵,perl -sane)不过,仍然认为避免xargs 是要走的路。但是您仍然可以通过将P="$( ... )" perl -ane'...$ENV{P}...' filename 更改为perl -sane'...$p...' -- -p="$( ... )" filename 来使用-s 来做到这一点
  • @ikegami 完全同意xargs。 (我认为他们只是为了展示他们想要的东西?)由于您的回答绝对详尽,我没有讨论其他任何事情。我想我还是会留下这篇文章,因为它提供了关于 -s 的详细信息。
猜你喜欢
  • 2017-12-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-28
  • 2019-07-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多