你存在幻觉;使用
getopts
不需要在标志字母前加上强制性参数。我试图从我的脚本语料库中找到一个合适的例子; 这是一个半合理的近似值。它被称为
rcsunco
,用于取消从 RCS 中的检出。我好像有一段时间没有修改它了,但我经常使用它(因为我还没有完全迁移到 RCS)。
#!/bin/sh
: ${RCS:=rcs}
: ${CO:=co}
remove=yes
keep=no
get=no
quiet=
while getopts gknqrV opt
do
case $opt in
V) echo "`basename $0 .sh`: RCSUNCO Version $Revision: 2.1 $ ($Date: 2002/08/03 07:41:00 $)" |
rcsmunger
exit 0;;
g) get=yes;;
k) keep=yes;;
n) remove=no;;
q) quiet=-q;;
r) remove=yes;;
*) echo "Usage: `basename $0 .sh` [-{n|g}][-{r|k}] file [...]" 1>&2
exit 1;;
esac
done
shift $(($OPTIND-1))
for file in $*
do
rfile=$(rfile $file)
xfile=$(xfile $rfile)
if $RCS -u $rfile
then
if [ $keep = yes ]
then
if [ -f $xfile ]
then
mv $xfile $xfile.keep
echo "$xfile saved in $xfile.keep"
fi
elif [ $remove = yes ]
then rm -f $xfile
fi
if [ $get = yes ] && [ $remove = yes -o $keep = yes ]
then $CO $quiet $rfile
fi
fi
done
这只是一个半靠谱的近似值;如果你在可选参数后没有提供任何文件名,脚本会安静地不做任何事情。然而,如果需要的话,你可以在 "shift" 后检查是否存在必需的参数。我的另一个脚本确实有必需的参数。它包含以下内容:
...
shift $(($OPTIND - 1))
case $# in
2) case $1 in
install) MODE=Installation;;
uninstall) MODE=Uninstallation;;
*) usage;;
esac;;
*) usage;;
esac
因此,该命令(jlss
)可以接受可选参数,例如-d $HOME
,但需要安装或卸载后跟要安装的内容的名称。基本使用模式如下:
jlss install program
但是可选的模式是:
jlss -d $HOME -u me -g mine -x -p install program
我没有展示所有的jlss
,因为它有大约12个选项-它不像rcsunco
那样紧凑。
如果你在处理强制参数之前处理可选参数,则需要做更多的工作:
- 你需要获取强制参数并将其移到一边。
- 然后你使用标志处理可选参数。
- 最后,如果适当的话,处理额外的“文件名”参数。
如果你正在处理强制参数与可选参数交替出现(在强制参数之前和之后),那么你需要做更多的工作。这被许多版本控制系统所使用;CVS和GIT都有此功能:
git -global option command [-sub option] [...]
在这里,你需要运行一个getopts
循环来获取全局选项;获得必填参数;然后再运行第二个getopts
循环以获取子选项(可能还需要对“文件名”参数进行最终循环)。
生活不是很有趣吗?
getopt
命令的手册。简单说就是,在选项后面添加冒号(例如"-rv:x"
,表示v需要带一个参数)。getopt
还支持长选项,这是它优于getopts
内置命令的一种方式。请注意,你需要自己处理额外的非选项参数。 - sorpigalgetopt
存在问题。根据man
手册中的描述:"传统的 getopt(1) 实现无法处理参数和非选项参数中的空格和其他(特定于 shell 的)特殊字符。" 查看man
手册 以获取更多详细信息并测试您的版本是否存在这些问题。 - Dennis Williamson