我有一个获取 N 参数的脚本。它首先解析它们(提取一个特定的值X
),然后用该值调用另一个程序:
function main() {
parse "$@"
run "$@"
}
main "$@"
我想在 args 列表的开头添加一个可选参数(用于设置我正在运行的 python 版本的参数)。所以我将它添加到解析函数中:
if [ "$1" = '2' ] || [ "$1" = '3' ]; then version=$1 && shift; else version=2; fi
但是,在解析结束后,我被卡住了,因为shift
它不影响运行功能。如果不再次检查第一个值的值,我怎么能做到这一点(这会破坏拥有解析函数的整个目的)
每个shell函数的作用域(以及脚本中顶层代码的作用域)都有自己的位置参数,只能直接访问自己的。最干净的解决方案是将您感兴趣的位置参数的值放入一个数组中。然后,您可以在多个函数范围内读取并修改该数组。
例如,您可以让这段代码出现在脚本开头附近:
args
.declare -a
如果你愿意,你甚至可以省略。args
运行。它甚至可能出现在使用args
. 为了清楚起见,我建议把它放在开头附近的某个地方。然后您可以
args
从多个函数对数组进行操作。您不必将其传递给函数;他们已经可以访问它了。当 shell 函数中的代码修改内容args
然后返回时,调用者中的代码将能够观察到变化。包括 Bash 在内的 Bourne 样式 shell 中的位置参数使用从 1 开始的索引。(这是因为
$0
扩展为程序名称的 ,在技术上不是位置参数,并且在函数范围内不会改变。)但是 Bash 中的数组使用从 0 开始的索引。所以,之后args=("$@")
,$1
matches${args[0]}
,$2
matches${args[1]}
,$3
matches${args[2]}
,等等。$@
仍然符合${args[@]}
您的预期。为了便于阅读,我是这样写的,不加引号。当然,您几乎总是希望双引号涉及您的
args
数组的扩展,就像您几乎总是希望双引号涉及位置参数的扩展一样。如果您决定采用这种方法,则不要:
你会写:
如果您不熟悉 Bash 中的数组,则需要查看Bash 参考手册的相关部分。您可能还想以交互方式进行试验。例如:
对应的代码
将会:
使用数组在语法上更麻烦,但也更灵活。
另一方面,由于您似乎将脚本的大部分代码组织成一个
run
函数及其被调用者,您可能会考虑在调用之前run
解析任何特殊命令行参数的替代方法,在任何 shell 函数之外,然后run "$@"
像你已经在做的那样打电话。有些编程语言的相关文化具有将几乎所有东西都放入小型(ish)自包含函数的强烈道德规范。Bash 不是这样的语言,从 shell 函数返回复杂数据的方法有限是原因之一。你不应该害怕编写 shell 函数,你甚至应该愿意编写大量微小的 shell 函数。但我认为如果你的剧本的最佳形式是别的东西,我认为你不应该担心。
如需进一步阅读,以及一些替代方法,包括获取进程替换输出的奇怪方法,请参阅Gilles对Function caller positional parameters的回答。