加入星計劃,您可以享受以下權(quán)益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴(kuò)散
  • 作品版權(quán)保護(hù)
  • 300W+ 專業(yè)用戶
  • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
  • 5000+ 長期合作伙伴
立即加入
  • 正文
    • 一、linux應(yīng)用程序如何接收參數(shù)?
    • 二、選項
    • 三、getopt
    • 四、getopt_long
    • 五、getopt_long_only
    • 六、綜合實例
  • 推薦器件
  • 相關(guān)推薦
  • 電子產(chǎn)業(yè)圖譜
申請入駐 產(chǎn)業(yè)圖譜

Linux程序之可變參數(shù)&選項那些事!

2023/11/15
2581
閱讀需 39 分鐘
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點資訊討論

一、linux應(yīng)用程序如何接收參數(shù)?

1. argc、argv

Linux應(yīng)用程序執(zhí)行時,我們往往通過命令行帶入?yún)?shù)給程序,比如

ls?/dev/?-l??

其中參數(shù) ?/dev/ 、**-l**都是作為參數(shù)傳遞給命令 ls

應(yīng)用程序又是如何接收這些參數(shù)的?

通常應(yīng)用程序都是從main函數(shù)開始執(zhí)行,傳統(tǒng)的main函數(shù)風(fēng)格如下:

int?main(int?argc,?char*?argv[])?
argc:
程序的命令行參數(shù)的數(shù)量,用于統(tǒng)計參數(shù)數(shù)量。?
argv:
是一個指向一個字符串?dāng)?shù)組的指針,數(shù)組包含了參數(shù),每個字符串就是一個參數(shù),最后一個元素為0。
過一般習(xí)慣使用多級指針來操作字符串。

*char argv[]有時候我們也寫成char argv

**argv[]**是一個存放字符類型元素地址的數(shù)組。

因為 C 中是有字符串的概念的:將每個字符存放在 char 數(shù)組,最后一個元素為****表示字符串的結(jié)束。

**printf(%s)**就是輸出字符串。

并且一般使用argv指針來訪問、處理argv[]數(shù)組的內(nèi)容。

C語言中,數(shù)組就是一個指針加偏移量。

所以argv則是指向一個指針數(shù)組argv[]的指針,不用定義,直接可以用。

在argv[]數(shù)組中存放的的指針指向輸入命令的各部分(調(diào)用程序、選項、參數(shù))。

2. 舉例

下面我們用一個實例來理解argc和argv

/*
*?argc:?命令行參數(shù)的個數(shù)
*?argv:?字符指針數(shù)組(指向各個命令行參數(shù)的字符指針?biāo)鶚?gòu)成的數(shù)組)
*/
int?main(int?argc,?char*?argv[])?//?接收命令行參數(shù)
{
?printf("argc=%dn",argc);
????for?(int?i?=?0;?i?<?argc;?i++)?{
????????printf("argv[%d]:?%sn",?i,?argv[i]);?//?遍歷字符指針數(shù)組argv
????}
????return?0;
}

執(zhí)行結(jié)果

peng@ubuntu:~/work$?./peng?arg1?arg2?arg3?
argc=4
argv[0]:?./peng
argv[1]:?arg1
argv[2]:?arg2
argv[3]:?arg3

參數(shù)與argc,argv關(guān)系如下:

二、選項

1. 選項含義

linux程序除了上述情況以外,我們還經(jīng)常會遇到一個使用方法就是選項應(yīng)用,

比如:ping命令

peng@ubuntu:~/work$?ping?-h
Usage:?ping?[-aAbBdDfhLnOqrRUvV]?[-c?count]?[-i?interval]?[-I?interface]
????????????[-m?mark]?[-M?pmtudisc_option]?[-l?preload]?[-p?pattern]?[-Q?tos]
????????????[-s?packetsize]?[-S?sndbuf]?[-t?ttl]?[-T?timestamp_option]
????????????[-w?deadline]?[-W?timeout]?[hop1?...]?destination

