linux的命令列解析引數之getopt_long函式
前言
在linux中,經常需要各種命令,通常情況下都會帶各種引數,而這些引數是如何解析的呢?通常使用GNU C提供的函式getopt、getopt_long、getopt_long_only函式來解析命令列引數。
一、關於命令列引數
命令列引數可以分為兩類,一類是短選項,一類是長選項,短選項在引數前加一槓"-",長選項在引數前連續加兩槓"--",如下表(ls 命令引數)所示,其中-a,-A,-b都表示短選項,--all,--almost-all, --author都表示長選項。他們兩者後面都可選擇性新增額外引數。比如--block-size=SIZE,SIZE便是額外的引數。
二、getopt_long函式
getopt函式只能處理短選項,而getopt_long函式兩者都可以,可以說getopt_long已經包含了getopt_long的功能。因此,這裡就只介紹getopt_long函式。而getopt_long與getopt_long_only的區別很小,等介紹完getopt_long,在提起會更好。
#include <unistd.h> extern char *optarg; extern int optind, opterr, optopt; #include <getopt.h> int getopt(int argc, char * const argv[],const char *optstring); int getopt_long(int argc, char * const argv[], const char *optstring, const struct option *longopts, int *longindex); int getopt_long_only(int argc, char * const argv[], const char *optstring, const struct option *longopts, int *longindex);
引數以及返回值介紹(以上三個函式都適用):
1、argc和argv和main函式的兩個引數一致。
2、optstring: 表示短選項字串。
形式如“a:b::cd:“,分別表示程式支援的命令列短選項有-a、-b、-c、-d,冒號含義如下:
(1)只有一個字元,不帶冒號——只表示選項, 如-c
(2)一個字元,後接一個冒號——表示選項後面帶一個引數,如-a 100
(3)一個字元,後接兩個冒號——表示選項後面帶一個可選引數,即引數可有可無, 如果帶引數,則選項與引數直接不能有空格
形式應該如-b200
3、longopts:表示長選項結構體。結構如下:
struct option { const char *name; int has_arg; int *flag; int val; };
eg:
static struct option longOpts[] = {
{ "daemon", no_argument, NULL, 'D' },
{ "dir", required_argument, NULL, 'd' },
{ "out", required_argument, NULL, 'o' },
{ "log", required_argument, NULL, 'l' },
{ "split", required_argument, NULL, 's' },
{ "http-proxy", required_argument, &lopt, 1 },
{ "http-user", required_argument, &lopt, 2 },
{ "http-passwd", required_argument, &lopt, 3 },
{ "http-proxy-user", required_argument, &lopt, 4 },
{ "http-proxy-passwd", required_argument, &lopt, 5 },
{ "http-auth-scheme", required_argument, &lopt, 6 },
{ "version", no_argument, NULL, 'v' },
{ "help", no_argument, NULL, 'h' },
{ 0, 0, 0, 0 }
};
(1) name:表示選項的名稱,比如daemon,dir,out等。
(2) has_arg:表示選項後面是否攜帶引數。該引數有三個不同值,如下:
a: no_argument(或者是0)時 ——引數後面不跟引數值,eg: --version,--help
b: required_argument(或者是1)時 ——引數輸入格式為:--引數 值 或者 --引數=值。eg:--dir=/home
c: optional_argument(或者是2)時 ——引數輸入格式只能為:--引數=值
(3) flag:這個引數有兩個意思,空或者非空。
a:如果引數為空NULL,那麼當選中某個長選項的時候,getopt_long將返回val值。
eg,可執行程式 --help,getopt_long的返回值為h.
b:如果引數不為空,那麼當選中某個長選項的時候,getopt_long將返回0,並且將flag指標引數指向val值。
eg: 可執行程式 --http-proxy=127.0.0.1:80 那麼getopt_long返回值為0,並且lopt值為1。
(4) val:表示指定函式找到該選項時的返回值,或者當flag非空時指定flag指向的資料的值val。
4、longindex:longindex非空,它指向的變數將記錄當前找到引數符合longopts裡的第幾個元素的描述,即是longopts的下標值。
5、全域性變數:
(1)optarg:表示當前選項對應的引數值。
(2)optind:表示的是下一個將被處理到的引數在argv中的下標值。
(3)opterr:如果opterr = 0,在getopt、getopt_long、getopt_long_only遇到錯誤將不會輸出錯誤資訊到標準輸出流。opterr在非0時,向螢幕輸出錯誤。
(4)optopt:表示沒有被未標識的選項。
6、返回值:
(1)如果短選項找到,那麼將返回短選項對應的字元。
(2)如果長選項找到,如果flag為NULL,返回val。如果flag不為空,返回0
(3)如果遇到一個選項沒有在短字元、長字元裡面。或者在長字元裡面存在二義性的,返回“?”
(4)如果解析完所有字元沒有找到(一般是輸入命令引數格式錯誤,eg: 連斜槓都沒有加的選項),返回“-1”
(5)如果選項需要引數,忘了新增引數。返回值取決於optstring,如果其第一個字元是“:”,則返回“:”,否則返回“?”。
注意:
(1)longopts的最後一個元素必須是全0填充,否則會報段錯誤
(2)短選項中每個選項都是唯一的。而長選項如果簡寫,也需要保持唯一性。
三、測試(自行測試)
1、官網給出測試用例。
#include <stdio.h> /* for printf */
#include <stdlib.h> /* for exit */
#include <getopt.h>
int
main(int argc, char **argv)
{
int c;
int digit_optind = 0;
while (1) {
int this_option_optind = optind ? optind : 1;
int option_index = 0;
static struct option long_options[] = {
{"add", required_argument, 0, 0 },
{"append", no_argument, 0, 0 },
{"delete", required_argument, 0, 0 },
{"verbose", no_argument, 0, 0 },
{"create", required_argument, 0, 'c'},
{"file", required_argument, 0, 0 },
{0, 0, 0, 0 }
};
c = getopt_long(argc, argv, "abc:d:012",
long_options, &option_index);
if (c == -1)
break;
switch (c) {
case 0:
printf("option %s", long_options[option_index].name);
if (optarg)
printf(" with arg %s", optarg);
printf("\n");
break;
case '0':
case '1':
case '2':
if (digit_optind != 0 && digit_optind != this_option_optind)
printf("digits occur in two different argv-elements.\n");
digit_optind = this_option_optind;
printf("option %c\n", c);
break;
case 'a':
printf("option a\n");
break;
case 'b':
printf("option b\n");
break;
case 'c':
printf("option c with value '%s'\n", optarg);
break;
case 'd':
printf("option d with value '%s'\n", optarg);
break;
case '?':
break;
default:
printf("?? getopt returned character code 0%o ??\n", c);
}
}
if (optind < argc) {
printf("non-option ARGV-elements: ");
while (optind < argc)
printf("%s ", argv[optind++]);
printf("\n");
}
exit(EXIT_SUCCESS);
}
2、自己專案相關一個例子。
#include<stdio.h>
#include <getopt.h>
#include<iostream>
#include<string>
#include<stdlib.h>
using namespace std;
void showUsage() {
//cout << "Usage: " << PACKAGE_NAME << " [options] URL ..." << endl;
cout << "Options:" << endl;
cout << " -d, --dir=DIR The directory to store downloaded file." << endl;
cout << " -o, --out=FILE The file name for downloaded file." << endl;
cout << " -l, --log=LOG The file path to store log. If '-' is specified," << endl;
cout << " log is written to stdout." << endl;
cout << " -D, --daemon Run as daemon." << endl;
cout << " -s, --split=N Download a file using s connections. s must be" << endl;
cout << " between 1 and 5. If this option is specified the" << endl;
cout << " first URL is used, and the other URLs are ignored." << endl;
cout << " --http-proxy=HOST:PORT Use HTTP proxy server. This affects to all" << endl;
cout << " URLs." << endl;
cout << " --http-user=USER Set HTTP user. This affects to all URLs." << endl;
cout << " --http-passwd=PASSWD Set HTTP password. This affects to all URLs." << endl;
cout << " --http-proxy-user=USER Set HTTP proxy user. This affects to all URLs" << endl;
cout << " --http-proxy-passwd=PASSWD Set HTTP proxy password. This affects to all URLs." << endl;
cout << " --http-auth-scheme=SCHEME Set HTTP authentication scheme. Currently, BASIC" << endl;
cout << " is the only supported scheme." << endl;
cout << " -v, --version Print the version number and exit." << endl;
cout << " -h, --help Print this message and exit." << endl;
cout << "URL:" << endl;
cout << " You can specify multiple URLs. All URLs must point to the same file" << endl;
cout << " or a download fails." << endl;
cout << "Examples:" << endl;
cout << " Download a file by 1 connection:" << endl;
cout << " aria2c http://AAA.BBB.CCC/file.zip" << endl;
cout << " Download a file by 2 connections:" << endl;
cout << " aria2c -s 2 http://AAA.BBB.CCC/file.zip" << endl;
cout << " Download a file by 2 connections, each connects to a different server." << endl;
cout << " aria2c http://AAA.BBB.CCC/file.zip http://DDD.EEE.FFF/GGG/file.zip" << endl;
cout << "Reports bugs to <tujikawa at rednoah dot com>" << endl;
}
int main(int argc, char* argv[]) {
bool stdoutLog = false;
string logfile;
string dir;
string ufilename;
int split = 0;
bool daemonMode = false;
int c;
while(1) {
int optIndex = 0;
int lopt;
static struct option longOpts[] = {
{ "daemon", no_argument, NULL, 'D' },
{ "dir", required_argument, NULL, 'd' },
{ "out", required_argument, NULL, 'o' },
{ "log", required_argument, NULL, 'l' },
{ "split", required_argument, NULL, 's' },
{ "http-proxy", required_argument, &lopt, 1 },
{ "http-user", required_argument, &lopt, 2 },
{ "http-passwd", required_argument, &lopt, 3 },
{ "http-proxy-user", required_argument, &lopt, 4 },
{ "http-proxy-passwd", required_argument, &lopt, 5 },
{ "http-auth-scheme", required_argument, &lopt, 6 },
{ "version", no_argument, NULL, 'v' },
{ "help", no_argument, NULL, 'h' },
{ 0, 0, 0, 0 }
};
c = getopt_long(argc, argv, "Dd:o:l:s:vh", longOpts, &optIndex);
printf("返回值: %c\n",c);
if(c == -1) {
break;
}
switch(c) {
case 0:{
switch(lopt) {
case 1: {
printf("1: %s\n",optarg);
break;
}
case 2:
printf("2: %s\n",optarg);
break;
case 3:
printf("3: %s\n",optarg);
break;
case 4:
printf("4: %s\n",optarg);
break;
case 5:
printf("5: %s\n",optarg);
break;
case 6:
printf("6: %s\n",optarg);
break;
}
break;
}
case 'D':
printf("D: %s\n",optarg);
break;
case 'd':
printf("d: %s\n",optarg);
break;
case 'o':
printf("o: %s\n",optarg);
break;
case 'l':
printf("l: %s\n",optarg);
break;
case 's':
printf("s: %s\n",optarg);
break;
case 'v':
printf("s: %s\n",optarg);
//showVersion();
exit(0);
case 'h':
showUsage();
exit(0);
default:
showUsage();
exit(1);
}
}
return 0;
}
[參考] : https://blog.csdn.net/qq_33850438/article/details/80172275