Linux 将bash脚本参数传递给脚本中的ansible命令

Linux 将bash脚本参数传递给脚本中的ansible命令,linux,bash,ubuntu,ansible,Linux,Bash,Ubuntu,Ansible,我试图从bash脚本运行这个命令,并从bash参数传递额外的变量 #!/bin/bash ansible-playbook /path/to/playbook.yml --extra-vars "var1=1 $@" > /path/to/log/file 我按如下方式运行脚本,并得到以下错误: > ./test.bs var2=2 var3=3 ERROR! the playbook: var3=3 could not be found 我甚至试着逃避引用,但没有成功。 我如何

我试图从bash脚本运行这个命令,并从bash参数传递额外的变量

#!/bin/bash
ansible-playbook /path/to/playbook.yml --extra-vars "var1=1 $@" > /path/to/log/file
我按如下方式运行脚本,并得到以下错误:

> ./test.bs var2=2 var3=3
ERROR! the playbook: var3=3 could not be found
我甚至试着逃避引用,但没有成功。
我如何才能让它运行?

这似乎是正确的,应该可以运行

引用和不引用
var1=1$@
只会对传入参数的方式产生影响。不加引号将允许传递带引号的参数(即
“var2=2 var3=3”
)或不带引号的参数(即
var2=2 var3=3
),因为它会将空格分隔的参数扩展为单独的参数。如果引用了
$@
,则必须传递参数而不引用或单独引用(即
“var2=2”和“var3=3”
),以便将它们作为单独的参数接受

#!/bin/bash
ansible-playbook /path/to/playbook.yml --extra-vars "var1=1 $@" > /path/to/log/file
一个肯定有效的选项是使用
eval
,然而,这通常是避免的,因为它允许传递不安全的数据。基本上只需将
eval
放在命令之前:

eval ansible-playbook /path/to/playbook.yml --extra-vars "var1=1 $@" \
    > /path/to/log/file

它将遍历命令,对其进行解析并删除所有一级引号,使命令
ansib--额外变量var1=1 var2=2 var3=3>/path…
您正在将一个长参数传递给
--extra vars
,因为它都在相同的
标记内。您正在构建一个
var1=1 arg1 arg2 arg3
字符串

您的意图可能是传递三个参数,每个参数是一个字符串,看起来像
var1=1
var2=2
var3=3

说到这里,试试这个

ansible playbook/path/to/playbook.yml——额外变量“var1=1”“$@”>/path/to/log/file

通过这种方式,您将第一个参数作为字符串
“var1=1”
传递,然后bash将
“$@”
扩展到传递给程序的各个参数中

因此,对于上面的代码段,
将正确执行/test.bs var2=2 var3=3。不过,养成这种习惯很好,因为有一天你会运行
/test.bs var2=*
并获得一些疯狂的输出。所以最后一个最理智的决定是

/test.bs“var2=2”“var3=3”

如下运行:

> ./test.bs 'var2=2 var3=3'

或者,您可以将脚本更改为使用$*:

#!/bin/bash
ansible-playbook /path/to/playbook.yml --extra-vars "var1=1 $*" > /path/to/log/file

只要您使用Ansible 1.2或更新版本,最可靠的方法就是使用
jq
生成JSON。对于任意数量的key=value参数,以下操作将执行此操作:

#!/bin/bash
jq_args=( )
jq_text='{}'

i=0
for arg in var1=1 "$@"; do
  [[ $arg = *=* ]] || continue # require arguments to be in key=value form
  key=${arg%%=*}
  value=${arg#*=}
  jq_args+=( --arg "key$i" "$key" --arg "value$i" "$value" )
  jq_text+=" | .[\$key$i]=\$value$i"
  ((i++))
done

json_final=$(jq "${jq_args[@]}" "$jq_text" <<<"$json") # || exit

ansible-playbook /path/to/playbook.yml --extra-vars "$json_final"
#/bin/bash
jq_args=()
jq_text='{}'
i=0
对于var1中的arg=1“$@”;做
[[$arg=*=*]| |继续#要求参数采用key=value形式
key=${arg%%=*}
值=${arg#*=}
jq_args+=(-arg“key$i”“$key”--arg“value$i”“$value”)
jq_text+=“|.\$key$i]=\$value$i”
((i++)
完成

json_final=$(jq“${jq_args[@]”“$jq_text”
“$@”
扩展为多个单独的参数。因此,
“var1=1 var2=2”“var3=3”
“传递一个长参数”?不正确;
“$@”
会导致不同参数之间的拆分被保留。请尝试运行
set--一二三;printf'\n'“start$@end”
,您将看到
startone
作为第一个参数,
two
作为第二个参数,
threeend
作为最后一个参数。与相同的参数进行比较,但使用
“start$*end”
--在这种情况下,所有内容都作为一个参数传递。虽然很少是真的,但这实际上是一种情况,
$*
实际上可能是正确的,至少如果保证值不会太有趣的话。我之所以选择这个答案是因为简单。你能解释一下为什么这样做吗?当然。“$@”在每个命令行参数周围加引号,$*不加引号。因此“$@”变为“var2=2”“var3=3”,而“$*”变为“var2=2 var3=3”。由于ansible playbook希望有一个且只有一个参数——额外的参数,因此所有参数都必须放在一对引号中:“var1=1 var2=2 var3=3”。$@将添加您不需要的引号。这不是
--extra vars
的正确形式。它需要一个单独的参数,即从,请参见
ansible playbook release.yml--extra vars“version=1.23.45 other_variable=foo”的示例
坦率地说,如果您确实想为每个变量传递一个参数,为什么要使用
eval
而不是使其成为
--extra vars“var1=1”“$@”
?(如果
eval
的参数最初指定为
var4='$(rm-rf~),那么使用
eval
也会将您的数据作为代码进行解析“
,有人会有非常糟糕的一天)。