參數(shù)含義:

-a:嘗試將IP地址解析為主機(jī)名。
-A:使用響應(yīng)數(shù)據(jù)包中的附加數(shù)據(jù)。
-b:允許ping廣播地址。
-B:不允許ping廣播地址。
-c?count:設(shè)置要發(fā)送的數(shù)據(jù)包數(shù)量。
-d:使用SO_DEBUG選項。
-D:不將socket設(shè)為分離模式。
-f:向目標(biāo)發(fā)送一個“強(qiáng)制”數(shù)據(jù)包。
-h:顯示幫助信息。
-i?interval:設(shè)置發(fā)送數(shù)據(jù)包之間的時間間隔。
-I?interface:設(shè)置要使用的網(wǎng)絡(luò)接口。
-l?preload:設(shè)置發(fā)送的數(shù)據(jù)包數(shù)量。
-m?mark:設(shè)置ping數(shù)據(jù)包的標(biāo)記。
-M?pmtudisc_option:設(shè)置MTU發(fā)現(xiàn)選項。
-n:不要將IP地址解析為主機(jī)名。
-O:啟用原始輸出。
-p?pattern:設(shè)置數(shù)據(jù)包的模式。
-Q?tos:設(shè)置服務(wù)類型。
-r:不使用路由表,直接發(fā)送數(shù)據(jù)包到目標(biāo)主機(jī)。
-R:啟用記錄路由。
-s?packetsize:設(shè)置數(shù)據(jù)包的大小。
-S?sndbuf:設(shè)置套接字的發(fā)送緩沖區(qū)大小。
-t?ttl:設(shè)置數(shù)據(jù)包的TTL值。
-T?timestamp_option:設(shè)置時間戳選項。
-U:使用UDP數(shù)據(jù)包。
-v:顯示詳細(xì)的ping命令輸出。
-V:顯示ping命令的版本信息。
-w?deadline:設(shè)置等待響應(yīng)的時間。
-W?timeout:設(shè)置等待響應(yīng)的超時時間。

destination:指定要ping的目標(biāo)主機(jī)或IP地址。

這些 - 開頭的都是選項,
[]表示可選的意思

[-aAbBdDfhLnOqrRUvV]????是無參的選項
[-c?count]?[-i?interval]?[-I?interface]
[-m?mark]?[-M?pmtudisc_option]?[-l?preload]?[-p?pattern]?[-Q?tos]
[-s?packetsize]?[-S?sndbuf]?[-t?ttl]?[-T?timestamp_option]
[-w?deadline]?[-W?timeout]?[hop1?...]??這些都是有參數(shù)的選項
destination???必須填寫的參數(shù)

前輩們利用這點發(fā)明了“UNIX 風(fēng)格”的命令,選項前面加一個橫杠-,用于區(qū)分選項和參數(shù)。

2. 程序如何區(qū)分參數(shù)和選項?

在程序的代碼實現(xiàn)中,按照 UNIX 的代碼慣例,上來直接跳過第一個,然后判斷指針指向的字符串第一個字符是不是-,如果是的,那么進(jìn)入一個switch判斷,用case列出多種支持的情況下,應(yīng)該執(zhí)行什么代碼。

例如下面這樣就可以判斷選項和處理參數(shù):

