1. 程式人生 > >Linux下getopt()、getopt_long()、getopt_long_only()函式的簡單使用

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的下標值。

  1. #include <unistd.h>
  2. #include <stdlib.h>
  3. #include <stdio.h>
  4. #include <getopt.h>
  5. int
  6. main(int argc, char **argv)  
  7. {  
  8.    int opt;  
  9.    int digit_optind = 0;  
  10.    int option_index = 0;  
  11.    char *optstring = "a:b:c:d";  
  12.    staticstruct option long_options[] = {  
  13.        {"reqarg", required_argument, NULL, 'r'},  
  14.        {"noarg",  no_argument,       NULL, 'n'},  
  15.        {"optarg", optional_argument, NULL, 'o'},  
  16.        {0, 0, 0, 0}  
  17.    };  
  18.    while ( (opt = getopt_long(argc, argv, optstring, long_options, &option_index)) != -1)  
  19.    {  
  20.         printf("opt = %c\n", opt);  
  21.         printf("optarg = %s\n", optarg);  
  22.         printf("optind = %d\n", optind);  
  23.         printf("argv[optind - 1] = %s\n",  argv[optind - 1]);  
  24.         printf("option_index = %d\n", option_index);  
  25.    }  
  26.    return 0;  
  27. }  

編譯執行以上程式並執行,可以得到以下結果:

  1. [email protected]:~/Desktop/getopt$ ./test_getopt_long -a 100 --reqarg 100 --nonarg  
  2. opt = a  
  3. optarg = 100  
  4. optind = 3  
  5. argv[optind - 1] = 100  
  6. option_index = 0  
  7. opt = r  
  8. optarg = 100  
  9. optind = 5  
  10. argv[optind - 1] = 100  
  11. option_index = 0  
  12. ./test_getopt_long: unrecognized option '--nonarg'  
  13. opt = ?  
  14. optarg = (null)  
  15. optind = 6  
  16. argv[optind - 1] = --nonarg  
  17. option_index = 0  

當所給的引數存在問題時,opt(即函式返回值是'?'),如:
  1. [email protected]:~/Desktop/getopt$ ./test_getopt_long -a  
  2. ./test_getopt_long: option requires an argument -- 'a'  
  3. opt = ?  
  4. optarg = (null)  
  5. optind = 2  
  6. argv[optind - 1] = -a  
  7. option_index = 0  
  8. [email protected]:~/Desktop/getopt$ ./test_getopt_long --reqarg  
  9. ./test_getopt_long: option '--reqarg' requires an argument  
  10. opt = ?  
  11. optarg = (null)  
  12. optind = 2  
  13. 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中進行匹配。

相關推薦

Linuxgetopt()getopt_longgetopt_long_only函式簡單使用

我們的主角----getopt()函式。英雄不問出處,getopt()函式的出處就是unistd.h標頭檔案(哈哈),寫程式碼的時候千萬不要忘記把他老人家include上。再來看一下這傢伙的原型(不是六耳獼猴):int getopt(int argc,char * const

linux 的兩種軟體安裝方式 —— 原始碼編譯安裝,編譯好的二進位制直接安裝

我們以 GPG(加密工具)為例來說明兩種安裝方式的區別: 原始碼(Source code releases,名稱中則會含有src等說明資訊,tarball:source),先編譯再安裝 ./c

linux檔案和目錄的壓縮和解壓gzipbzip2tar

檔案的壓縮和解壓: 注意:區分Linux系統中檔案和目錄的區別 首先說一下打包和壓縮的概念: 打包是指將一大堆檔案或目錄什麼的變成一個總的檔案; 壓縮則是將一個大的檔案通過一些壓縮演算法變成一個小檔案。 常見的壓縮副檔名: 副檔名

Linux五種I/O模型詳解阻塞IO非阻塞IOIO複用訊號驅動非同步IO

文章轉載自微信公眾號:漫話程式設計 1 什麼是I/O 程式是由資料+指令構成的,執行程式的過程可以分成下面這幾步: 1.將程式碼載入到記憶體中,逐條執行記憶體中的程式碼 2.在執行程式碼的過程中,可能需要對檔案的讀寫,即將檔案輸入(Input)

Linux四款Web伺服器壓力測試工具http_loadwebbenchabsiege介紹

一、http_load程式非常小,解壓後也不到100Khttp_load以並行複用的方式執行,用以測試web伺服器的吞吐量與負載。但是它不同於大多數壓力測試工具,它可以以一個單一的程序執行,一般不會把客戶機搞死。還可以測試HTTPS類的網站請求。下載地址:http://sof

轉載Linuxgetopt()函式的使用

步入正題: 我們的主角----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

LinuxKVM的圖形界面管理工具virt-manager桌面版

工具 .html mage 使用 get pre shel viso 而且 背景: virt-manager是用於管理KVM虛擬環境的主要工具,virt-manager默認設置下需要使用root用戶才能夠使用該工具。當你想在KVM hypervisor服務器上托管虛擬機,

LinuxKVM的圖形界面管理工具WebVirtMgrWeb版

查看 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