Linux下getopt()、getopt_long()、getopt_long_only()函式的簡單使用
我們的主角----getopt()函式。
英雄不問出處,getopt()函式的出處就是unistd.h標頭檔案(哈哈),寫程式碼的時候千萬不要忘記把他老人家include上。
再來看一下這傢伙的原型(不是六耳獼猴):
int getopt(int argc,char * const argv[ ],const char * optstring);
前兩個引數大家不會陌生,沒錯,就是老大main函式的兩個引數!老大傳進來的引數自然要有人接著!
第三個引數是個字串,看名字,我們可以叫他選項字串(後面會說明)
返回值為int型別,我們都知道char型別是可以轉換成int型別的,每個字元都有他所對應的整型值,其實這個返回值返回的就是一個字元,什麼字元呢,叫選項字元
簡單瞭解了出身和原型,下面我們看看這傢伙到底有什麼本事吧!
(⊙o⊙)…在此之前還要介紹他的幾個兄弟~~~~呃呃呃
小弟1、extern char* optarg;
小弟2、extern int optind;
小弟3、extern int opterr;
小弟4、extern int optopt;
隊形排的不錯。小弟1是用來儲存選項的引數的(先混個臉熟,後面有例子);小弟2用來記錄下一個檢索位置;小弟3表示的是是否將錯誤資訊輸出到stderr,為0時表示不輸出,小弟4表示不在選項字串optstring中的選項(有點亂哈,後面會有例子)
開始逐漸解釋上面遺留的問題。
問題1:選項到底是個什麼鬼?
在linux下大家都用過這樣一條指令吧:gcc helloworld.c -o helloworld.out; 這條指令中的-o就是命令列的選項,而後面的helloworld.out就是-o選項所攜帶的引數。當然熟悉shell指令的人都知道(雖然我並不熟悉),有些選項是不用帶引數的,而這樣不帶引數的選項可以寫在一起(這一點在後面的例子中會用到,希望理解),比如說有兩個選項-c和-d,這兩個選項都不帶引數(而且明顯是好基友),那麼他們是可以寫在一起,寫成-cd的。實際的例子:當我們刪除一個資料夾時可以使用指令 rm 目錄名 -rf,本來-r表示遞迴刪除,就是刪除資料夾中所有的東西,-f表示不提示就立刻刪除,他們兩個都不帶引數,這時他們就可以寫在一起。
問題2:選項字串又是何方神聖?
還是看個例子吧
"a:b:cd::e",這就是一個選項字串。對應到命令列就是-a ,-b ,-c ,-d, -e 。冒號又是什麼呢? 冒號表示引數,一個冒號就表示這個選項後面必須帶有引數(沒有帶引數會報錯哦),但是這個引數可以和選項連在一起寫,也可以用空格隔開,比如-a123 和-a 123(中間有空格) 都表示123是-a的引數;兩個冒號的就表示這個選項的引數是可選的,即可以有引數,也可以沒有引數,但要注意有引數時,引數與選項之間不能有空格(有空格會報錯的哦),這一點和一個冒號時是有區別的。
好了,先給個程式碼,然後再解釋吧。
#include <unistd.h> #include <stdio.h> int main(int argc, char * argv[]) { int ch; printf("\n\n"); printf("optind:%d,opterr:%d\n",optind,opterr); printf("--------------------------\n"); while ((ch = getopt(argc, argv, "ab:c:de::")) != -1) { printf("optind: %d\n", optind); switch (ch) { case 'a': printf("HAVE option: -a\n\n"); break; case 'b': printf("HAVE option: -b\n"); printf("The argument of -b is %s\n\n", optarg); break; case 'c': printf("HAVE option: -c\n"); printf("The argument of -c is %s\n\n", optarg); break; case 'd': printf("HAVE option: -d\n"); break; case 'e': printf("HAVE option: -e\n"); printf("The argument of -e is %s\n\n", optarg); break; case '?': printf("Unknown option: %c\n",(char)optopt); break; } } }
編譯後命令行執行:# ./main -b "qing er"
輸出結果為:
optind:1,opterr:1
--------------------------
optind: 3
HAVE option: -b
The argument of -b is qing er
我們可以看到:optind和opterr的初始值都為1,前面提到過opterr非零表示產生的錯誤要輸出到stderr上。那麼optind的初值為什麼是1呢?
這就要涉及到main函式的那兩個引數了,argc表示引數的個數,argv[]表示每個引數字串,對於上面的輸出argc就為3,argv[]分別為: ./main 和 -b 和"qing er" ,實際上真正的引數是用第二個-b 開始,也就是argv[1],所以optind的初始值為1;
當執行getopt()函式時,會依次掃描每一個命令列引數(從下標1開始),第一個-b,是一個選項,而且這個選項在選項字串optstring中有,我們看到b後面有冒號,也就是b後面必須帶有引數,而"qing er"就是他的引數。所以這個命令列是符合要求的。至於執行後optind為什麼是3,這是因為optind是下一次進行選項搜尋的開始索引,也是說下一次getopt()函式要從argv[3]開始搜尋。當然,這個例子argv[3]已經沒有了,此時getopt()函式就會返回-1。
再看一個輸入:
./main -b "qing er" -c1234
輸出結果為:
optind:1,opterr:1
--------------------------
optind: 3
HAVE option: -b
The argument of -b is qing er
optind: 4
HAVE option: -c
The argument of -c is 1234
對於這個過程會呼叫三次getopt()函式,和第一個輸入一樣,是找到選項-b和他的引數"qing er",這時optind的值為3,也就意味著,下一次的getopt()要從argv[3]開始搜尋,所以第二次呼叫getopt()函式,找到選項-c和他的引數1234(選項和引數是連在一起的),由於-c1234寫在一起,所以他兩佔一起佔用argv[3],所以下次搜尋從argv[4]開始,而argv[4]為空,這樣第三次呼叫getopt()函式就會返回-1,迴圈隨之結束。
接下來我們看一個錯誤的命令列輸入: ./main -z 123
輸出為:
optind:1,opterr:1
--------------------------
./main: invalid option -- 'z'
optind: 2
Unknown option: z
其中./main: invalid option -- 'z'就是輸出到stderr的錯誤輸出。如果把opterr設定為0那麼就不會有這條輸出。
在看一個錯誤的命令列輸入: ./main -zheng
optind:1,opterr:1
--------------------------
./main: invalid option -- 'z'
optind: 1
Unknown option: z
./main: invalid option -- 'h'
optind: 1
Unknown option: h
optind: 2
HAVE option: -e
The argument of -e is ng
前面提到過不帶引數的選項可以寫在一起,所以當getopt()找到-z的時候,發現在optstring 中沒有,這時候他就認為h也是一個選項,也就是-h和-z寫在一起了,依次類推,直到找到-e,發現optstring中有。
最後要說明一下,getopt()會改變argv[]中引數的順序。經過多次getopt()後,argv[]中的選項和選項的引數會被放置在陣列前面,而optind 會指向第一個非選項和引數的位置。看例子
#include <unistd.h> #include <stdio.h> int main(int argc, char * argv[]) { int i; printf("--------------------------\n"); for(i=0;i<argc;i++) { printf("%s\n",argv[i]); } printf("--------------------------\n"); //int aflag=0, bflag=0, cflag=0; int ch; printf("\n\n"); printf("optind:%d,opterr:%d\n",optind,opterr); printf("--------------------------\n"); while ((ch = getopt(argc, argv, "ab:c:de::")) != -1) { printf("optind: %d\n", optind); switch (ch) { case 'a': printf("HAVE option: -a\n\n"); break; case 'b': printf("HAVE option: -b\n"); printf("The argument of -b is %s\n\n", optarg); break; case 'c': printf("HAVE option: -c\n"); printf("The argument of -c is %s\n\n", optarg); break; case 'd': printf("HAVE option: -d\n"); break; case 'e': printf("HAVE option: -e\n"); printf("The argument of -e is %s\n\n", optarg); break; case '?': printf("Unknown option: %c\n",(char)optopt); break; } } printf("----------------------------\n"); printf("optind=%d,argv[%d]=%s\n",optind,optind,argv[optind]); printf("--------------------------\n"); for(i=0;i<argc;i++) { printf("%s\n",argv[i]); } printf("--------------------------\n"); }
命令列:./main zheng -b "qing er" han -c123 qing
輸出結果為:
--------------------------
./main
zheng
-b
qing er
han
-c123
qing
--------------------------
optind:1,opterr:1
--------------------------
optind: 4
HAVE option: -b
The argument of -b is qing er
optind: 6
HAVE option: -c
The argument of -c is 123
----------------------------
optind=4,argv[4]=zheng
--------------------------
./main
-b
qing er
-c123
zheng
han
qing
--------------------------
可以看到最開始argv[]內容為:
./main
zheng
-b
qing er
han
-c123
qing
在執行了多次getopt後變成了
./main
-b
qing er
-c123
zheng
han
qing
我們看到,被getopt挑出的選項和對應的引數都按順序放在了陣列的前面,而那些既不是選項又不是引數的會按順序放在後面。而此時optind為4,即指向第一個非選項也非選項的引數,zheng
下面來講getopt_long函式,getopt_long函式包含了getopt函式的功能,並且還可以指定“長引數”(或者說長選項),與getopt函式對比,getopt_long比其多了兩個引數:
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);
在這裡,longopts指向的是一個由option結構體組成的陣列,那個陣列的每個元素,指明瞭一個“長引數”(即形如--name的引數)名稱和性質:
struct option {
const char *name;
int has_arg;
int *flag;
int val;
};
name 是引數的名稱
has_arg 指明是否帶引數值,其數值可選:
no_argument (即 0) 表明這個長引數不帶引數(即不帶數值,如:--name)
required_argument (即 1) 表明這個長引數必須帶引數(即必須帶數值,如:--name Bob)
optional_argument(即2)表明這個長引數後面帶的引數是可選的,(即--name和--name Bob均可)
flag 當這個指標為空的時候,函式直接將val的數值從getopt_long的返回值返回出去,當它非空時,val的值會被賦到flag指向的整型數中,而函式返回值為0
val 用於指定函式找到該選項時的返回值,或者當flag非空時指定flag指向的資料的值。
另一個引數longindex,如果longindex非空,它指向的變數將記錄當前找到引數符合longopts裡的第幾個元素的描述,即是longopts的下標值。
- #include <unistd.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <getopt.h>
- int
- main(int argc, char **argv)
- {
- int opt;
- int digit_optind = 0;
- int option_index = 0;
- char *optstring = "a:b:c:d";
- staticstruct option long_options[] = {
- {"reqarg", required_argument, NULL, 'r'},
- {"noarg", no_argument, NULL, 'n'},
- {"optarg", optional_argument, NULL, 'o'},
- {0, 0, 0, 0}
- };
- while ( (opt = getopt_long(argc, argv, optstring, long_options, &option_index)) != -1)
- {
- printf("opt = %c\n", opt);
- printf("optarg = %s\n", optarg);
- printf("optind = %d\n", optind);
- printf("argv[optind - 1] = %s\n", argv[optind - 1]);
- printf("option_index = %d\n", option_index);
- }
- return 0;
- }
編譯執行以上程式並執行,可以得到以下結果:
- [email protected]:~/Desktop/getopt$ ./test_getopt_long -a 100 --reqarg 100 --nonarg
- opt = a
- optarg = 100
- optind = 3
- argv[optind - 1] = 100
- option_index = 0
- opt = r
- optarg = 100
- optind = 5
- argv[optind - 1] = 100
- option_index = 0
- ./test_getopt_long: unrecognized option '--nonarg'
- opt = ?
- optarg = (null)
- optind = 6
- argv[optind - 1] = --nonarg
- option_index = 0
當所給的引數存在問題時,opt(即函式返回值是'?'),如:
- [email protected]:~/Desktop/getopt$ ./test_getopt_long -a
- ./test_getopt_long: option requires an argument -- 'a'
- opt = ?
- optarg = (null)
- optind = 2
- argv[optind - 1] = -a
- option_index = 0
- [email protected]:~/Desktop/getopt$ ./test_getopt_long --reqarg
- ./test_getopt_long: option '--reqarg' requires an argument
- opt = ?
- optarg = (null)
- optind = 2
- argv[optind - 1] = --reqarg
最後說說getopt_long_only函式,它與getopt_long函式使用相同的引數表,在功能上基本一致,只是getopt_long只將--name當作長引數,但getopt_long_only會將--name和-name兩種選項都當作長引數來匹配。在getopt_long在遇到-name時,會拆解成-n -a -m -e到optstring中進行匹配,而getopt_long_only只在-name不能在longopts中匹配時才將其拆解成-n -a -m -e這樣的引數到optstring中進行匹配。
相關推薦
Linux下getopt()、getopt_long()、getopt_long_only()函式的簡單使用
我們的主角----getopt()函式。英雄不問出處,getopt()函式的出處就是unistd.h標頭檔案(哈哈),寫程式碼的時候千萬不要忘記把他老人家include上。再來看一下這傢伙的原型(不是六耳獼猴):int getopt(int argc,char * const
linux 下的兩種軟體安裝方式 —— 原始碼(編譯、安裝),編譯好的二進位制(直接安裝)
我們以 GPG(加密工具)為例來說明兩種安裝方式的區別: 原始碼(Source code releases,名稱中則會含有src等說明資訊,tarball:source),先編譯再安裝 ./c
linux下檔案和目錄的壓縮和解壓(gzip、bzip2、tar)
檔案的壓縮和解壓: 注意:區分Linux系統中檔案和目錄的區別 首先說一下打包和壓縮的概念: 打包是指將一大堆檔案或目錄什麼的變成一個總的檔案; 壓縮則是將一個大的檔案通過一些壓縮演算法變成一個小檔案。 常見的壓縮副檔名: 副檔名
Linux下五種I/O模型詳解(阻塞IO、非阻塞IO、IO複用、訊號驅動、非同步IO)
文章轉載自微信公眾號:漫話程式設計 1 什麼是I/O 程式是由資料+指令構成的,執行程式的過程可以分成下面這幾步: 1.將程式碼載入到記憶體中,逐條執行記憶體中的程式碼 2.在執行程式碼的過程中,可能需要對檔案的讀寫,即將檔案輸入(Input)
Linux下四款Web伺服器壓力測試工具(http_load、webbench、ab、siege)介紹
一、http_load程式非常小,解壓後也不到100Khttp_load以並行複用的方式執行,用以測試web伺服器的吞吐量與負載。但是它不同於大多數壓力測試工具,它可以以一個單一的程序執行,一般不會把客戶機搞死。還可以測試HTTPS類的網站請求。下載地址:http://sof
(轉載)Linux下getopt()函式的使用
步入正題: 我們的主角----getopt()函式。 英雄不問出處,getopt()函式的出處就是unistd.h標頭檔案(哈哈),寫程式碼的時候千萬不要忘記把他老人家include上。 再來看一下這傢伙的原型(不是六耳獼猴): int getopt(int
Linux下&/jobs/fg/bg命令的使用(轉)
序號 選中 前臺 blog sin 如果 繼續 log targe 一、& 這個用在一個命令的最後,可以把這個命令放到後臺執行。 二、【Ctrl】+【Z】 可以將一個正在前臺執行的命令放到後臺,並且暫停。 三、jobs 查看當前有多少在後臺運行的命令。
Linux下查看/修改系統時區、時間
英國倫敦 sha 硬件時間 創建 com rec shanghai asi deb 一、查看和修改Linux的時區 1. 查看當前時區 命令 : "date -R" 2. 修改設置Linux服務器時區 方法 A 命令 : "tzselect" 方法 B 僅限於RedHat
linux下查看機器的CPU、內存信息
linux查看cpu信息Linux下如何查看版本信息, 包括位數和多核信息,今天我們就來一起看看linux 查看版本信息以及查看CPU內核信息、CPU具體型號等等,整個CPU信息一目了然。相信不會讓大家失望。# uname -aLinux euis1 2.6.9-55.ELsmp #1 SMP Fri Apr
Linux下創建和刪除軟、硬鏈接 可臨時處理空間不足
clas 就會 blog file 兩種 而是 也有 符號連接 總計 在Linux系統中,內核為每一個新創建的文件分配一個Inode(索引結點),每個文件都有一個惟一的inode號。文件屬性保存在索引結點裏,在訪問文件時,索引結點被復制到內存在,從而實
轉載:Linux下查看/修改系統時區、時間
div 系統 啟動 localtime ive hctosys red 亞洲 命令 一、查看和修改Linux的時區 1. 查看當前時區 命令 : "date -R" 2. 修改設置Linux服務器時區 方法 A 命令 : "tzselect" 方法 B 僅限於RedHat
Linux下KVM的圖形界面管理工具(virt-manager)(桌面版)
工具 .html mage 使用 get pre shel viso 而且 背景: virt-manager是用於管理KVM虛擬環境的主要工具,virt-manager默認設置下需要使用root用戶才能夠使用該工具。當你想在KVM hypervisor服務器上托管虛擬機,
Linux下KVM的圖形界面管理工具(WebVirtMgr)(Web版)
查看 sta bsp 創建 ron span rac post tsp WebVirtMgr面板 截圖 介紹 WebVirtMgr是一個基於libvirt的Web界面,用於管理虛擬機。它允許您創建和配置新域,並調整域的資源分
在linux下創建和刪除軟、硬鏈接
在linux下創建和刪除軟、硬鏈接說明:在安裝Mysql時,采用軟鏈接的方式來訪問Mysql安裝包,這樣可以避免後期升級,而且不方便知曉其版本,軟鏈接和硬鏈接操作如下 來源地址:https://www.cnblogs.com/xiaochaohuashengmi/archive/2011/10/05/2199
linux下添加邏輯分區並掛載(手動和自動方式)
mount -a 自動掛載 tom rpc nosuid contains fst gid 成功 一、查看新磁盤[root@desktop61 Desktop]# fdisk -cul /dev/sdcDisk /dev/sdc: 21.5 GB, 21474836480
linux下查看物理CPU個數、核數、邏輯CPU個數
相同 查看 red sort red hat wc -l 詳細 dmidecode processor cat /proc/cpuinfo中的信息processor 邏輯處理器的id。physical id 物理封裝的處理器的id。core id
linux下遠程服務器登錄命令(SSH)
str 命令行 tro 服務器 res 密碼 a* 空密碼 密碼登錄 方法一、使用用戶名密碼登錄 在命令行中輸入命令: ssh username@ip_address -p port 之後系統會提示輸入密碼,輸入後即可登錄,如果不添加-p選項,則默認是22端口。 還可以
轉載:Linux下解壓zip亂碼問題的解決(unzip)
方式 -h linu 文件名 inf etc java env 系統默認 https://blog.csdn.net/abyjun/article/details/48344379 在windows上壓縮的文件,是以系統默認編碼中文來壓縮文件。由於zip文件中沒有聲明其編碼
Linux 下監控使用者最大程序數引數(nproc)是否到達上限的步驟:
https://www.cnblogs.com/autopenguin/p/6184886.html 1.檢視各系統使用者的程序(LWP)數: 注意:預設情況下采用 ps 命令並不能顯示出所有的程序。因為 Linux 環境下執行多執行緒,每個執行緒都將以一個輕量級程
linux 下URL中 UTF-8編碼、GB2312編碼與漢字之間的轉換
下面是UTF-8編碼的轉換程式碼 #include <string.h> #include <stdio.h> #include <stdlib.h> /* 16進位制字元表 */ static const char c2x_table[] = "0