int?c;
while?(--argc?>?0?&&?(*++argv)[0]?==?'-'?{
?while?(c?=?*++argv[0]?{
??switch(c){
??case?'x':
???...
???break;
??case?'n':
???...
???break;
??default:
???printf("xxx:?illegal?opyion?%cn",?c);
???...
???break;
??}
?}
}

3. getopt、getopt_long

事實這么處理選項參數(shù)是比較麻煩的,

linux提供了選項解析的函數(shù):

//?頭文件
#include<unistd.h>
#include<getopt.h>??????????/*所在頭文件?*/
int?getopt(intargc,?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);
extern?char?*optarg;?????????/*系統(tǒng)聲明的全局變量?*/
extern?int?optind,?opterr,?optopt;

三、getopt

1. 定義:

int?getopt(int?argc,?char?*?const?argv[],?const?char?*optstring);
功能:
?getopt是用來解析命令行選項參數(shù)的,但是只能解析短選項:?**-d?100**,不能解析長選項:**--prefix**
參數(shù)
?argc:
??main()函數(shù)傳遞過來的參數(shù)的個數(shù)
?argv:
??main()函數(shù)傳遞過來的參數(shù)的字符串指針數(shù)組
?optstring:
??選項字符串,告知?getopt()可以處理哪個選項以及哪個選項需要參數(shù)
返回:
?如果選項成功找到,返回選項字母;如果所有命令行選項都解析完畢,返回?-1;
?如果遇到選項字符不在?optstring?中,返回字符?‘?’;
?如果遇到丟失參數(shù),那么返回值依賴于?optstring?中第一個字符,
?如果第一個字符是?‘:’?則返回’:‘,否則返回’?'并提示出錯誤信息。

2. optstring 含義 【重要】

下邊重點舉例說明optstring的格式意義:

char*optstring?=?“ab:c::”;
單個字符a?????????表示選項a沒有參數(shù)????????????格式:-a即可,不加參數(shù)
單字符加冒號b:?????表示選項b有且必須加參數(shù)??????格式:-b?100或-b100,但-b=100錯
單字符加2冒號c::???表示選項c可以有,也可以無?????格式:-c200,其它格式錯誤

上面這個 optstring 在傳入之后,getopt 函數(shù)將依次檢查命令行是否指定了 -a, -b, -c(這需要多次調(diào)用 getopt 函數(shù),直到其返回-1),當(dāng)檢查到上面某一個參數(shù)被指定時,函數(shù)會返回被指定的參數(shù)名稱(即該字母)

系統(tǒng)聲明的4個全局變量含義如下:

optarg?——?指向當(dāng)前選項參數(shù)(如果有)的指針。
optind?——?再次調(diào)用?getopt()?時的下一個?argv指針的索引。
optopt?——?最后一個未知選項。
opterr?-——?如果不希望getopt()打印出錯信息,則只要將全域變量opterr設(shè)為0即可。

3. 實例

說千道萬,不如來一個實例:

#include<stdio.h>
#include<unistd.h>
#include<getopt.h>
int?main(intargc,?char?*argv[])
{
????int?opt;
????char?*string?=?"a::b:c:d";
????while?((opt?=?getopt(argc,?argv,?string))!=?-1)
????{??
????????printf("opt?=?%ctt",?opt);
????????printf("optarg?=?%stt",optarg);
????????printf("optind?=?%dtt",optind);
????????printf("argv[optind]?=?%sn",argv[optind]);
????}??
}
    正確輸入?yún)?shù),執(zhí)行結(jié)果如下:
peng@ubuntu:~/work/test$?./peng?-a100?-b?200?-c?300?-d
opt?=?a??optarg?=?100??optind?=?2??argv[optind]?=?-b
opt?=?b??optarg?=?200??optind?=?4??argv[optind]?=?-c
opt?=?c??optarg?=?300??optind?=?6??argv[optind]?=?-d
opt?=?d??optarg?=?(null)??optind?=?7??argv[optind]?=?(null)

或者

ork/test$?./peng?-a100?-b200?-c300?-d?
opt?=?a??optarg?=?100??optind?=?2??argv[optind]?=?-b200
opt?=?b??optarg?=?200??optind?=?3??argv[optind]?=?-c300
opt?=?c??optarg?=?300??optind?=?4??argv[optind]?=?-d
opt?=?d??optarg?=?(null)??optind?=?5??argv[optind]?=?(null)
    輸入選項參數(shù)錯誤的情況
