奇怪的 bash 脚本行为 - 生成的命令在复制粘贴时有效,但在脚本中无效 [英] Weird bash-script behavior - generated command works when copy-pasted, but not from script

查看:27
本文介绍了奇怪的 bash 脚本行为 - 生成的命令在复制粘贴时有效,但在脚本中无效的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

出于安全原因,我编写了一个简短的 bash 脚本来包装 ansible playbook 命令.没有什么复杂的,大部分脚本在这里都无关紧要.最后,我将根据脚本参数生成的变量中的 ansible 命令放在一起,如下所示:

I have written a short bash-script to wrap an ansible playbook command for safety reasons. It's nothing much complicated, and most of the script is irrelevant here. At the end, I put together the ansible command from the variables that were generated from the arguments for the script, like so:

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

生成的命令在大多数情况下都有效,只是 $additionalargs 似乎没有任何效果.所以我做了一个回声,看看脚本实际生成了什么:

The generated command works for the most part, except that $additionalargs doesn't seem to have any effect. So I do an echo and look at what the script actually generated:

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 参数.

This looks exactly as intended, but the --extra-vars parameter seems to not get passed. So I copied the line produced by the echo, pasted it in the console and hit enter, and this worked fully, including the --extra-vars argument.

所以脚本生成了我想要的,如果我手动提供脚本生成的命令,它会起作用……但是当脚本本身执行命令时它不起作用,或者至少不完全.

So the script generates what I intend, and if I manually supply the command generated by the script it works... but it doesn't work when the script itself executes the command, or at least not completely.

任何人都可以给我提示可能会出错的地方吗?下面是完整的脚本供参考,尽管由于输出符合预期,我不希望问题出在这里,而是有一些我不知道的 bash 特性.

Can anybody give me a hint as to what might go wrong? below is the full script for reference, although since the output is as expected I don't expect the problem to be located here, but rather that there's some bash pecularity I just don't know about.

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

推荐答案

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

I found the solution to this one while writing another script involving rather complex curl commands. First I found out that you can use

set -x

在脚本中让它显示扩展的命令,我对引用扩展产生的混乱感到相当震惊.它在回声中很好地扩展了,但是作为参数传递了整个事情,构建了一个神秘的引号迷宫.我也尝试过引用变量,但 Ansible 不太喜欢这样.

In the script to make it show the expanded commands, and I was rather horrified at the mess the quote expansion produced. It expanded nicely in an echo, but passing the whole thing as arguments built a mystic labyrinth of quotes. I also experimented around with quoting the variables, but Ansible doesn't like that too much.

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

I found that for long commands with many arguments that themselves may contain quotes, it is best to write the whole command in a string within double quotes and escape any quotes inside the arguments, and then pass the whole thing to eval.

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

In this particular case, the command that actually works looks like this:

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

这篇关于奇怪的 bash 脚本行为 - 生成的命令在复制粘贴时有效,但在脚本中无效的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