![将所有参数传递给另一个使用 getopts 的源 bash 脚本](https://linux22.com/image/229808/%E5%B0%86%E6%89%80%E6%9C%89%E5%8F%82%E6%95%B0%E4%BC%A0%E9%80%92%E7%BB%99%E5%8F%A6%E4%B8%80%E4%B8%AA%E4%BD%BF%E7%94%A8%20getopts%20%E7%9A%84%E6%BA%90%20bash%20%E8%84%9A%E6%9C%AC.png)
我正在尝试将所有参数从一个脚本传递到另一个脚本。但是,当获取其他脚本时会出现问题;所有参数均未正确传递。
首先.sh:
#!/usr/bin/bash
while getopts a option
do
case "${option}"
in
a) echo 'OptionA:somevalue';;
esac
done
# This way works
./second.sh "$@"
# Does not work when source command is used
#source ./second.sh "$@"
第二个.sh:
#!/usr/bin/bash
while getopts b:c option
do
case "${option}"
in
b) echo 'OptionB:'"${OPTARG}";;
c) echo 'OptionC:somevalue';;
esac
done
输出:
$ ./test.sh -a -b foo -c
OptionA:somevalue
./first.sh: illegal option -- b
./second.sh: illegal option -- a
OptionB:foo
OptionC:somevalue
预期输出:
$ ./test.sh -a -b foo -c
OptionA:somevalue
OptionB:foo
OptionC:somevalue
要实现什么目标?
使用source命令正确传递参数second.sh
,摆脱illegal option
并兼容其他shell。
编辑:用更清晰的示例再次更新了问题。
答案1
考虑while getopts
循环在正常情况下如何工作。getopts
为循环的每次迭代调用,即使它本身不修改命令行参数(位置参数),它也需要知道下一步要查看参数列表中的位置。它必须通过保持“隐藏”状态来做到这一点,这是在调用中未明确传递的东西。
这在Bash 的参考手册:
每次调用时,
getopts
将下一个选项放入 shell 变量中姓名, 初始化姓名如果不存在,以及要处理到变量 中的下一个参数的索引OPTIND
。OPTIND
每次调用 shell 或 shell 脚本时都会初始化为 1。当选项需要参数时,getopts 将该参数放入变量 中OPTARG
。外壳不会OPTIND
自动重置;getopts
如果要使用一组新参数,则必须在同一 shell 调用中的多次调用之间手动重置它。
当您获取脚本时,它会在与主脚本相同的 shell 环境中运行,这包括OPTIND
.
正如手册中所暗示的,只需OPTIND=1
在开始新getopts
循环之前设置即可。 (不要尝试取消设置,这可能会导致某些 shell 出现问题。)
举个例子:
set -- -a foo
while getopts a:b: option; do
echo "$option: $OPTARG"
done
set -- -b first -b second
# OPTIND=1
while getopts a:b: option; do
echo "$option: $OPTARG"
done
印刷
a: foo
b: second
因为第二个循环从第一个循环结束的位置继续,缺少-b first
.
取消OPTIND=1
中间分配的注释,您将获得预期的输出:
a: foo
b: first
b: second
至于与 分开存储参数$@
,args+="-a ${OPTARG} "
会构建单个字符串,而命令行参数集实际上是不同字符串的列表/数组。当任何参数本身包含空格时,差异最为明显。两组参数 ( -a
, foo bar
) 和 ( -a foo
, bar
) 都连接成-a foo bar
,并且无法区分后一个字符串。
相反,使用数组将参数存储为不同的字符串。
while getopts a:b:d option
do
case "${option}"
in
a) args+=(-a "$OPTARG");;
b) args+=(-b "$OPTARG");;
d) echo 'Option:D';;
esac
done
# ...
./args.sh "${args[@]}"
(看 我们如何运行存储在变量中的命令?有关更多示例等)
注意,标准.
(点)命令源脚本不带参数,但源脚本$@
与主脚本相同。 (源脚本中所做的更改$@
在主脚本中可见。)
虽然 Bash 的.
/source
支持传递一组新的参数,但如果您source filename
在没有一组参数的情况下调用,则源脚本不会不是得到一个空列表,但有主脚本的参数。
所以,如果你这样做:
source ./args.sh "${args[@]}"
您可能需要注意检查它args
不为空。或者只是在获取另一个脚本之前重置主脚本的参数。当然,这会破坏原始的参数集,但如果您需要它们,可以先将它们保存到另一个数组中:
orig_args=( "$@" ) # if needed
set -- "${args[@]}"
source ./args.sh