peng@ubuntu:~/work/test$?./peng?-a?100?-b?200?-c?300?-d
opt?=?a??optarg?=?(null)??optind?=?2??argv[optind]?=?100
opt?=?b??optarg?=?200??optind?=?5??argv[optind]?=?-c
opt?=?c??optarg?=?300??optind?=?7??argv[optind]?=?-d
opt?=?d??optarg?=?(null)??optind?=?8??argv[optind]?=?(null)

導(dǎo)致解析錯誤,第一個 optarg = null,實際輸入?yún)?shù) 100,由于格式不正確造成的(可選參數(shù)格式固定)

    參數(shù)丟失,也會導(dǎo)致錯誤
peng@ubuntu:~/work/test$?./peng?-a?-b?200?-c?
opt?=?a??optarg?=?(null)??optind?=?2??argv[optind]?=?-b
opt?=?b??optarg?=?200??optind?=?4??argv[optind]?=?-c
./peng:?option?requires?an?argument?--?'c'
opt?=????optarg?=?(null)??optind?=?5??argv[optind]?=?(null)

c選項是必須有參數(shù)的

    命令行選項未定義,-e選項未在optstring中定義,會報錯:
peng@ubuntu:~/work/test$?./peng?-t
./peng:?invalid?option?--?'t'
opt?=????optarg?=?(null)??optind?=?2??argv[optind]?=?(null)

四、getopt_long

1. 定義:

int?getopt_long(int?argc,?char?*?const?argv[],?const?char?*optstring,
const?struct?option?*longopts,int?*longindex);
功能:
?包含?getopt?功能,增加了解析長選項的功能如:--prefix?--help
參數(shù):
?longopts?
??指明了長參數(shù)的名稱和屬性
?longindex?
??如果longindex非空,它指向的變量將記錄當(dāng)前找到參數(shù)符合longopts里的第幾個元素的描述,即是?longopts?的下標(biāo)值
返回:
?對于短選項,返回值同?getopt?函數(shù);
?對于長選項,
??如果?flag?是?NULL?,返回?val?,否則返回?0?;
?對于錯誤情況返回值同?getopt?函數(shù)

2. struct option

struct?option?{
?const?char??*name;???????/*?參數(shù)名稱?*/
?int??????????has_arg;????/*?指明是否帶有參數(shù)?*/
?int??????????*flag;??????/*?flag=NULL時,返回value;不為空時,*flag=val,返回0?*/
?int??????????val;????????/*?用于指定函數(shù)找到選項的返回值或flag非空時指定*flag的值?*/
};?

參數(shù)has_arg 說明:
has_arg ?指明是否帶參數(shù)值,其數(shù)值可選:

?no_argument?
??表明長選項不帶參數(shù),如:–name,?--help
?required_argument?
??表明長選項必須帶參數(shù),如:–prefix?/root或?--prefix=/root
?optional_argument?
??表明長選項的參數(shù)是可選的,如:–help或?–prefix=/root,其它都是錯誤

3. 實例

#include<stdio.h>
#include<unistd.h>
#include<getopt.h>
int?main(intargc,?char?*argv[])
{
????int?opt;
????int?digit_optind?=?0;
????int?option_index?=?0;
????char?*string?=?"a::b:c:d";
????static?struct?option?long_options[]?=
????{??
????????{"reqarg",?required_argument,NULL,?'r'},
????????{"optarg",?optional_argument,NULL,?'o'},
????????{"noarg",??no_argument,?????????NULL,'n'},
????????{NULL,?????0,??????????????????????NULL,?0},
????};?
????while((opt?=getopt_long_only(argc,argv,string,long_options,&option_index))!=?-1)
????{??
????????printf("opt?=?%ctt",?opt);
????????printf("optarg?=?%stt",optarg);
????????printf("optind?=?%dtt",optind);
????????printf("argv[optind]?=%stt",?argv[optind]);
????????printf("option_index?=?%dn",option_index);
????}??
}
    正確執(zhí)行命令
