【发布时间】:2016-05-10 04:41:09
【问题描述】:
我有一个脚本需要将其所有参数转发到另一个程序。此外,出于清洁目的,我保持 shell 选项 nounset 处于启用状态。
考虑以下示例脚本:
#!/bin/ksh
set -o nounset
# Pass all of our parameters (plus a few extra) to our target
printf "<%s>\n" "Parameter count: $#" "$@"
只要主调用脚本至少有一个参数,上述方法就可以正常工作。如果没有参数,则返回ksh: @: parameter not set,脚本终止。
$ ./dollar_at.sh "Hello" "World"
<Parameter count: 2>
<Hello>
<World>
$ ./dollar_at.sh ""
<Parameter count: 1>
<>
$ ./dollar_at.sh
./dollar_at.sh[5]: @: parameter not set
如果我禁用nounset 选项,我们会得到以下信息:
$ ./dollar_at.sh
<Parameter count: 0>
顺便提一下,bash 下的nounset 处理空的$@ 时不会出错,但此脚本的环境没有bash 作为选项。
有没有办法让 ksh 与空的 $@ 配合得很好?
理想情况下,我希望 "$@" 扩展到零参数,就像 bash 和 ksh 在未启用 nounset 时所做的那样。
到目前为止,我只提出了两种可能的解决方法,但我都不太满意:
- 将目标命令包装在
if (( $# > 0 ))中并有条件地传递$@。我不喜欢这个选项,因为必须始终传递其他常量参数,这会导致重复代码。 - 当我需要访问
$@时,随时切换nounset选项。这感觉像是一种不好的做法,并违背了启用nounset的初衷。
【问题讨论】:
-
脚本运行后,您无需保持
nounset选项处于活动状态。如果需要修改脚本重新调试,可以重新加进去。这听起来像是“医生,医生,我用锤子敲头疼”的案例——处方是一样的:“别再用锤子敲你的头了”。如果您依赖于设置的环境变量,或者从配置文件中读取,那么您可以明确检查那些重要的。或者,您可以按照您的建议关闭调用其他程序的脚本部分的选项。我不会测试$#。 -
@JonathanLeffler - 这就像告诉 Perl 用户删除
use warnings和use strict如果脚本没有抛出错误。我不想禁用安全功能,我只想在访问$# == 0和$@时抑制误报情况。 -
IMNSHO,我不同意与 Perl 警告/限制的比较——我从未发现
nounset有任何相关性(好吧,在过去 30 年或这么多年的shell脚本)。但是,您可以简单地在使用"$@"的地方关闭nounset。我认为如果你不能切换到 Bash,那将是最干净的,你说你不能这样做。 -
@Mr.Llama、
use warnings和use strict实际上设计得很好,就像 Perl 中的任何东西一样。这绝对不是set -e的情况(这会产生比它解决的更多的意外、歧义和跨版本不兼容问题),并且有理由证明set -o nounset的情况并非如此要么。