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

Linux下getopt()函式的簡單使用

最近在弄Linux C程式設計,本科的時候沒好好學啊,希望學弟學妹們引以為鑑。

好了,雖然囉嗦了點,但確實是忠告。步入正題:

我們的主角----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

花了40多分鐘整理,希望能夠給需要的人帶來幫助。

很多時候我都在尋思,為啥要花時間整理,明明已經非常忙碌了,有這點時間休息一下多好,多愜意?

我總結的原因有一下幾個:

1、總結時會注意到之前沒有關注的問題,可以加深對問題的理解。

2、方便以後忘記的時候查閱

3、與廣大朋友們分享,想想我們從哪些大牛的部落格裡得到的太多了。我們應當向那些大神學習。把自己學到的分享出來,幫助其他人(雖然我很渣,但是三人行必有我師,應該還是會幫到些人吧)。

共勉!努力!

最後給大家介紹一個寫的更加全面的文章:http://blog.csdn.net/huangxiaohu_coder/article/details/7475156

相關推薦

Linuxgetopt()函式簡單使用

最近在弄Linux C程式設計,本科的時候沒好好學啊,希望學弟學妹們引以為鑑。 好了,雖然囉嗦了點,但確實是忠告。步入正題: 我們的主角----getopt()函式。 英雄不問出處,getopt()函式的出處就是unistd.h標頭檔案(哈哈),寫程式碼的時候千萬不

Linuxgetopt()函式的使用

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

(轉載)Linuxgetopt()函式的使用

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

Linuxgetopt函式的使用

getopt為解析命令列引數函式,它是Linux C庫函式。使用此函式需要包含系統標頭檔案unistd.h。 getopt函式宣

Linuxgetopt()、getopt_long()、getopt_long_only()函式簡單使用

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

LinuxMySQL的簡單操作

max name 失效 發現 root用戶 修改 statement times l數據庫 更改mysql數據庫root的密碼 首次進入數據庫是不用密碼的: [root@localhost ~]# /usr/local/mysql/bin/mysql -uroot W

Linux一個最簡單的不依賴第三庫的的C程式(1)

如下程式碼是一段彙編程式碼,雖然標題中使用了C語言這個詞語,但下面確實是一段彙編程式碼,弄清楚了這個程式碼,後續的知識點才會展開。 #PURPOSE: Simple program that exits and returns a # status code back to the Lin

c語言實現linux高危函式system (簡易V1.0版本)

system這個函式真的是要慎用,一不小心就會留下漏洞。 下面是用c語言簡易的實現了一下system函式 #include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<err

linux的selinux簡單運用

首先通過getenforce命令我們可以檢視selimux狀態 通過vim /etc/sysconfig/selinux 編輯selimux配置檔案,啟動 引數SELINUX=enforcing  強制狀態,不可以操作,也會發出警告    &

Linuxtime函式

Linux下time函式都在time.h標頭檔案中。 1、標頭檔案 和時間有關的標頭檔案有以下幾個: time.h sys/time.h sys/times.h sys/timeb.h sys/timex.h time.h是C標準庫的標頭檔案,其餘sys開頭的都是Linux系統自己的標頭檔

對於linuxsystem 函式的深度理解 整理

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

Linuxgets函式警告

由於Linux下的gcc編譯器不支援gets函式,程式編譯過後會出現一個警告,即:“warning: the `gets' function is dangerous and should not be used.”   此時,可以用fgets函式代替,函式在標頭檔案stdio.h中,

對於linuxsystem()函式的深度理解(整理)

對於linux下system()函式的深度理解(整理)   (2013-02-07 08:58:54) 轉載▼ 標籤:  system()   popen()   sys

linuxsystem函式詳解

一、system函式的簡單介紹 標頭檔案 #include <stdlib.h> 函式定義 int system(const char * string); 函式說明 system()會呼叫fork()產生子程序,由子程序來呼叫/bin/sh-

Linux系統函式

Linux下系統函式 rand()函式 獲取02147483647(0RAND_MAX)之間的隨機數。真隨機需要srand()設定種子。一般用時間作為srand()的引數 #include<unistd.h> int rand(void) void srand(uns

linux封裝函式庫——動態庫.so和靜態庫.a(程式碼實現及連結方式)

在linux環境下的連結庫分為靜態連結庫(.a庫)和動態連結庫(.so庫),其作用是把C程式編譯好做成一種可執行連結檔案,主程式檔案呼叫這些程式的函式介面是可以使用a庫或so庫,在主程式中只需要include含有庫中提供的函式介面宣告的標頭檔案即可。所以學會如何

Linuxselect函式檔案描述符0狀態的問題

當然是在有輸入或者輸出時檔案描述符的讀寫狀態改變咯,比如標準輸入的檔案描述符是0,如果用select來等待0號檔案描述符,那麼當在鍵盤上敲字元時開始,就是檔案描述符的讀寫狀態改變之時,這時select函式就會返回;對於套接字描述符來說也是這樣,用select來等待一個伺服器描

Linux實現 OpenSSL 簡單加密與解密字串

場景 shell指令碼中存在明文密碼 客戶要求禁止使用明文密碼,密碼做加密處理. 方案 在網上了解到了Linux OpenSSL加密解密工具 可以指定各種加密演算法為字元,檔案做加密處理. 加密的案例比較多,解密的寥寥無幾. 有興趣的可以去查下中文教程 案例中使用加密演算法 : AES 例項

linux時間函式

void get_local_time(long sec, char *plocaltime, int len) { struct tm t1 = {0}; localtime_r(&sec, &t1); snprintf(plocaltime, len, "%04d-%02

Linuxexec函式詳解

exec核心函式呼叫 exec函式說明 exec函式的作用是執行一個檔案,他有很多同類型函式,對execl而言,所需要傳入的引數,第一個是檔案的絕對路徑,後面就是給要執行檔案傳入的引數,下面的程式,絕對路徑path="/mnt/nfs/hell",傳入的引數有4個