peng@ubuntu:~/work/test$?./long?--reqarg?100?--optarg=200?--noarg
opt?=?r??optarg?=?100??optind?=?3??argv[optind]?=--optarg=200??option_index?=?0
opt?=?o??optarg?=?200??optind?=?4??argv[optind]?=--noarg??option_index?=?1
opt?=?n??optarg?=?(null)??optind?=?5??argv[optind]?=(null)??option_index?=?2

或者

peng@ubuntu:~/work/test$?./long?–reqarg=100?--optarg=200?--noarg
opt?=?o??optarg?=?200??optind?=?3??argv[optind]?=--noarg??option_index?=?1
opt?=?n??optarg?=?(null)??optind?=?4??argv[optind]?=(null)??option_index?=?2
    可選選項可以不給參數(shù)
peng@ubuntu:~/work/test$?./long?--reqarg?100?--optarg?--noarg
opt?=?r??optarg?=?100??optind?=?3??argv[optind]?=--optarg??option_index?=?0
opt?=?o??optarg?=?(null)??optind?=?4??argv[optind]?=--noarg??option_index?=?1
opt?=?n??optarg?=?(null)??optind?=?5??argv[optind]?=(null)??option_index?=?2
    輸入長選項錯誤的情況
peng@ubuntu:~/work/test$?./long?--reqarg?100?--optarg?200?--noarg
opt?=?r??optarg?=?100??optind?=?3??argv[optind]?=--optarg??option_index?=?0
opt?=?o??optarg?=?(null)??optind?=?4??argv[optind]?=200??option_index?=?1
opt?=?n??optarg?=?(null)??optind?=?6??argv[optind]?=(null)??option_index?=?2

五、getopt_long_only

getopt_long_only 函數(shù)與 getopt_long 函數(shù)使用相同的參數(shù)表,在功能上基本一致

只是 getopt_long 只將 --name 當(dāng)作長參數(shù),但 getopt_long_only 會將 --name 和 -name 兩種選項都當(dāng)作長參數(shù)來匹配

getopt_long_only 如果選項 -name 不能在 longopts 中匹配,但能匹配一個短選項,它就會解析為短選項。

六、綜合實例

下面這個例子,是一口君從開源項目ifplug提取出來的命令提取小例子,

大家可以根據(jù)自己需要,基于這個框架,定制自己的程序。

#define?_GNU_SOURCE
#include?<stdlib.h>
#include?<stdio.h>
#include?<string.h>
#include?<unistd.h>
#include?<errno.h>
#include?<getopt.h>
#include?<sys/param.h>

#define?ETHCHECKD_VERSION?"1.1"


int?delay_up?=?0;
char?*interface?=?"eth0";


void?usage(char?*p)?{
????if?(strrchr(p,?'/'))
????????p?=?strchr(p,?'/')+1;

????printf("%s?[options]n"
???????????"???-i?--iface=IFACE??????????Specify?ethernet?interface?(%s)n"?
???????????"???-d?--delay-up=SECS????????Specify?delay?time?(%i)n"
???????????"???-h?--help?????????????????Show?this?helpn",
???????????p,
???????????interface,
???????????delay_up);
}

void?parse_args(int?argc,?char?*argv[])?{
????static?struct?option?long_options[]?=?{

????????{"iface",????????????????required_argument,?0,?'i'},
????????{"delay-up",?????????????required_argument,?0,?'d'},
????????{"help",?????????????????no_argument,?0,?'h'},
????????{"version",??????????????no_argument,?0,?'v'},
????????{0,?0,?0,?0}
????};
????int?option_index?=?0;
????int?help?=?0,?_kill?=?0,?_check?=?0,?_version?=?0,?_suspend?=?0,?_resume?=?0,?_info?=?0;
????
????for?(;;)?{
????????int?c;
????????
????????if?((c?=?getopt_long(argc,?argv,?"i:d:hv",?long_options,?&option_index))?<?0)
????????????break;

????????switch?(c)?{
????????????case?'i'?:
????????????????interface?=?strdup(optarg);
????printf("interface?%sn",interface);
????????????????break;
????????????case?'d':
????????????????delay_up?=?atoi(optarg);
????printf("delay_up?%dn",delay_up);
????????????????break;
????????????case?'h':
????????????????usage(argv[0]);
????????????????break;
?????????????case?'v':
????????????????printf("peng?"ETHCHECKD_VERSION"n");
????????????????break;
????????????default:
????????????????fprintf(stderr,?"Unknown?parameter.n");
????????????????exit(1);
????????}
????}
????
}

