我试图在 while 循环中调用一个函数并传递一些参数。但是,getopts
只能获取第一次调用的参数。
这是一个最小的例子:
function add_all_external_services() {
env | sed -n "s/^EXTERNAL_SERVICE_OPTIONS_\(.*\)$/\1/p" > options
while read -r line
do
key="${line%%=*}"
opt="${line#*=}"
if [[ -n "$key" && -n "$opt" ]]; then
echo "Adding external service \"$key\" with options: \"$opt\""
add_external_service $opt
else
echo "Missing one or more variables:
- Key: \"$key\"
- Options: \"$opt\"
"
fi
done < options
rm options
}
function add_external_service() {
local local_service_name=""
local external_service_name=""
local external_service_namespace=""
local service_url=""
echo " Options: $@"
while getopts l:s:n:-: OPT; do
if [[ "$OPT" = "-" ]]; then # long option: reformulate OPT and OPTARG
OPT="${OPTARG%%=*}" # extract long option name
OPTARG="${OPTARG#$OPT}" # extract long option argument (may be empty)
OPTARG="${OPTARG#=}" # if long option argument, remove assigning `=`
fi
case "$OPT" in
l | local-service-name) needs_arg; local_service_name="$OPTARG" ;;
s | external-service-name) needs_arg; external_service_name="$OPTARG" ;;
n | external-service-namespace) needs_arg; external_service_namespace="$OPTARG" ;;
external-name) needs_arg; service_url="$OPTARG" ;;
??* ) die "Illegal option --$OPT" ;; # bad long option
\? ) exit 2 ;; # bad short option (error reported via getopts)
esac
done
echo " - local $local_service_name"
echo " - name $external_service_name"
echo " - namespace $external_service_namespace"
echo " - url $service_url"
}
然后,调用时:
export EXTERNAL_SERVICE_OPTIONS_A="-l local_a -s rasa -n botinstance-12424526-review-feature-ce-swdjtf"
export EXTERNAL_SERVICE_OPTIONS_B="-l local_b -s review-feature-ce-swdjtf -n botinstance-12424526-review-feature-ce-swdjtf"
ventury-deploy add_all_external_services
我明白了:
Adding external service "B" with options: "-l local_b -s name_b -n namespace_b"
Options: -l local_b -s name_b -n namespace_b
- local local_b
- name name_b
- namespace namespace_b
- url
Adding external service "A" with options: "-l local_a -s name_a -n namespace_a"
Options: -l local_a -s name_a -n namespace_a
- local
- name
- namespace
- url
我得到的getopts
部分来自这里每当我在循环外调用函数时它都可以正常工作。
看完之后这个问题我尝试&
在循环内调用函数后添加 a ,它有效......所有参数都由getopts
.我不明白为什么在后台运行命令会使其工作。
如果我echo $@
在 之前getopts
,我可以看到所有参数都正确传递,如果我手动调用第二个函数,对于每个 env 变量一次,它也可以正常工作。
那么,在后台运行这些命令有何不同?我的意思是,有什么不同getopts
?另外,为什么echo $@
可以看到参数而看getopts
不到?
答案1
这是因为你没有重置OPTIND
。根据手册:
每次调用时,getopts 将下一个选项放入 shell 变量 name 中,如果 name 不存在则初始化 name,并将下一个要处理的参数的索引放入变量 OPTIND 中。每次调用 shell 或 shell 脚本时,OPTIND 都会初始化为 1。
因此,OPTIND 用于跟踪要处理的下一个参数,并1
在脚本启动时自动设置它,但在函数结束时不会重置。
要修复您的脚本,只需添加OPTIND=1
到函数的开头:
function add_external_service() {
OPTIND=1
local local_service_name=""
local external_service_name=""
local external_service_namespace=""
local service_url=""
echo " Options: $@"
while getopts l:s:n:-: OPT; do
if [[ "$OPT" = "-" ]]; then # long option: reformulate OPT and OPTARG
OPT="${OPTARG%%=*}" # extract long option name
OPTARG="${OPTARG#$OPT}" # extract long option argument (may be empty)
OPTARG="${OPTARG#=}" # if long option argument, remove assigning `=`
fi
case "$OPT" in
l | local-service-name) needs_arg; local_service_name="$OPTARG" ;;
s | external-service-name) needs_arg; external_service_name="$OPTARG" ;;
n | external-service-namespace) needs_arg; external_service_namespace="$OPTARG" ;;
external-name) needs_arg; service_url="$OPTARG" ;;
??* ) die "Illegal option --$OPT" ;; # bad long option
\? ) exit 2 ;; # bad short option (error reported via getopts)
esac
done
echo " - local $local_service_name"
echo " - name $external_service_name"
echo " - namespace $external_service_namespace"
echo " - url $service_url"
}