奇怪的bash脚本行为-复制粘贴时生成的命令有效,但不是从脚本生成的
出于安全考虑,我编写了一个简短的bash脚本来包装ansible playbook命令。这没什么复杂的,而且大部分脚本在这里都是无关的。最后,我将ansible命令与脚本参数生成的变量组合在一起,如下所示:奇怪的bash脚本行为-复制粘贴时生成的命令有效,但不是从脚本生成的,bash,ansible,Bash,Ansible,出于安全考虑,我编写了一个简短的bash脚本来包装ansible playbook命令。这没什么复杂的,而且大部分脚本在这里都是无关的。最后,我将ansible命令与脚本参数生成的变量组合在一起,如下所示: ansible-playbook -k $user -i hosts-staging $limit $tags $additionalargs site.yml 生成的命令在大部分情况下都有效,除了$additionalargs似乎没有任何效果。所以我做了一个回音,看看脚本实际生成了什
ansible-playbook -k $user -i hosts-staging $limit $tags $additionalargs site.yml
生成的命令在大部分情况下都有效,除了$additionalargs似乎没有任何效果。所以我做了一个回音,看看脚本实际生成了什么:
echo ansible-playbook -k $user -i hosts-staging $limit $tags $additionalargs site.yml
output: ansible-playbook -k -u pi -i hosts-staging -l tcameras --tags fulllaunch --extra-vars "agraphite_force_restart=true" site.yml
这看起来与预期完全一样,但是--extra-vars参数似乎没有通过。
因此,我复制了echo生成的行,将其粘贴到控制台中并点击enter,这完全起作用,包括--extra-vars参数
所以脚本生成我想要的,如果我手动提供脚本生成的命令,它就会工作。。。但是当脚本本身执行命令时,或者至少不完全执行命令时,它不起作用
有谁能给我一个提示,说明什么地方可能会出错?下面是供参考的完整脚本,尽管由于输出如预期的那样,我不希望问题出现在这里,但是我不知道bash的一些特殊性
#!/bin/bash
# brief Makes graphite deployment via Ansible saver by wrapping it into a script that only needs the most common variables, does not apply to the whole inventory by default, and uses the current staging inventory.
# args (3) Expects 3 arguments: what to do, who to do it with, and if it should do it with all of them or just with one individual instance
# arg $1 What to do. Valid values are "deploy", "launch" or "restart".
# arg $2 Who to do it with. Valid values are "cameras", "servers" or "all".
# arg $3 Optional: Pass an IP from the inventory to apply the action to.
# error codes:
# 1: Unexpected number of arguments
# 2: Invalid first argument
# 3: Invalid second argument
# 4: Invalid third argument (optional)
# 5: Optional third argument not compatible with second argument
additionalargs=""
if [ $# -lt 2 ]; then
echo "Unexpected number of arguments (2 expected). Please pass what (\"deploy\", \"launch\" or \"restart\") and who (\"cameras\", \"servers\" or \"all\")"
exit 1
fi
if [ $1 == "launch" ]; then
tags="--tags fulllaunch"
elif [ $1 == "restart" ]; then
tags="--tags fulllaunch"
additionalargs='--extra-vars "agraphite_force_restart=true"'
elif [ $1 != "deploy" ]; then
echo "Invalid argument: "$1"! Must be either \"launch\", \"deploy\" or \"restart\"!"
exit 2
else
tags=""
fi
if [ $2 == "cameras" ]; then
limit="-l tcameras"
user="-u pi"
elif [ $2 == "servers" ]; then
limit="-l tservers"
user="-u ubuntu"
elif [ $2 == "all" ]; then
limit=""
user="both"
else
echo "Invalid argument: "$2"! Must be either \"cameras\", \"servers\", <ip> or \"all\"!"
exit 3
fi
if [ $# -eq 3 ]; then
if [[ $3 == *.*.*.* ]]; then #quite a superficial check for the validity of an ip address, but it serves to prevent dangerous input
limit="-l "$3
else
echo "Error: optional third parameter must be a valid ip-address!"
exit 4
fi
if [ $user == "both" ]; then
echo "Error: specific ip cannot be used with parameter \"all\"."
exit 5
fi
fi
if [[ $user == "both" ]]; then
#do actions for both cameras and servers
ansible-playbook -k -u ubuntu -i hosts-staging -l tcameras $tags $additionalargs site.yml
ansible-playbook -k -u pi -i hosts-staging -l tservers $tags $additionalargs site.yml
else
echo ansible-playbook -k $user -i hosts-staging $limit $tags $additionalargs site.yml
ansible-playbook -k $user -i hosts-staging $limit $tags $additionalargs site.yml
fi
#/bin/bash
#brief通过Ansible saver将graphite部署到一个脚本中,该脚本只需要最常用的变量,默认情况下不应用于整个库存,并使用当前的暂存库存。
#args(3)需要3个参数:做什么,和谁一起做,是应该和所有参数一起做,还是只和一个实例一起做
#arg$1要做什么。有效值为“部署”、“启动”或“重新启动”。
#arg$2与谁一起做这件事。有效值为“摄像机”、“服务器”或“全部”。
#arg$3可选:从清单中传递一个IP以应用操作。
#错误代码:
#1:意外的参数数
#2:第一个参数无效
#3:第二个参数无效
#4:第三个参数无效(可选)
#5:可选的第三个参数与第二个参数不兼容
additionalargs=“”
如果[$#-lt 2];然后
echo“意外的参数数(应为2个)。请传递什么(\'deploy\'、\'launch\'或\'restart\')和谁(\'cameras\'、\'servers\'或\'all\')”
出口1
fi
如果[$1==“启动”];然后
tags=“--tags fulllaunch”
elif[$1==“重新启动”];然后
tags=“--tags fulllaunch”
additionalargs='--extra vars“agraphite\u force\u restart=true”
elif[$1!=“部署”];然后
echo“无效参数:$1”!必须是“启动”、“部署”或“重新启动”!”
出口2
其他的
tags=“”
fi
如果[$2==“摄像机”];然后
limit=“-l tcameras”
user=“-u pi”
elif[$2==“服务器”];然后
limit=“-l t服务器”
user=“-u ubuntu”
elif[$2==“全部”];然后
limit=“”
user=“两者”
其他的
echo“无效参数:$2”!必须是“摄像机”、“服务器”或“全部”!”
出口3
fi
如果[$#-eq 3];然后
如果[[$3==*.*]];然后#对ip地址的有效性进行相当肤浅的检查,但它可以防止危险的输入
limit=“-l”$3
其他的
echo“错误:可选的第三个参数必须是有效的ip地址!”
出口4
fi
如果[$user==“两者”];然后
echo“错误:特定ip不能与参数\“all\”一起使用”
出口5
fi
fi
如果[[$user==“两者”];然后
#对摄影机和服务器执行操作
ansible playbook-k-u ubuntu-i主机staging-l tcameras$tags$additionalargs site.yml
ansible playbook-k-u pi-i hosts staging-l tservers$tags$additionalargs site.yml
其他的
echo ansible playbook-k$user-i主机暂存$limit$tags$additionalargs site.yml
ansible playbook-k$user-i主机staging$limit$tags$additionalargs site.yml
fi
我在编写另一个涉及相当复杂的curl命令的脚本时找到了解决方案。
首先我发现你可以使用
set -x
在脚本中显示扩展的命令,我对引用扩展产生的混乱感到相当震惊。它在一个回音中很好地扩展了,但整个过程都以论点的形式传递,形成了一个神秘的引语迷宫。我也尝试过引用变量,但Ansible不太喜欢这样
我发现,对于本身可能包含引号的具有许多参数的长命令,最好将整个命令写在双引号内的字符串中,并转义参数内的任何引号,然后将整个内容传递给eval
在这种情况下,实际运行的命令如下所示:
eval "ansible-playbook -k $user -i hosts-staging $limit $tags $additionalargs site.yml"
这里是BashFAQ#50:…这里还有一堆其他bug
=
在POSIX测试中实际上不是有效的运算符——标准保证的唯一字符串比较运算符是=
。在[$user==“both”]
中,您引用的是不需要引用的内容(文字),但扩展了不需要引用的内容(扩展)——如果您的名称带有空格,则会导致语法错误(在某些平台上,空格是合法的;在Windows/Cygwin上,空格是完全常见的)。考虑运行你的代码。谢谢。对于那些不经常抨击的人来说,突然将变量放在引号中而不是字符串中真的很奇怪。我明白了原因,但仍然觉得这样做是完全错误的。以这种方式使用eval
是非常非常糟糕的形式——如果您的任何变量包含,例如,$(rm-rf$HOME)
,该代码将被扩展,而不是按字面意思传递……收集参数列表的正确方法是在为此目的而构建的数据结构中——也就是说,数组。你的意思是,像#ansible playbook${arguments[@]}一样,仍然缺少引号<代码>ansible playbook“${arguments[@]}”,如果您已将参数收集到名为arguments的数组中。(希望你也能得到照顾