在 Bash 函数中使用 getopts
Posted
技术标签:
【中文标题】在 Bash 函数中使用 getopts【英文标题】:Using getopts inside a Bash function 【发布时间】:2013-05-15 07:28:24 【问题描述】:我想在我在 .bash_profile 中定义的函数中使用getopts
。
这个想法是我想将一些标志传递给这个函数来改变它的行为。
代码如下:
function t()
echo $*
getopts "a:" OPTION
echo $OPTION
echo $OPTARG
当我这样调用它时:
t -a bc
我得到这个输出:
-a bc
?
怎么了?我想在不手动移动和解析的情况下获得值bc
。如何在函数中正确使用getopts
?
编辑:更正我的代码 sn-p 以尝试 $OPTARG,但无济于事
编辑#2:好的结果证明代码很好,我的外壳不知何故搞砸了。打开一个新窗口解决了它。 arg 值确实在 $OPTARG 中。
【问题讨论】:
【参考方案1】:参数存储在变量$OPTARG
中。
function t()
echo $*
getopts "a:" OPTION
echo $OPTION
echo $OPTARG
输出:
$ t -a bc
-a bc
a
bc
【讨论】:
对不起,我错误地粘贴了我的代码 sn-p... 我也回显了 $OPTARG,这是第三行,它是空白的。还有其他想法吗? @Magnus 可能是因为您多次调用该函数并且$OPTIND
未在本地定义(请参阅 Adrian 的回答)。虽然我很感激你接受了我的回答,但你或许更应该接受他的回答。
该代码仅在粘贴到 shell 时有效,在脚本中无效。
@kenorb 从脚本中可以正常工作。这不是我编的。
好的,我不确定t
是如何被调用的,我必须在脚本中调用t -a bc
或添加t "$@"
,最初我认为它可以不使用。跨度>
【参考方案2】:
正如@Ansgar 指出的那样,您选项的参数存储在$OPTARG
中,但这并不是在函数中使用getopts
时唯一需要注意的事情。您还需要通过取消设置或声明local
来确保$OPTIND
是函数的本地函数,否则在多次调用函数时会遇到意外行为。
t.sh
:
#!/bin/bash
foo()
foo_usage() echo "foo: [-a <arg>]" 1>&2; exit;
local OPTIND o a
while getopts ":a:" o; do
case "$o" in
a)
a="$OPTARG"
;;
*)
foo_usage
;;
esac
done
shift $((OPTIND-1))
echo "a: [$a], non-option arguments: $*"
foo
foo -a bc bar quux
foo -x
示例运行:
$ ./t.sh
a: [], non-option arguments:
a: [bc], non-option arguments: bar quux
foo: [-a <arg>]
如果你注释掉# local OPTIND
,你会得到这样的结果:
$ ./t.sh
a: [], non-option arguments:
a: [bc], non-option arguments: bar quux
a: [bc], non-option arguments:
除此之外,其用法与在函数外使用时相同。
【讨论】:
1.)1>&2
中的 1
不是必需的。 2.) 您没有将a
、o
和OPTARG
定义为本地。 3.) exit
不会退出脚本,而只是一个子shell。为了退出脚本,必须在外壳中输入set -e
,在子shell 中输入exit 1
。该示例不会触发问题,但 MSG=$(foo ...)
会触发。
@ceving 1) 这是编码风格的问题,但是,不,根据语言定义,这不是必需的。 2)同意,那些应该是本地的。 3)正如你所说,exit 将退出我的示例中的脚本。当然exit
不会退出子shell,但这不是这个问题的具体问题。您不必使用set -e
,您只需要确保捕获错误并且MSG=$(foo ...) || die
也可以正常工作。 set -e
是but it's not idiot-proof 问题的一种解决方案,我和其他许多人一样,不建议使用它。
只是指出,即使您没有在函数中使用 OPTIND(例如,使用 shift;
),它仍然需要本地化才能具有可预测的行为。
@ceving,你可以看这里,***.com/questions/61566331/… - 我添加了local
,但没有帮助【参考方案3】:
下面是 getopts
在 shell 函数中使用的简单示例:
#!/usr/bin/env bash
t()
local OPTIND
getopts "a:" OPTION
echo Input: $*, OPTION: $OPTION, OPTARG: $OPTARG
t "$@"
t -a foo
输出:
$ ./test.sh -a bc
Input: -a bc, OPTION: a, OPTARG: bc
Input: -a foo, OPTION: a, OPTARG: foo
作为@Adrian pointed out,需要设置local OPTIND
(或OPTIND=1
),因为shell不会在multiple calls to getopts
(man bash
)之间自动重置OPTIND
。
getopts
的基本语法是:
getopts OPTSTRING VARNAME [ARGS...]
默认情况下,不指定参数等效于使用“$@”显式调用它,即:getopts "a:" opts "$@"
。
如果出现问题,这些是getopts
用来检查的变量:
OPTIND
- 要处理的下一个参数的索引,
OPTARG
- 变量设置为getopts
找到的选项的任何参数,
OPTERR
(不是 POSIX)- 设置为 0 或 1 以指示 Bash 是否应显示由 getopts
生成的错误消息。
更多信息,请参阅:The Bash Hackers Wiki 上的 Small getopts tutorial
【讨论】:
非常周到的答案。我不知道它是否有效,但做得很好。 @kenorb,你可以看这里 -> ***.com/questions/61566331/…,添加了local
,但没有帮助以上是关于在 Bash 函数中使用 getopts的主要内容,如果未能解决你的问题,请参考以下文章
在 CloudFormation 中使用 Sub 函数会妨碍 bash 脚本的使用吗?