static?volatile?int?alarmed?=?0;

int?main(int?argc,?char*?argv[])?{

????parse_args(argc,?argv);
????return?0;
}

下面是測試結(jié)果

    短選項
peng@ubuntu:~/work/test$?./param?-h
param?[options]
???-i?--iface=IFACE??????????Specify?ethernet?interface?(eth0)
???-d?--delay-up=SECS????????Specify?delay?time?(0)
???-h?--help?????????????????Show?this?help
peng@ubuntu:~/work/test$?./param?-v
peng?1.1

peng@ubuntu:~/work/test$?./param?-vh
peng?1.1
param?[options]
???-i?--iface=IFACE??????????Specify?ethernet?interface?(eth0)
???-d?--delay-up=SECS????????Specify?delay?time?(0)
???-h?--help?????????????????Show?this?help??
???
peng@ubuntu:~/work/test$?./param?-i?eth3?-d?15
interface?eth3
delay_up?15?


peng@ubuntu:~/work/test$?./param?-i?eth3?-d?15?-h
interface?eth3
delay_up?15
param?[options]
???-i?--iface=IFACE??????????Specify?ethernet?interface?(eth3)
???-d?--delay-up=SECS????????Specify?delay?time?(15)
???-h?--help?????????????????Show?this?help
    長選項
peng@ubuntu:~/work/test$?./param?--help
param?[options]
???-i?--iface=IFACE??????????Specify?ethernet?interface?(eth0)
???-d?--delay-up=SECS????????Specify?delay?time?(0)
???-h?--help?????????????????Show?this?help
???
peng@ubuntu:~/work/test$?./param?--version
peng?1.1

peng@ubuntu:~/work/test$?./param?--iface?eth3?--delay-up?15
interface?eth3
delay_up?15
talk?is?cheap!
test?this?code!

快操練起來吧?。?!

推薦器件

更多器件
器件型號 數(shù)量 器件廠商 器件描述 數(shù)據(jù)手冊 ECAD模型 風(fēng)險等級 參考價格 更多信息
JST01TMAC1CY5GE2 1 Viavi Solutions Inc Transceiver,
暫無數(shù)據(jù) 查看
6N137-X007T 1 Vishay Intertechnologies Optocoupler Logic-Out Open Collector DC-IN 1-CH 8-Pin PDIP SMD T/R

ECAD模型

下載ECAD模型
$2.22 查看
TJA1055T/3/CM,118 1 NXP Semiconductors TJA1055 - Enhanced fault-tolerant CAN transceiver SOIC 14-Pin

ECAD模型

下載ECAD模型
$1.95 查看

相關(guān)推薦

電子產(chǎn)業(yè)圖譜

公眾號『一口Linux』號主彭老師,擁有15年嵌入式開發(fā)經(jīng)驗和培訓(xùn)經(jīng)驗。曾任職ZTE,某研究所,華清遠(yuǎn)見教學(xué)總監(jiān)。擁有多篇網(wǎng)絡(luò)協(xié)議相關(guān)專利和軟件著作。精通計算機(jī)網(wǎng)絡(luò)、Linux系統(tǒng)編程、ARM、Linux驅(qū)動、龍芯、物聯(lián)網(wǎng)。原創(chuàng)內(nèi)容基本從實際項目出發(fā),保持原理+實踐風(fēng)格,適合Linux驅(qū)動新手入門和技術(shù)進(jìn)階。