getopt使用
参考:
http://www.gnu.org/software/libc/manual/html_node/Example-of-Getopt.html
http://en.wikipedia.org/wiki/Getopt
http://www.lemoda.net/c/getopt/
http://www.ibm.com/developerworks/aix/library/au-unix-getopt.html
http://stackoverflow.com/questions/16483119/example-of-how-to-use-getopt-in-bash
Example of Parsing Arguments with getopt
Here is an example showing how getopt
is typically used. The key points to notice are:
- Normally,
getopt
is called in a loop. Whengetopt
returns-1
, indicating no more options are present, the loop terminates. - A
switch
statement is used to dispatch on the return value fromgetopt
. In typical use, each case just sets a variable that is used later in the program. - A second loop is used to process the remaining non-option arguments.
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> int
main (int argc, char **argv)
{
int aflag = ;
int bflag = ;
char *cvalue = NULL;
int index;
int c; opterr = ; while ((c = getopt (argc, argv, "abc:")) != -)
switch (c)
{
case 'a':
aflag = ;
break;
case 'b':
bflag = ;
break;
case 'c':
cvalue = optarg;
break;
case '?':
if (optopt == 'c')
fprintf (stderr, "Option -%c requires an argument.\n", optopt);
else if (isprint (optopt))
fprintf (stderr, "Unknown option `-%c'.\n", optopt);
else
fprintf (stderr,
"Unknown option character `\\x%x'.\n",
optopt);
return ;
default:
abort ();
} printf ("aflag = %d, bflag = %d, cvalue = %s\n",
aflag, bflag, cvalue); for (index = optind; index < argc; index++)
printf ("Non-option argument %s\n", argv[index]);
return ;
}
Here are some examples showing what this program prints with different combinations of arguments:
% testopt
aflag = 0, bflag = 0, cvalue = (null) % testopt -a -b
aflag = 1, bflag = 1, cvalue = (null) % testopt -ab
aflag = 1, bflag = 1, cvalue = (null) % testopt -c foo
aflag = 0, bflag = 0, cvalue = foo % testopt -cfoo
aflag = 0, bflag = 0, cvalue = foo % testopt arg1
aflag = 0, bflag = 0, cvalue = (null)
Non-option argument arg1 % testopt -a arg1
aflag = 1, bflag = 0, cvalue = (null)
Non-option argument arg1 % testopt -c foo arg1
aflag = 0, bflag = 0, cvalue = foo
Non-option argument arg1 % testopt -a -- -b
aflag = 1, bflag = 0, cvalue = (null)
Non-option argument -b % testopt -a -
aflag = 1, bflag = 0, cvalue = (null)
Non-option argument -
Example of getopt in C
#include <stdio.h>
/* getopt is defined in "unistd.h". */
#include <unistd.h> int main (int argc, char ** argv)
{
int i; while () {
char c; c = getopt (argc, argv, "ab:");
if (c == -) {
/* We have finished processing all the arguments. */
break;
}
switch (c) {
case 'a':
printf ("User has invoked with -a.\n");
break;
case 'b':
printf ("User has invoked with -b %s.\n", optarg);
break;
case '?':
default:
printf ("Usage: %s [-a] [-b <something>].\n", argv[]);
}
} /* Now set the values of "argc" and "argv" to the values after the
options have been processed, above. */
argc -= optind;
argv += optind; /* Now do something with the remaining command-line arguments, if
necessary. */
if (argc > ) {
printf ("There are %d command-line arguments left to process:\n", argc);
for (i = ; i < argc; i++) {
printf (" Argument %d: '%s'\n", i + , argv[i]);
}
}
return ;
}
example of how to use getopt in bash
#!/bin/bash usage() { echo "Usage: $0 [-s <45|90>] [-p <string>]" >&; exit ; } while getopts ":s:p:" o; do
case "${o}" in
s)
s=${OPTARG}
((s == || s == )) || usage
;;
p)
p=${OPTARG}
;;
*)
usage
;;
esac
done
shift $((OPTIND-)) if [ -z "${s}" ] || [ -z "${p}" ]; then
usage
fi echo "s = ${s}"
echo "p = ${p}" Example runs: $ ./myscript.sh
Usage: ./myscript.sh [-s <|>] [-p <string>] $ ./myscript.sh -h
Usage: ./myscript.sh [-s <|>] [-p <string>] $ ./myscript.sh -s "" -p ""
Usage: ./myscript.sh [-s <|>] [-p <string>] $ ./myscript.sh -s -p foo
Usage: ./myscript.sh [-s <|>] [-p <string>] $ ./myscript.sh -s -p foo
s =
p = foo $ ./myscript.sh -s -p bar
s =
p = bar
Command-line processing with getopt()
Introduction
Early in its evolution, the command-line environment of UNIX® (its only user interface back then) became dominated by dozens of small text-processing tools. These tools were small and generally did one thing well. The tools were chained together in longer command pipelines, one program passing its output to the next as input, and controlled by a variety of command-line options and arguments.
This is one aspect of UNIX that makes it a supremely powerful environment for processing text-based data, one of its first uses in a corporate environment. Dump some text in one end of a command pipeline and retrieve processed output from the other end.
Command-line options and arguments control UNIX programs and tell them how to behave. As a developer, it's your responsibility to discover the user's intentions from the command line passed to your program's main()
function. This article shows you how to use the standard getopt()
and getopt_long()
functions to simplify your command-line processing, and it covers one technique for keeping track of your command-line options.
Before you start
The sample code included with this article (see Downloads) was written in Eclipse 3.1 using the C Development Tooling (CDT); the getopt_demo and getopt_long_demo projects are Managed Make projects, which are built using the CDT's program-generation rules. You won't find a Makefile in the project, but it's so trivial that you'll have no trouble generating one if you need to compile the code outside of Eclipse.
If you haven't tried using Eclipse yet (see Resources), you should really give it a go -- it's an excellent integrated development environment (IDE) that just gets better with each release. And that's coming from a die-hard EMACS- and Makefile-based developer.
Command lines
When you're working on a new program, one of the first obstacles you'll face is what to do about the command-line arguments that control its behavior. These are passed from the command line to your program's main()
function as an integer count (traditionally named argc) and an array of pointers to strings (traditionally named argv). The standard main()
function can be declared in two different ways that are essentially the same, as shown in Listing 1.
Listing 1. The main()
function's double life
int main( int argc, char *argv[] );
int main( int argc, char **argv );
The first one, with its array of pointers to char
, seems to be more fashionable these days, and slightly less confusing than the second version, with its pointer to pointers to char
. For some reason, I tend to use the second form more often, possibly to represent my hard-won victory over the C pointer learning curve way back in high school. For all intents and purposes, these are identical, so use whichever one appeals to you the most.
When your main()
is called by the C runtime library's program startup code, the command line has already been processed. The argc
argument contains a count of arguments, and argv
contains an array of pointers to those arguments. To the C runtime library, arguments are the program's name, and anything after the program's name should be separated by whitespace.
For example, if you ran a program named foo with arguments of -v bar www.ibm.com
, your argc would be set to 4, and argv
would be set up as shown in Listing 2.
Listing 2. argv's contents
argv[0] - foo
argv[1] - -v
argv[2] - bar
argv[3] - www.ibm.com
A program has only one set of command-line arguments, so I'm going to store this information in a global structure that tracks options and settings. Anything that makes sense for the program to track globally can go in this structure, and I'm using a structure to help reduce the number of global variables. As I mentioned in my network services design article (see Resources), globals are bad for threaded programming, so it's a good idea to use them carefully.
The sample code is going to show command-line processing for an imaginary doc2html program. The doc2html program translates some sort of document into HTML, controlled by the command-line options specified by the user. It supports the following options:
-I
-- Don't create a keyword index.-l lang
-- Translate into the language specified using the language code,lang
.-o outfile.html
-- Write the translated document to outfile.html instead of printing to standard output.-v
- - Be verbose while translating; can be specified multiple times to increase the diagnostic level.- Additional file names will be used as input document.
You'll also support -h
and -?
to print a help message that gives the user a reminder about these options.
Simple command-line processing: getopt()
The getopt()
function, which lives in the unistd.h system header file, is shown in Listing 3:
Listing 3. getopt()
prototype
int getopt( int argc, char *const argv[], const char *optstring );
Given a number of command-line arguments (argc
), an array of pointers to those arguments (argv
), and an option string (optstring
), getopt()
returns the first option, and sets some global variables. When you call it again with the same arguments, it returns the next option, and sets the global variables. If no more recognized options are found, it returns -1
and you're done.
The global variables set by getopt()
include:
optarg
-- A pointer to the current option argument, if there is one.optind
-- An index of the next argv pointer to process whengetopt()
is called again.optopt
-- This is the last known option.
The option string (optstring
) is one character per option. Options that have arguments, such as the -l
and -o
options in the example, are followed by a :
character. The optstring
used by the example is Il:o:vh?
(remember, you also want to support the last two options for printing the program's usage message).
You call getopt()
repeatedly until it returns -1
; any remaining command-line arguments are usually considered file names or something else appropriate for the program.
getopt()
in action
Let's walk through the getopt_demo project's code; I've split it up here to make it easier to talk about, but you can see it in its full glory in the downloadable source code (see Downloads).
In Listing 4, you can see the system headers used by the demo program; standard fare with stdio.h
for standard I/O function prototypes, stdlib.h
for EXIT_SUCCESS
and EXIT_FAILURE
, and unistd.h
for getopt()
.
Listing 4. System headers
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
Listing 5 shows the globalArgs
structure I've created to store the command-line options in a sensible manner. Since it's a global variable, code anywhere in the program can access these variables to see whether to create a keyword index, which language to generate, and so on. It's a good idea for code outside of the main()
function to treat this structure as a constant, read-only storage area, since any part of the program could depend on its contents.
There's one variable per command-line option, with extra variables to store the output file name, a pointer to the list of input files, and the number of input files.
Listing 5. Global argument storage and option string
struct globalArgs_t {
int noIndex; /* -I option */
char *langCode; /* -l option */
const char *outFileName; /* -o option */
FILE *outFile;
int verbosity; /* -v option */
char **inputFiles; /* input files */
int numInputFiles; /* # of input files */
} globalArgs; static const char *optString = "Il:o:vh?";
The option string, optString
, tells getopt()
which options you can process, and which options require an argument. If other options are encountered during processing, getopt()
displays an error message, and the program exits after displaying a usage message.
Listing 6 contains some small stubs for the usage message function and document conversion function referenced from main()
, below. Feel free to make these do something more useful than nothing!
Listing 6. Stubs
void display_usage( void )
{
puts( "doc2html - convert documents to HTML" );
/* ... */
exit( EXIT_FAILURE );
} void convert_document( void )
{
/* ... */
}
Finally, with Listing 7, you've made it to the main()
function. Like good developers, you need to initialize the globalArgs
structure before you begin processing the command-line arguments. In your programs, you can use this to set up reasonable defaults for your options in one place, which will make it easier to tweak later if more reasonable defaults come to light.
Listing 7. Initialization
int main( int argc, char *argv[] )
{
int opt = 0; /* Initialize globalArgs before we get to work. */
globalArgs.noIndex = 0; /* false */
globalArgs.langCode = NULL;
globalArgs.outFileName = NULL;
globalArgs.outFile = NULL;
globalArgs.verbosity = 0;
globalArgs.inputFiles = NULL;
globalArgs.numInputFiles = 0;
The while
loop and switch
statement in Listing 8 are the meat of the command-line processing for this program. Whenever getopt()
discovers an option, the switch
statement decides which option was found, and you take note of that in the globalArgs
structure. When getopt()
finally returns -1
, you're done processing options, and the remaining arguments are your input files.
Listing 8. Processing argc/argv with getopt()
opt = getopt( argc, argv, optString );
while( opt != -1 ) {
switch( opt ) {
case 'I':
globalArgs.noIndex = 1; /* true */
break; case 'l':
globalArgs.langCode = optarg;
break; case 'o':
globalArgs.outFileName = optarg;
break; case 'v':
globalArgs.verbosity++;
break; case 'h': /* fall-through is intentional */
case '?':
display_usage();
break; default:
/* You won't actually get here. */
break;
} opt = getopt( argc, argv, optString );
} globalArgs.inputFiles = argv + optind;
globalArgs.numInputFiles = argc - optind;
Now that you're done collecting arguments and options, you can do whatever it is the program was built for (in this case, converting documents), and exit (Listing 9).
Listing 9. Go to work
convert_document(); return EXIT_SUCCESS;
}
There, done. Perfect. You can stop reading now. Unless you want to bring your program up to the standards of the late '90s and support long options, popularized in GNU applications.
Complex command-line processing: getopt_long()
At some point in the 1990s (if memory serves), UNIX applications started supporting long options, a pair of dashes instead of the single dash used for normal short options, a descriptive option name, and possibly an argument connected to the option with an equal sign.
Luckily, you can add support for long options to your program by using getopt_long()
. As you might have already guessed, getopt_long()
is a version of getopt()
that supports long options in addition to the short options.
The getopt_long()
function takes additional arguments, one of which is a pointer to an array of struct option
objects. This structure is straightforward, as you can see from Listing 10.
Listing 10. option for getopt_long()
struct option {
char *name;
int has_arg;
int *flag;
int val;
};
The name
member is a pointer to the long option's name without the double dashes. The has_arg
member is set to one of no_argument
, optional_argument
, or required_argument
(all defined in getopt.h
) to indicate whether this option has an argument or not. If the flag member isn't set to NULL, the int
it points to will be filled with the value in the val
member when this option is encountered during processing. If the flag member is NULL
, the value in val
is returned by getopt_long()
when it encounters this option; by setting val
to the option's short
argument, getopt_long()
can be used without adding any additional code -- the existing getopt()
that handles while loop
and switch
automatically handles this option.
Already this is more flexible, since options can now have optional arguments. More importantly, it's easy to drop into your existing code with very little work.
Let's see how using getopt_long()
changes the sample program (the getopt_long_demo project can be found in Downloads).
Using getopt_long()
Since the getopt_long_demo is nearly the same as the getopt_demo code you already looked at, I'll just take you through the changed bits. Because you've got more flexibility now, you'll also add support for a --randomize
option, without a corresponding short option.
The getopt_long()
function resides in the getopt.h
header instead of unistd.h
, so you'll need to include that (see Listing 11). I've also included string.h
, because you'll use strcmp()
later to help figure out which long argument you're dealing with.
Listing 11. Additional headers
#include <getopt.h>
#include <string.h>
You've added a flag (see Listing 12) to the globalArgs
for the --randomize
option, and created the longOpts
array to hold information about the long options supported by this program. Except for --randomize
, all of the arguments correspond to existing short options (--no-index
is the same as -I
, for example). By including their short option equivalent as the last entry in the option structure, you can handle the equivalent long options without adding any extra code to the program.
Listing 12. Expanded arguments
struct globalArgs_t {
int noIndex; /* -I option */
char *langCode; /* -l option */
const char *outFileName; /* -o option */
FILE *outFile;
int verbosity; /* -v option */
char **inputFiles; /* input files */
int numInputFiles; /* # of input files */
int randomized; /* --randomize option */
} globalArgs; static const char *optString = "Il:o:vh?"; static const struct option longOpts[] = {
{ "no-index", no_argument, NULL, 'I' },
{ "language", required_argument, NULL, 'l' },
{ "output", required_argument, NULL, 'o' },
{ "verbose", no_argument, NULL, 'v' },
{ "randomize", no_argument, NULL, 0 },
{ "help", no_argument, NULL, 'h' },
{ NULL, no_argument, NULL, 0 }
};
Listing 13 changes the getop()
calls to getopt_long()
, which takes the longOpts
array and an int
pointer (longIndex
) in addition to getopt()
's arguments. The integer pointed to by longIndex
will be set to the index of the currently found long option when getopt_long()
returns 0
.
Listing 13. New and improved option handling
opt = getopt_long( argc, argv, optString, longOpts, &longIndex );
while( opt != -1 ) {
switch( opt ) {
case 'I':
globalArgs.noIndex = 1; /* true */
break; case 'l':
globalArgs.langCode = optarg;
break; case 'o':
globalArgs.outFileName = optarg;
break; case 'v':
globalArgs.verbosity++;
break; case 'h': /* fall-through is intentional */
case '?':
display_usage();
break; case 0: /* long option without a short arg */
if( strcmp( "randomize", longOpts[longIndex].name ) == 0 ) {
globalArgs.randomized = 1;
}
break; default:
/* You won't actually get here. */
break;
} opt = getopt_long( argc, argv, optString, longOpts, amp;longIndex );
}
I've also added a case for 0
where you can handle any long options that don't map to existing short options. In this case, you have only one long option, but the code still uses strcmp()
to make sure it's the one you're expecting.
That's all there is to it; the program now supports more verbose (and more casual user-friendly) long options.
Summary
UNIX users have always depended on command-line arguments to modify the behavior of programs, especially utilities designed to be used as part of the collection of small tools that is the UNIX shell environment. Programs need to be able to handle options and arguments quickly, and without wasting a lot of the developer's time. After all, few programs are designed to simply process command-line arguments, and the developer would rather be working on whatever the program really does.
The getopt()
function is a standard library call that lets you loop over a program's command-line arguments and detect options (with or without arguments attached to them) easily using a straightforward while/switch idiom. Its cousin, getopt_long()
, lets you handle the more descriptive long options with almost no additional work, which is something that makes developers very happy.
Now that you've seen how to easily handle command-line options, you can concentrate on improving your program's command line by adding support for long options, and by adding any additional options you might have been putting off because you didn't want to add additional command-line option handling to your program.
Don't forget to document all of your options and arguments somewhere, and to provide a built-in help function of some sort to help remind
getopt使用的更多相关文章
- getopt,getoptlong学习
getopt和getoptlong被用来解析命令行参数. 一.getopt #include <unistd.h> extern char *optarg; extern i ...
- getopt()和getopt_long()用法
参考链接: http://home.eeworld.com.cn/home.php?mod=space&do=blog&id=43897&uid=101752 http://b ...
- python getopt使用
函数getopt(args, shortopts, longopts = []) 参数args一般是sys.argv[1:] shortopts 短格式 (-) longopts 长格式(--) 命令 ...
- 使用getopt()处理命令行参数
假设有一程序 testopt,其命令行选项参数有: -i 选项 -l 选项 -r 选项 -n <值> 带关联值的选项 则处理 ...
- 命令行选项解析函数(C语言):getopt()和getopt_long()
命令行选项解析函数(C语言):getopt()和getopt_long() 上午在看源码项目webbench时,刚开始就被一个似乎挺陌生函数getopt_long()给卡住了,说实话这函数没怎么见过, ...
- Use getopt() & getopt_long() to Parse Arguments
Today I came across a function [getopt] by accident. It is very useful to parse command-line argumen ...
- [转]Python 命令行参数和getopt模块详解
FROM : http://www.tuicool.com/articles/jaqQvq 有时候我们需要写一些脚本处理一些任务,这时候往往需要提供一些命令行参数,根据不同参数进行不同的处理,在Pyt ...
- getopt
头文件 #include<unistd.h> 定义函数 int getopt(int argc,char * const argv[ ],const char * optstring); ...
- C语言getopt()函数的使用
getopt(分析命令行参数) 相关函数表头文件 #include<unistd.h>定义函数 int getopt(int argc,char * ...
- windows下的getopt/getoptlong函数
windows下的getopt/getoptlong函数 getopt/getopt_long函数是GNU C中的函数,在linux编程中很常用到.这里就不介绍了. windows下没有找到类似的函数 ...
随机推荐
- (转)C/S 与 B/S 区别
感谢:http://www.cnblogs.com/xiaoshuai/archive/2010/05/25/1743741.html C/S结构,即Client/Server(客户机/服务器)结构, ...
- DOM遍历查找结点
一.遍历API(2个) 1.深度优先原则遍历NodeIterator 节点迭代器 创建遍历API对象: var iterator=document.createNodeIterator(开始的父节点对 ...
- idea控制台中文乱码问题解决办法
解决办法: 打开Intellij的安装的bin目录(D:\Program Files\JetBrains\IntelliJ IDEA 14.0\bin ),找到上图的两个文件(根据你的系统是32位或6 ...
- 01-导航实例-QQ空间Demo示例程序源代码
01-导航实例-QQ空间.zip62.4 KB // MJLoginViewController.h Map // // MJLoginViewController.h // 01-导航实例-QQ ...
- BZoj 1003 物流运输 DP+最短路
2013-09-11 09:56 W[I]代表前I天能取得的最小花费,假设在第J天更改一次路线,那么如果有 W[I]>W[J]+第j+1到第I天的最小花费+更改路线的花费(K) 那么更新W[I] ...
- c:forEach 如何输出序号
关键在于<c:forEach>的varStatus属性,具体代码如下: <table width="500" border="0" cells ...
- Objective-C中ORM的运用:实体对象和字典的相互自动转换
http://blog.csdn.net/cooldragon/article/details/18991973 iOS开发中基于ORM的框架很多,如SQLitePersistentObject,实际 ...
- TCP三次握手四次分手
TCP(Transmission Control Protocol) 传输控制协议 TCP是主机对主机层的传输控制协议,提供可靠的连接服务,采用三次握手确认建立一个连接: 位码即tcp标志位,有6种标 ...
- JS实现上下左右对称的九九乘法表
JS实现上下左右对称的九九乘法表 css样式 <style> table{ table-layout:fixed; border-collapse:collapse; } td{ padd ...
- 复选框回显、全选、非全选、cookie处理数据、json数组对象转换处理学习笔记参考的页面
<%@include file="/common/head.jsp"%> <%@ page contentType="text/html; charse ...