雖然沒有辦法做到很完美,例如像"ps aux"和"rpm -ivh"這種指令的選項解譯,但是還是有符合大部份Linux系統下的指令需求。
getopt_long()函式所傳進去的第4個引數const struct option *longopts,它是一個option的結構陣列,option結構的第4個成員int val; 的用法,和第1個成員const char *name; 相呼應。換句話說,就是當使用者輸入長選項"--help"時,就等同於短選項的"-H"。
問題來了,option結構的第2個成員int has_arg; 是決定這個長選項是否要帶參數。而getopt_long()函式所傳進去的第3個引數const char *optstring; 是定義短選項的字元,若字元後面有接冒號 (:)就代表這個短選項後面需要接參數;沒有接冒號就代表不需要接參數。
Question: 「如果第3個引數const char *optstring; 和第4個引數const struct option *longopts的設定『發生衝突』,會發生什麼事?」
長選項的option結構的第2個成員int has_arg; 有3種設定方式:沒有參數 (no_argument)、必有參數 (required_argument)和可有參數 (optional_argument);短選項就只有2種設定方式:沒有參數 ()和必有參數 (:)。
所以,如此又多了3 * 2 = 6種測試方式!我們先來看最理想的狀況:
Step VIII: 長選項設定為沒有參數 (no_argument);短選項也設定為沒有參數 ()
57. ./main --help
58. ./main --help 1234
59. ./main -H
60. ./main -H 1234
[root@localhost]# [root@localhost]# ./main --help You got a short option argv[1]: "-H" [root@localhost]# [root@localhost]# ./main --help 1234 You got a short option argv[1]: "-H", but DOESN'T need argument argv[2]: 1234 [root@localhost]# [root@localhost]# ./main -H You got a short option argv[1]: "-H" [root@localhost]# [root@localhost]# ./main -H 1234 You got a short option argv[1]: "-H", but DOESN'T need argument argv[2]: 1234 [root@localhost]# [root@localhost]#這一部份的測試結果,若長選項"--help"有找到相對應的短選項"-H",執行結果會以短選項為優先。
Step IX: 長選項設定為必有參數 (required_argument);短選項也設定為必有參數 (:)
61. ./main --delete
62. ./main --delete 1234
63. ./main -D
64. ./main -D 1234
[root@localhost]# [root@localhost]# ./main --delete ./main: option '--delete' requires an argument The long option argv[1]: "--delete" need an argument!! [root@localhost]# [root@localhost]# ./main --delete 1234 You got a short option argv[1]: "-D" with an argument: argv[2]: "1234" [root@localhost]# [root@localhost]# ./main -D ./main: option requires an argument -- 'D' The short option argv[1]: "-D" need an argument!! [root@localhost]# [root@localhost]# ./main -D 1234 You got a short option argv[1]: "-D" with an argument: argv[2]: "1234" [root@localhost]# [root@localhost]#不論是長選項或是短選項,應帶參數而未帶參數,getopt_long()函式就直接回傳問號'?'字元;若有帶參數,就直接對應到短選項的設定。
Step X: 長選項設定為沒有參數 (no_argument);短選項設定為必有參數 (:)
65. ./main --count
66. ./main --count 1234
67. ./main -c
68. ./main -c 1234
[root@localhost]# [root@localhost]# ./main --count 程式記憶體區段錯誤 (core dumped) [root@localhost]# [root@localhost]# ./main --count 1234 程式記憶體區段錯誤 (core dumped) [root@localhost]# [root@localhost]# ./main -c ./main: option requires an argument -- 'c' The short option argv[1]: "-c" need an argument!! [root@localhost]# [root@localhost]# ./main -c 1234 You got a short option argv[1]: "-c" with an argument: argv[2]: "1234" [root@localhost]# [root@localhost]#當執行長選項時,就會發生「程式記憶體區段錯誤 (core dumped)」的錯誤訊息;若執行短選項時,則是正常執行。
Step XI: 長選項設定為必有參數 (required_argument);短選項設定為沒有參數 ()
69. ./main --create
70. ./main --create 1234
71. ./main -C
72. ./main -C 1234
[root@localhost]# [root@localhost]# ./main --create ./main: option '--create' requires an argument The long option argv[1]: "--create" need an argument!! [root@localhost]# [root@localhost]# ./main --create 1234 You got a short option argv[2]: "-C" [root@localhost]# [root@localhost]# ./main -C You got a short option argv[1]: "-C" [root@localhost]# [root@localhost]# ./main -C 1234 You got a short option argv[1]: "-C", but DOESN'T need argument argv[2]: 1234 [root@localhost]# [root@localhost]#這個執行結果就有意思了!
a). 當長選項設定為必有參數而未輸入參數時,getopt_long()函式會回傳0,因為它有找到相對應的長選項;
b). 當長選項設定為必有參數而輸入參數時,getopt_long()函式會回傳相對應的短選項字元;但短選項的字元設定為沒有參數,所以就不會抓取輸入長選項時所帶進來的參數。
c). 當短選項設定為沒有參數時,完全不影響長選項的設定。
Step XII: 長選項設定為可有參數 (optional_argument);短選項設定為沒有參數 ()
73. ./main --interface
74. ./main --interface 1234
75. ./main -I
76. ./main -I 1234
[root@localhost]# [root@localhost]# ./main --interface You got a short option argv[1]: "-I" [root@localhost]# [root@localhost]# ./main --interface 1234 You got a short option argv[1]: "-I", but DOESN'T need argument argv[2]: 1234 [root@localhost]# [root@localhost]# ./main -I You got a short option argv[1]: "-I" [root@localhost]# [root@localhost]# ./main -I 1234 You got a short option argv[1]: "-I", but DOESN'T need argument argv[2]: 1234 [root@localhost]# [root@localhost]#輸入短選項時,並沒有什麼問題;但輸入長選項時,則是直接對應到短選項。因為短選項設定為沒有參數,所以不管長選項有無帶參數,都不會抓取。
Step XIII: 長選項設定為可有參數 (optional_argument);短選項設定為必有參數 (:)
73. ./main --list
74. ./main --list 1234
75. ./main -L
76. ./main -L 1234
[root@localhost]# [root@localhost]# ./main --list 程式記憶體區段錯誤 (core dumped) [root@localhost]# [root@localhost]# ./main --list 1234 程式記憶體區段錯誤 (core dumped) [root@localhost]# [root@localhost]# ./main -L ./main: option requires an argument -- 'L' The short option argv[1]: "-L" need an argument!! [root@localhost]# [root@localhost]# ./main -L 1234 You got a short option argv[1]: "-L" with an argument: argv[2]: "1234" [root@localhost]# [root@localhost]#因為短選項設定為必有參數,雖然長選項設定為可有參數,但是當短選項對應到長選項時,依然會發生「程式記憶體區段錯誤 (core dumped)」的問題。
綜合以上Step VIII ~ XIII的實驗結果可得知:
a). 長選項如果有相對應的短選項時,短選項的設定優先權會大於長選項。
b). 例如:當短選項設定為沒有參數 ()時,無論長選項是設定為必有參數 (required_argument)或是可有參數 (optional_argument)時,短選項都不會去抓取長選項的參數。
c). 反之,當短選項設定為必有參數 (:)時,無論長選項是設定為沒有參數 (no_argument)或是可有參數 (optional_argument)而沒帶參數時,都會發生「程式記憶體區段錯誤 (core dumped)」的問題。
Answer: 簡而言之,當長選項和短選項的參數設定發生衝突時,getopt_long()函式並沒有解決這樣的問題;反而是程式設計師們應自行注意,不應讓這樣的衝突發生。
在一開始的範例程式碼最後,還多加了3個函式:pid_t writePID(const char *PATH); pid_t readPID(const char *PATH); 和int killPID(const char *PATH); 這3個函式也是在Linux Programming下常看到的。當我們執行一支常註程式時,通常都會記下自己在系統中的PID (Process ID),所以會有一個writePID()函式;倘若有別支程序需要送一個訊號 (Signal)和這一支程式溝通時,就需要用readPID()函式;當我們的常註程式要結束時,也要記得刪除自己的PID,就用killPID()函式。
相關文章:Linux C getopt_long()
沒有留言:
張貼留言