为 PERL 脚本构建 CLI 参数的 Shell 脚本

Posted

技术标签:

【中文标题】为 PERL 脚本构建 CLI 参数的 Shell 脚本【英文标题】:Shell script to build CLI args for a PERL script 【发布时间】:2015-04-24 08:13:58 【问题描述】:

我有一份 Jenkins 工作,作为参数化构建触发。它接受一个可选的字符串参数 (HOSTNAMES),可以是逗号分隔的主机名列表。

我需要将此以逗号分隔的主机名列表作为命令行参数传递给 PERL 脚本(在执行 shell 构建步骤中)。

这是我在执行 shell 构建步骤中处理输入参数和构造命令行参数的方式:

cmd_options=''
echo hostnames is $HOSTNAMES
if [ "$HOSTNAMES" != "" ]
  then
  cmd_options+=" --hostnames \"$HOSTNAMES\""
fi
perl myscript.pl $cmd_options

在构建的控制台输出中,我看到参数传递不正确。这是控制台输出:

+ cmd_options=
+ echo hostnames is host1, host2
hostnames is host1, host2
+ '[' 'host1, host2' '!=' '' ']'
+ cmd_options+=' --hostnames "host1, host2"'
+ perl myscript.pl --hostnames '"host1,' 'host2"'

我希望myscript.pl 被这样称呼:

perl myscript.pl --hostnames "host1, host2"

我尝试过使用单引号和双引号来处理$cmd_options 的各种方法,但到目前为止都没有成功。任何关于我哪里出错的指针?

【问题讨论】:

为什么不改写 Perl 脚本呢? 我能做到。但我提出这个问题的目的更多是为了试图了解 shell 脚本的更详细的细节以及我错过了什么。 你用的是什么外壳? $HOSTNAMES 是环境变量还是您以某种方式从命令行参数中获取它的值? $HOSTNAMES 将是 Jenkins 构建环境中的环境变量。 【参考方案1】:

构建命令时,延迟插值,使用eval执行。

HOSTNAMES='host1, host2'

cmd_options=''
if [ "$HOSTNAMES" != "" ]; then
   cmd_options+='--hostnames "$HOSTNAMES"'
fi

eval "prog $cmd_options"

更好的解决方案是使用数组。

HOSTNAMES='host1, host2'

cmd_options=()
if [ "$HOSTNAMES" != "" ]; then
   cmd_options+=(--hostnames "$HOSTNAMES")
fi

prog "$cmd_options[@]"

如果prog 是以下程序:

#!/usr/bin/perl
use feature qw( say );
say 0+@ARGV; say for @ARGV

两个 sn-ps 都输出以下内容:

2
--hostnames
host1, host2

【讨论】:

我强烈建议不要在这里使用eval,至少在不确定HOSTNAMES 的值是否安全的情况下。 @chepner,你错了。 HOSTNAMES 的内容永远不会传递给 eval,因此无需检查。 啊,错过了。文字字符串$HOSTNAMES 被传递给eval,它会进行参数扩展。【参考方案2】:

您似乎无法在 $cmd_options 中嵌入列表, 因为它会阻止您正确使用引号 - 用反斜杠“转义”引号 (\") 将它们转换为常规的 " 字符 - 不是分隔符,因此, 它们只是连接到$HOSTNAMES 列表的第一项和最后一项。

建议你删除这一行:

cmd_options+=" --hostnames \"$HOSTNAMES\""

并根据需要使用以下两行代码 (这假设您仍然需要$cmd_options 来传递其他参数)

perl myscript.pl $cmd_options --hostnames "$HOSTNAMES"
perl myscript.pl $cmd_options

包裹在if 语句中,应该如下所示:

if [ "$HOSTNAMES" != "" ]
then
  perl myscript.pl $cmd_options --hostnames "$HOSTNAMES"
else
  perl myscript.pl $cmd_options
fi

另一种选择是确保$HOSTNAMES 列表中没有空格 - 它将允许将列表作为单个参数传递,并且不再需要引号。

【讨论】:

我认为他们仍然需要包含 $cmd_options 以防它有其他选项。所以在第一种情况下可能类似于perl myscript.pl $cmd_options --hostnames "$HOSTNAMES" ,在第二种情况下可能是相同的但没有 --hostnames 选项。 @Gonen 你能解释一下为什么--hostnames \"$HOSTNAMES\"$cmd_options 连接时不会简单地产生--hostnames "host1, host2" 吗? @sockmonk,谢谢 - 用你的评论更新了我的例子。 @SindhuriKuppasad,您示例中的引号不是分隔符 - 它们只是" 字符,连接到$HOSTNAMES 列表的第一项和最后一项。【参考方案3】:

假设您不再需要脚本的位置参数,您可以自己设置它们。 (这适用于任何 POSIX shell,其中数组不可用。)

# Save any positional parameters first, if necessary;
# we're going to overwrite them.
first_arg=$1
second_arg=$2
# etc.
set -- --hostnames "$HOSTNAMES"
perl myscript.pl "$@"

【讨论】:

以上是关于为 PERL 脚本构建 CLI 参数的 Shell 脚本的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 shell 脚本拦截 perl 脚本的执行,然后实际执行它们?

将我的代码从 perl 转换为 shell 脚本

将环境变量设置为从 perl 脚本执行的 shell

shell脚本下载webkit夜间构建

写个脚本使用perl或shell对比oracle表数据,急啊,高分悬赏!

安装脚本的 shell 脚本与 perl - perl 有多普遍?