getopt 错误地缓存参数
getopt erroneously caches arguments
我在 bash_aliases 中创建了一个脚本,使通过 SSH 连接到服务器更容易。但是,我遇到了一些我不理解的奇怪行为。下面的脚本如你所料的那样工作,除非它被重新使用。
如果我第一次在 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 "[=12=]" -- "$@")
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 "" in
-u|--user)
user=""
shift 2
;;
-k|--key)
key="".pem
shift 2
;;
-p|--prod)
domain=proddomain
shift
;;
-s|--server)
server=""
shift 2
;;
--)
shift
break
;;
*)
echo "Programming error"
exit 3
;;
esac
done
if [ -z "$server" ]; then
echo "[=12=]: 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
}
server
是一个全局 shell 变量,因此它在函数的 运行 之间共享(只要它们 运行 在同一个 shell).也就是说,当您 运行 sdev -s myservername
时,它会将变量 server
设置为 "myservername"。稍后,当您 运行 只是 sdev
时,它会检查 $server
是否为空,发现不是,然后继续使用它。
解决方法:使用局部变量!实际上,最好将您在函数中使用的所有变量都声明为局部变量;这样,您就不会 运行 干扰其他尝试使用相同变量名的东西的风险。我还建议避免使用全部大写的变量名称(例如 OPTIONS
、LONGOPTIONS
和 PARSED
)——有一些全部大写的变量对 shell and/or 其他程序,如果您错误地使用其中一个程序,可能会导致奇怪的问题。
无论如何,这是一个简单的解决方案:在脚本开头附近添加:
local server=""
我在 bash_aliases 中创建了一个脚本,使通过 SSH 连接到服务器更容易。但是,我遇到了一些我不理解的奇怪行为。下面的脚本如你所料的那样工作,除非它被重新使用。
如果我第一次在 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 "[=12=]" -- "$@")
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 "" in
-u|--user)
user=""
shift 2
;;
-k|--key)
key="".pem
shift 2
;;
-p|--prod)
domain=proddomain
shift
;;
-s|--server)
server=""
shift 2
;;
--)
shift
break
;;
*)
echo "Programming error"
exit 3
;;
esac
done
if [ -z "$server" ]; then
echo "[=12=]: 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
}
server
是一个全局 shell 变量,因此它在函数的 运行 之间共享(只要它们 运行 在同一个 shell).也就是说,当您 运行 sdev -s myservername
时,它会将变量 server
设置为 "myservername"。稍后,当您 运行 只是 sdev
时,它会检查 $server
是否为空,发现不是,然后继续使用它。
解决方法:使用局部变量!实际上,最好将您在函数中使用的所有变量都声明为局部变量;这样,您就不会 运行 干扰其他尝试使用相同变量名的东西的风险。我还建议避免使用全部大写的变量名称(例如 OPTIONS
、LONGOPTIONS
和 PARSED
)——有一些全部大写的变量对 shell and/or 其他程序,如果您错误地使用其中一个程序,可能会导致奇怪的问题。
无论如何,这是一个简单的解决方案:在脚本开头附近添加:
local server=""