我经常通过 ssh 连接到远程服务器上运行的 Docker 容器。每次停止或删除容器时,我都需要再次将 ssh 密钥复制到容器上,以便进行连接。为此,我在 Mac 笔记本电脑上放置了这个简单的 bash 脚本,其目的只是将我的 ssh 密钥添加到我想要连接的 Docker 容器中。
#!/bin/bash
# A POSIX variable
OPTIND=1 # Reset in case getopts has been used previously in the shell.
# Default parameter value:
PORT=...
PUBKEY=...
HOST_IP=...
# show_help function
show_help() {
echo "Usage: $(basename "$0") [-h] [-p PORT] [-f PUBKEY] [-i HOST_IP]"
echo
echo " -p PORT add key to container running on port PORT (default: ...)"
echo " -f PUBKEY add key file PUBKEY (default: ...)"
echo " -i HOST_IP connect to host HOST_IP (default: ...)"
echo
return
}
while getopts ":h:p:f:i:" option; do
case "$option" in
\?)
echo "invalid argument"
show_help
exit 1
;;
h)
show_help
exit 0
;;
p) PORT=$OPTARG
;;
f) PUBKEY=$OPTARG
;;
i) HOST_IP=$OPTARG
;;
esac
done
shift $((OPTIND-1))
USER_AT_HOST="root@$HOST_IP"
PUBKEYPATH="$HOME/.ssh/$PUBKEY"
ssh-copy-id -i "$PUBKEYPATH" "$USER_AT_HOST" -p "$PORT"
exit 0
我有两个问题:
(较小)参数具有非直观字母(
f
对于PUBKEY
,i
对于HOST_IP
),因为如果我没记错的话,getopts
仅支持单字母参数。有什么方法可以规避此限制吗?如果没有,您能否为参数建议一些更具创意/不言自明的字母?
答案1
通过此实现,您无需预先指定默认值。
的参数ssh-copy-id
由数组组成。请注意+=
使用附加到数组。
其他说明:
OPTIND=1
仅当您使用此脚本时才需要source
。如果您将其作为脚本运行,则在您到达之前变量将被取消设置getopts
我会删除
exit 0
脚本底部的内容:让它以ssh-copy-id
退出状态退出。您的代码忘记了
i
getopts 的 opt 字符串。请仔细检查一下。?*
是一个与至少 1 个字符匹配的 shell 模式(又名“通配符”)。摆脱使用全大写变量名的习惯,让它们保留在 shell 中。有一天你会写
PATH=something
,然后 想知道为什么 你的脚本损坏。设置默认值的另一种方法是使用
:
命令: ${var:="default value"}
但这有点不透明。
#!/bin/bash
# show_help function
show_help() {
echo "Usage: $(basename "$0") [-h] [-p PORT|-u] [-f PUBKEY] [-i HOST_IP]"
echo
echo " -p PORT add key to container running on port PORT (default: ...)"
echo " -u USER help string here..."
echo " -f PUBKEY add key file PUBKEY (default: ...)"
echo " -i HOST_IP connect to host HOST_IP (default: ...)"
echo
return
}
while getopts ":hi:p:f:u:" option; do
case "$option" in
p) port=$OPTARG ;;
f) pubkey=$OPTARG ;;
i) host_ip=$OPTARG ;;
u) user=$OPTARG ;;
h) show_help; exit 0 ;;
?) echo "invalid argument"; show_help; exit 1 ;;
esac
done
shift $((OPTIND-1)) # not needed if there are no positional parameters
[[ -z $host_ip ]] && host_ip="default value"
[[ -z $pubkey ]] && pubkey="default value"
cmd_args=( -i "$HOME/.ssh/$pubkey" )
case "$port,$user" in
,) # empty port and empty user
echo "If you don't specify a port, you need to specify a user" >&2
exit 1
;;
,?*) # empty port but user is specified
cmd_args+=( "$user@$host_ip" )
;;
?*,*) # port has been given. user doesn't matter
cmd_args+=( -p "$port" "root@$host_ip" )
;;
esac
ssh-copy-id "${cmd_args[@]}"
针对您的评论:
只有带参数的选项才使用冒号。为了演示
有了冒号,
$ set -- -h $ getopts :h: opt $ declare -p opt OPTARG OPTIND declare -- opt=":" declare -- OPTARG="h" declare -i OPTIND="2"
作为手册
getopts
说:如果未找到所需参数 [...],则会在名称中放置冒号 (
:
),并将 OPTARG 设置为找到的选项字符。如果没有冒号,选项解析将按预期进行
$ unset opt OPTARG OPTIND $ set -- -h $ getopts :h opt $ declare -p opt OPTARG OPTIND declare -- opt="h" declare -- OPTARG declare -- OPTIND="2"
关于默认值,进行选项解析第一的。然后,如果变量未通过选项设置,提供默认值。
[[ -z $host_ip ]] && host_ip="default value"
这意味着:如果的值为
host_ip
空(-z
),则将该值设置为默认值。