getopt的错误缓存参数(getopt erroneously caches arguments)

2019-10-28 08:37发布

我在我的bash_aliases创建了一个脚本,使SSH'ing到服务器上更容易。 不过,我得到一些奇怪的行为,我不明白。 下面的脚本做了你所期望的,除了正在复使用时它。

如果我在shell这样使用它为这个第一次,它的工作原理完全如预期:

$>sdev -s myservername
ssh -i ~/.ssh/id_rsa currentuser@myservername.devdomain.com

但是,如果我运行第二次,而无需指定-s|--server ,它将使用服务器的名字从我最后一次跑这一点,已经看似缓存它:

$>sdev
ssh -i ~/.ssh/id_rsa currentuser@myservername.devdomain.com

:应该有一个错误,并且输出该消息已经退出/bin/bash: A server name (-s|--server) is required.

这种情况与任何参数; 也就是说,如果我指定参数,然后下次我不这样做,这种方法将使用的参数,从它提供的最后一次。

显然,这不是我想要的行为。 什么是负责任的,我做这件事的脚本,如何解决呢?

#!/bin/bash

sdev() {
    getopt --test > /dev/null

    if [[ $? -ne 4 ]]; then
        echo "`getopt --test` failed in this environment"
        exit 1
    fi

    OPTIONS=u:,k:,p,s:
    LONGOPTIONS=user:,key:,prod,server:

    # -temporarily store output to be able to check for errors
    # -e.g. use “--options” parameter by name to activate quoting/enhanced mode
    # -pass arguments only via   -- "$@"   to separate them correctly
    PARSED=$(getopt --options=$OPTIONS --longoptions=$LONGOPTIONS --name "$0" -- "$@")

    if [[ $? -ne 0 ]]; then
        # e.g. $? == 1
        #  then getopt has complained about wrong arguments to stdout
        exit 2
    fi

    # read getopt’s output this way to handle the quoting right:
    eval set -- "$PARSED"

    domain=devdomain
    user="$(whoami)"
    key=id_rsa

    # now enjoy the options in order and nicely split until we see --
    while true; do
        case "$1" in
            -u|--user)
                user="$2"
                shift 2
                ;;
            -k|--key)
                key="$2".pem
                shift 2
                ;;
            -p|--prod)
                domain=proddomain
                shift
                ;;
            -s|--server)
                server="$2"
                shift 2
                ;;
            --)
                shift
                break
                ;;
            *)
                echo "Programming error"
                exit 3
                ;;
        esac
    done

    if [ -z "$server" ]; then
        echo "$0: A server name (-s|--server) is required."
        kill -INT $$
    fi

    echo "ssh -i ~/.ssh/$key.pem $user@$server.$domain.com"
    ssh -i ~/.ssh/$key $user@$server.$domain.com
}

Answer 1:

server是一个全球性的shell变量,所以它的功能的运行之间共享(只要他们在同一个shell正在运行)。 也就是说,当你运行sdev -s myservername ,它设置变量server为“myservername”。 后来,当你只运行sdev ,它会检查,看看是否$server是空的,发现它不是,并继续运行并使用它。

解决方法:使用局部变量! 其实,这将会是最好声明你的函数作为本地使用的变量; 这样一来,你就不要运行其他东西是试图使用相同的变量名的干扰的风险。 我也建议避免全部大写的变量名(如OPTIONSLONGOPTIONSPARSED ) -有一堆全大写的具有特殊意义的外壳和/或其他程序的变量,如果你使用一个这些错误它可能会导致奇怪的问题。

总之,这里的简单的解决方案:添加此附近脚本的开头:

local server=""


文章来源: getopt erroneously caches arguments