我使用getopt
来解析命令行中的参数,我遇到问题,使其识别可选参数顺序。
我想实现这些案例:
$ ./program -i file.html -o output.html #ex 1
$ ./program -i -o file.html output.html #ex 2
$ ./program -o output.html -i file.html #ex 3
我的代码看起来像这样
while((c = getopt(argc, argv, "hi:o:")) != -1) {
switch(c) {
case 'h':
//prints the help file
break;
case 'i':
ivalue = optarg;
break;
case 'f':
fvalue = optarg;
break;
case '?':
//prints an error
break;
default:
abort();
}
}
为了更好地调试,我还在外面写了
for(int i = optind; i < argc; i++) {
printf("non optional argument %s\n", argv[i]);
return 0;
}
所以示例1和3正确工作,而示例2没有直接获得参数。起初我认为这个函数根本不可能,但是在this示例中,我看到它是。
还有一个额外的问题:如何在没有参数的情况下调用该程序并不是abort()
?
我使用ubuntu 15.10和gcc 5.2.1与apt-get一起安装(dunno,如果有用,但更安全,抱歉)。
答案 0 :(得分:0)
getopt
无法实现您的目标。 optstring中的"i:"
表示如果存在-i
选项,则必须具有参数。在第二个示例中,这意味着-o
被解释为-i
的参数,而不是选项。
如果您使用的是Linux并使用glibc进行链接,则可以使用::
GNU扩展名(例如"hi::o:"
)使-i
采用可选参数。然而,这会破坏您的第一个和第三个示例,因为可选参数需要在选项后立即显示(例如-ifile.html
)。
答案 1 :(得分:0)
在this示例中我看到它[可能]。
不,你没有。您的选项-i
需要一个参数,但在您的非工作情况下,您尝试在-i
及其参数之间插入一个不同的选项。这是不允许的 - 如果一个选项接受一个参数,无论是可选的还是必需的,那么该参数(如果提供的话)必须紧跟在选项字母后面。您链接的示例显示不同。
getopt()
不支持您尝试做的事情,它不遵循标准的Unix惯例。此外,尽管可以想象使用必需参数的方式可以按照您想象的方式工作,但对于具有可选参数的选项来说,它完全不可行。当参数是可选的时,如果不需要直接跟随它们,则无法将它们与它们的选项正确匹配。
还有一个额外的问题:如何在没有参数的情况下调用该程序并不会中止()?
为什么会这样?如果在其命令行上没有为程序指定选项,则getopt()
在第一次调用时返回-1,并且循环体永远不会执行。要从代码中获取abort()
,您需要指定选项字符串中的选项,但是您没有提供特定情况,或者需要参数的选项,但不提供参数(在哪个事件getopt()
返回':'
,您没有提供具体案例)。由于代码目前已编写,因此需要-o
,无论是否有参数,或-i
没有参数。
答案 2 :(得分:0)
要解决这个“限制” ...我更称其为预期功能,我使用了标志和函数。您遍历每个getopt参数,并在传递过程中设置标志和变量(并且在某些情况下,如果希望特定的模型先于另一个函数,则发送到函数以获取返回值并取消设置其他标志。然后,完成后,请执行一些心理数学运算以确定发生什么顺序。
例如,通过脚本使最终用户更容易进行ACL设置(伪代码区域已清楚标记):
getHelp () {
printf "\nThis does stuff with [OPTIONS] and stuff...\n\n"
exit 0
}
main () {
if [[ $targetFile == "-h" ]]; then
usage
exit 0
fi
[[ ! -f $targetFile ]] && [[ ! -d $targetF ]] && {
printf "\nYou must specify a target File or Folder. Exiting.\n"
exit 1
}
modeOctal=1
if [[ readMode -eq 1 ]] || [[ writeMode -eq 1 ]]; then
printf "We're doing stuff to this file or folder...\n"
if [[ readMode -eq 1 ]]; then
modeOctal=`expr $modeOctal + 4`
elif [[ writeMode -eq 1 ]]; then
modeOctal=`expr $modeOctal + 2`
fi
*code to do stuff to setfacl on target*
fi
if [[ removeMode -eq 1 ]]; then
*code to do stuff to setfacl -x permissions on target*
fi
while true; do
case "$1" in
-h)
getHelp
exit 0
;;
-r)
readMode=1
;;
-w)
writeMode=1
;;
-R)
readMode=0
writeMode=0
removeMode=1
;;
-t)
shift
targetFile=$1
targetIsSet=1
;;
--)
shift
break
;;
esac
shift
done
if [[ $targetIsSet == 1 ]]; then
main
exit 0
fi
exit 0
由于您可以每次依靠相同的顺序执行操作,因此可以确保无论执行的顺序如何,执行都是一致的。在此示例中,您还允许使用-t选项的人第二个参数是使用“ -h”代替那里的帮助。
如果下一项是其他选项(例如:-i -o output.file
或{{1}),则可以使用类似的逻辑将脚本添加到处理'-i'或'-o'的函数中,以使其行为不同。 })