我写下列 bash
脚本作为预算工具,可以更准确地计算(和调节)我上次购买一包香烟的时间。
除了-h
打印输出之外,它还需要另一个选项:-b
使用(预期的)可选参数来设置偏移量(以小时为单位)。因此-b 5
记录 5 小时前购买的一包新香烟,随后的运行指示cigs.sh
自那时以来已经过了多少周、多少天或多少小时。如果自上次购买一包以来经过的时间少于$threshold
,则输出以红色打印;如果经过的时间超过$threshold
,则输出为绿色,表示现在“可以”购买一包新香烟了。
我已经设法让所有这一切工作正常,除了一件事:目前无法指定-b
没有偏移量(即记录购买是现在进行的,而不是几个小时前进行的)。据我所知,这似乎是 的一个限制getopts
:如果 中没有冒号b:h
,$OPTARG 将无法填充,从而导致 case 选项中的逻辑b)
失败;如果使用冒号,则无法-b
在没有参数的情况下使用,从而引发以下错误:
/usr/local/bin/scripts/cigs.sh:选项需要一个参数——b
传递了未知参数:-b
这是getopts
我的脚本的一部分:
while getopts "b:h" OPTION; do
case $OPTION in
h)
echo "$usage"
exit
;;
b)
offset=$OPTARG
if [[ -n $offset && ! $offset =~ ^[0-9]+$ ]]; then
echo "HOURS parameter passed to -b must be an integer."
exit
fi
echo -e "Bought a new $item...\nResetting timer to 0 days and $offset hours."
offset=$((offset*60*60))
last_bought="$(date -u +%s)"
new_lb=$((last_bought-offset))
echo $new_lb > $lb_file
exit
;;
*)
echo "Unknown parameter passed: $1"
exit 1
;;
esac
done
答案1
这是一个非常有趣的问题。根据我对getopts
工作原理的理解,使用单个冒号 ( :
) 意味着必须设置选项值:
getopts "b:h"
如果您希望它是可选的,您需要设置两个冒号(::
),并且后面没有任何内容,如下所示:
getopts "hb::"
但那hb::
不起作用。
我尝试了你的脚本,这是我能找到的唯一解决方案。它改变了你的代码,getopts "b:h"
所以getopts "bh"
两个选项参数都是可选的。但神奇之处在于在案例中添加了更多代码b)
,所以整个while
块现在看起来像这样:
while getopts "bh" OPTION; do
case $OPTION in
h)
echo "$usage"
exit
;;
b)
eval nextopt=\${$OPTIND}
if [[ -n $nextopt && $nextopt != -* ]] ; then
OPTIND=$((OPTIND + 1))
offset=$nextopt
else
offset=0
fi
if [[ -n $offset && ! $offset =~ ^[0-9]+$ ]]; then
echo "HOURS parameter passed to -b must be an integer."
exit
fi
echo -e "Bought a new $item...\nResetting timer to 0 days and $offset hours."
offset=$((offset*60*60))
last_bought="$(date -u +%s)"
new_lb=$((last_bought-offset))
echo $new_lb > $lb_file
exit
;;
*)
echo "Unknown parameter passed: $1"
exit 1
;;
esac
done
魔法来自于这块基于此其他 Stack Overflow 答案关于同一问题的问题:
# Check next positional parameter
eval nextopt=\${$OPTIND}
# existing or starting with dash?
if [[ -n $nextopt && $nextopt != -* ]] ; then
OPTIND=$((OPTIND + 1))
offset=$nextopt
显然,如果它能工作的话,它就不会像预期的那样干净getopts "hb::"
,但是它不能,所以这个临时解决方案可以工作。
如果其他更有 Bash 经验的人可以解释原因 — 或者想出更简洁的解决方案 — 他们应该发布出来。目前,这个方法有效,所以有效!