奇怪的bash-script行为 - 生成的命令在复制粘贴时起作用,但不起作用于脚本

时间:2016-05-17 11:42:30

标签: bash ansible

出于安全原因,我编写了一个简短的bash脚本来包装ansible playbook命令。它并不复杂,大多数脚本在这里都无关紧要。最后,我将来自脚本参数生成的变量的ansible命令放在一起,如下所示:

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产生的行,将它粘贴在控制台中并点击回车,这完全有效,包括--extra-vars参数。

因此脚本会生成我想要的内容,如果我手动提供脚本生成的命令,它可以工作......但是当脚本本身执行命令时,它不起作用,或者至少不完全。

有人能给我一些关于可能出错的提示吗?下面是完整的脚本供参考,虽然由于输出是预期的,我不认为问题在这里,而是有一些我不知道的bash pecularity。

#!/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

1 个答案:

答案 0 :(得分:0)

我在编写另一个涉及相当复杂的curl命令的脚本时找到了这个解决方案。 首先我发现你可以使用

set -x

在脚本中让它显示扩展的命令,而我对报价扩展产生的混乱感到非常恐惧。它在回声中很好地扩展,但是通过整个事物作为参数构建了一个神秘的引号迷宫。我也试过引用变量,但Ansible不太喜欢这个。

我发现对于带有许多参数的长命令本身可能包含引号,最好将整个命令写入双引号内的字符串中并转义参数中的任何引号,然后将整个事物传递给eval。 / p>

在这种特殊情况下,实际工作的命令如下所示:

eval "ansible-playbook -k $user -i hosts-staging $limit $tags $additionalargs site.yml"