getopt 没有按某种顺序获取参数
getopt not getting parameters in some order
我正在使用 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();
}
}
为了更好地调试这个我也在 while
之外写了
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(不知道是否有用,但更安全,抱歉)。
getopt
无法实现您想要执行的操作。 optstring 中的 "i:"
意味着如果 -i
选项存在,它必须有参数。在您的第二个示例中,这意味着 -o
被解释为 -i
的参数而不是选项。
如果您在 Linux 上并与 glibc 链接,您可以使用 ::
GNU 扩展(例如 "hi::o:"
)使 -i
接受一个可选参数.但是,这会破坏您的第一个和第三个示例,因为可选参数需要立即出现在选项之后(例如 -ifile.html
)。
in this example I saw it was [possible].
不,你没有。您的选项 -i
需要一个参数,但在您的非工作情况下,您尝试在 -i
及其参数之间插入一个不同的选项。这是不允许的——如果一个选项带有一个参数,无论是可选的还是必需的,该参数(如果提供)必须紧跟在选项字母之后。您链接的示例没有显示不同。
您尝试做的事情不仅不受 getopt()
支持,而且不遵循标准的 Unix 约定。此外,尽管对于带有 required 参数的选项,它可以按照您想象的方式工作,但对于带有 optional 参数的选项,它是完全行不通的。当参数是可选的时,如果不需要直接跟随它们,则无法将它们与它们的选项正确匹配。
There's also a bonus question: how come calling the program with no parameters doesn't abort()?
为什么会这样?如果在程序的命令行上没有指定任何选项,那么在第一次调用时 getopt()
returns -1,并且永远不会执行循环体。要从您的代码中获取 abort()
,您需要指定选项字符串中的选项,但您没有提供特定案例,或者需要参数但没有提供的选项参数(在事件 getopt()
returns ':'
中,您没有提供具体案例)。由于目前编写的代码,需要 -o
,有或没有参数,或者 -i
没有参数。
为了解决这个问题 "limitation"...我更愿意称之为预期功能,我使用了标志和函数。您遍历每个 getopt 参数并在传递时设置标志和变量(在某些情况下发送到函数以获取 returns 并取消设置其他标志,如果您希望一个特定的标志优先于另一个标志。然后一旦完成您进行一些心算以确定以何种顺序发生的事情。
例如,对于使最终用户更容易设置 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 "" in
-h)
getHelp
exit 0
;;
-r)
readMode=1
;;
-w)
writeMode=1
;;
-R)
readMode=0
writeMode=0
removeMode=1
;;
-t)
shift
targetFile=
targetIsSet=1
;;
--)
shift
break
;;
esac
shift
done
if [[ $targetIsSet == 1 ]]; then
main
exit 0
fi
exit 0
因为你可以指望事情每次都以相同的顺序进行,你可以确保无论你以什么顺序进行,你的执行都是一致的。在这个例子中,你也允许有人使用 -t 选项这需要第二个参数来使用“-h”来获得帮助。
如果下一项是其他选项(例如:-i -o output.file
或 -o -i input.file
)
我正在使用 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();
}
}
为了更好地调试这个我也在 while
之外写了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(不知道是否有用,但更安全,抱歉)。
getopt
无法实现您想要执行的操作。 optstring 中的 "i:"
意味着如果 -i
选项存在,它必须有参数。在您的第二个示例中,这意味着 -o
被解释为 -i
的参数而不是选项。
如果您在 Linux 上并与 glibc 链接,您可以使用 ::
GNU 扩展(例如 "hi::o:"
)使 -i
接受一个可选参数.但是,这会破坏您的第一个和第三个示例,因为可选参数需要立即出现在选项之后(例如 -ifile.html
)。
in this example I saw it was [possible].
不,你没有。您的选项 -i
需要一个参数,但在您的非工作情况下,您尝试在 -i
及其参数之间插入一个不同的选项。这是不允许的——如果一个选项带有一个参数,无论是可选的还是必需的,该参数(如果提供)必须紧跟在选项字母之后。您链接的示例没有显示不同。
您尝试做的事情不仅不受 getopt()
支持,而且不遵循标准的 Unix 约定。此外,尽管对于带有 required 参数的选项,它可以按照您想象的方式工作,但对于带有 optional 参数的选项,它是完全行不通的。当参数是可选的时,如果不需要直接跟随它们,则无法将它们与它们的选项正确匹配。
There's also a bonus question: how come calling the program with no parameters doesn't abort()?
为什么会这样?如果在程序的命令行上没有指定任何选项,那么在第一次调用时 getopt()
returns -1,并且永远不会执行循环体。要从您的代码中获取 abort()
,您需要指定选项字符串中的选项,但您没有提供特定案例,或者需要参数但没有提供的选项参数(在事件 getopt()
returns ':'
中,您没有提供具体案例)。由于目前编写的代码,需要 -o
,有或没有参数,或者 -i
没有参数。
为了解决这个问题 "limitation"...我更愿意称之为预期功能,我使用了标志和函数。您遍历每个 getopt 参数并在传递时设置标志和变量(在某些情况下发送到函数以获取 returns 并取消设置其他标志,如果您希望一个特定的标志优先于另一个标志。然后一旦完成您进行一些心算以确定以何种顺序发生的事情。
例如,对于使最终用户更容易设置 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 "" in
-h)
getHelp
exit 0
;;
-r)
readMode=1
;;
-w)
writeMode=1
;;
-R)
readMode=0
writeMode=0
removeMode=1
;;
-t)
shift
targetFile=
targetIsSet=1
;;
--)
shift
break
;;
esac
shift
done
if [[ $targetIsSet == 1 ]]; then
main
exit 0
fi
exit 0
因为你可以指望事情每次都以相同的顺序进行,你可以确保无论你以什么顺序进行,你的执行都是一致的。在这个例子中,你也允许有人使用 -t 选项这需要第二个参数来使用“-h”来获得帮助。
如果下一项是其他选项(例如:-i -o output.file
或 -o -i input.file
)