我正在使用 getopts,它有一个OPTERR
影响其行为的 shell 变量。我想在同一行更改 getopts 的值OPTERR
并调用 getopts ,以影响 getopts 的行为,但OPTERR
此后恢复为其默认值。因此,考虑到我对混合变量更改命令调用的过程有点模糊,我想我应该尝试一个简单的echo
.这是一系列 shell 命令及其输出,其中一些对我来说没有意义。
$ echo OPTERR
1
$ OPTERR=0 echo $OPTERR
1
现在,我们就到此为止吧。第二个命令的输出不应该是“0”吗?所以在问这个问题之前,我绞尽脑汁,认为这一定是因为以下命令应该在子 shell 中。所以后来我尝试了...
$ OPTERR=0 (echo $OPTERR)
-bash: syntax error near unexpected token `('
这更是一个更大的惊喜。如果上述构造存在语法错误,如何更改 shell 变量的值以运行子 shell? (我还尝试在 echo 命令后放置一个终端“;”,得到相同的结果)。我也尝试过...
$OPTERR=0 bash -c 'echo $OPTERR'
1
所以,那里也没有欢乐。我采取了不同的策略...
$function sf() { echo $OPTERR }
$sf
1
$OPTERR=0 sf
0
$sf
1
成功!!但为什么?函数特别不是子 shell(我不这么认为),这并不是我真正想要的(尽管,我可能可以让它适用于我的应用程序)。这是另一个有效的公式(某种程度上):
$function sf() { (OPTERR=0; echo $OPTERR;) }
$sf
0
$echo $OPTERR
1
这非常接近我想要的,但是当然实际脚本(不是我的琐碎echo
)的预期目标是getopts
,并且getopts
必须更改脚本其余部分可以看到的变量。因此,我将简单的echo
脚本更改为简单的变量集,如......
$function sf() { foo='bar'; (foo='check'; echo $foo;); echo $foo; }
$sf
check
bar
噢!!所以我可以getopts
使用我想要的环境进行调用,但我无法从子 shell 中获取任何值。我尝试导出 foo 和各种太尴尬的东西,无法在这里列出,但这是我的问题:如果你把我所有的实验放在一起,它们必须揭示一个根本错误的模型,即所有这一切应该如何工作。我的理解中缺少什么?正确的做法是什么?
只是重申一下,我想做的就是构建一个函数,该函数使用getopts
withOPTERR
设置为 0,理想情况下无需在调用函数的行上进行设置,并且以在函数外部恢复的OPTERR
方式进行设置,并且大多数OPTERR
重要的是,以一种允许我实际处理getopts
.这听起来好像有很多问题,但这是相当明智的,并且这个OPTERR
变量的存在表明它应该是可能的。
答案1
$ echo $VAR
这给出了旧值,$VAR
因为 shell 仅在命令行上扩展后才应用变量赋值。
IFS= read -r foo
然而,您经常在网站上看到的构造是有效的,因为它read
不是IFS
从命令行获取,而是在内部使用它。同样,OPTERR=0 getopts ...
应该也有效。
$ cat arg.sh
#!/bin/bash
OPTERR=0 getopts a:b var
echo "var: $var OPTERR: $OPTERR"
$ bash arg.sh -z
var: ? OPTERR: 1
即使-z
选项无效,也不会出现错误消息。
$ OPTERR=0 bash -c 'echo $OPTERR'
这有点特殊,因为OPTERR
很特殊。 Bash 的手册页显示:
OPTERR
如果设置为值1
,Bash 将显示内置命令生成的错误消息getopts
。OPTERR
每次调用 shell 或执行 shell 脚本时都会初始化为 1。
不过,这个想法是正确的,它适用于常规变量:
$ FOO=123 bash -c 'echo $FOO'
123
我想做的就是构建一个函数,它使用
getopts
如果您正在解析函数的参数,并从主程序中多次调用它(例如dothis -a; dothis -b -c
),并且不使用该函数来解析 shell 的参数(parse_args "$@"
),那么您还需要记住getopts
修改OPTIND
变量, 也。它还需要使其成为该函数的本地化。
例如,在这里,第二个函数调用看不到任何选项:
foo() { while getopts "abcd" opt; do echo "$opt"; done; };
foo -a -a
foo -b -b
与前一个结合起来,这个函数将默默地工作:
foo() {
local OPTIND=1
while OPTERR=0 getopts "abcd" opt; do
echo "$opt"
done
}
答案2
如果您需要在函数调用期间 OPTERR 为 0,请将其设置为局部变量,如 Gordon Davisson 所示:
#!/bin/bash
myfunc() {
local OPTERR=0
printf "Inside myfunc, OPTERR=%d\n" "$OPTERR"
while getopts ":a:" opt; do
echo $opt is $OPTARG
done
}
printf "Before calling myfunc, OPTERR=%d\n" "$OPTERR"
myfunc
printf "After calling myfunc, OPTERR=%d\n" "$OPTERR"
结果是:
Before calling myfunc, OPTERR=1
Inside myfunc, OPTERR=0
After calling myfunc, OPTERR=1