getopt没有按某种顺序获取参数

时间:2016-04-05 15:41:43

标签: c getopt

我使用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,如果有用,但更安全,抱歉)。

3 个答案:

答案 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'的函数中,以使其行为不同。 })