
getopt
bash命令列中有一個命令。getopt
可以與短選項一起使用(例如getopt -o axby "$@"
),並且可以與短選項和長選項一起使用(例如getopt -o axby -l long-key -- "$@"
),但現在我需要僅有的長選項(即根本不存在短選項),但是該指令getopt -l long-key -- "$@"
無法--long-key
正確解析選項。那我該如何使用getopt
指令僅有的長選項?或者這是不可能的或只是命令的錯誤getopt
?
答案1
getopt
沒有短期選擇就完全沒問題。但你需要告訴它你沒有短期選擇。這是語法上的一個怪癖——來自手冊:
如果在第一部分中沒有找到
-o
或--options
選項,則第二部分的第一個參數將用作短選項字串。
這就是您的測試中發生的情況:getopt -l long-key -- --long-key foo
將其--long-key
視為選項清單-egklnoy
和foo
唯一的參數。使用
getopt -o '' -l long-key -- "$@"
例如
$ getopt -l long-key -o '' -- --long-key foo
--long-key -- 'foo'
$ getopt -l long-key -o '' -- --long-key --not-recognized -n foo
getopt: unrecognized option '--not-recognized'
getopt: invalid option -- 'n'
--long-key -- 'foo'
答案2
不知道,getopt
但getopts
內建函數只能用於處理長選項,如下所示:
while getopts :-: o
do case "$o$OPTARG" in
(-longopt1) process ;;
(-longopt2) process ;;
esac; done
當然,如果長選項應該有參數,那麼這不起作用。不過,這是可以做到的,但是,根據我在這方面的工作所了解到的。雖然我最初將它放在這裡,但我意識到對於長期期權來說它沒有太多用處。在這種情況下,它只是將我的case
(match)
字段縮短了一個可預測的字元。現在,我知道,它對於短選項非常有用 - 當它循環未知長度的字串並根據其選項字串選擇單個位元組時,它最有用。但當選項是for var do case $var in
arg,你用它可以做的組合做的事情並不多。我認為,最好保持簡單。
我懷疑情況也是如此,getopt
但我對此了解不夠,無法肯定地說。給定以下 arg 數組,我將演示我自己的小 arg 解析器 - 這主要取決於我對alias
and的評估/賦值關係$((shell=math))
。
set -- this is ignored by default --lopt1 -s 'some '\''
args' here --ignored and these are ignored \
--alsoignored andthis --lopt2 'and
some "`more' --lopt1 and just a few more
這就是我將要使用的 arg 字串。現在:
aopts() { env - sh -s -- "$@"
} <<OPTCASE 3<<\OPTSCRIPT
acase() case "\$a" in $(fmt='
(%s) f=%s; aset "?$(($f)):";;\n'
for a do case "$a" in (--) break;;
(--*[!_[:alnum:]]*) continue;;
(--*) printf "$fmt" "$a" "${a#--}";;
esac;done;printf "$fmt" '--*' ignored)
(*) aset "" "\$a";;esac
shift "$((SHIFT$$))"; f=ignored; exec <&3
OPTCASE
aset() { alias "$f=$(($f${1:-=$(($f))+}1))"
[ -n "${2+?}" ] && alias "${f}_$(($f))=$2"; }
for a do acase; done; alias
#END
OPTSCRIPT
它以兩種不同方式之一處理 arg 數組,具體取決於您是否向其提供一組或兩組由--
分隔符號分隔的參數。在這兩種情況下,它都適用於 arg 數組的處理序列。
如果你這樣稱呼它:
: $((SHIFT$$=3)); aopts --lopt1 --lopt2 -- "$@"
它的首要任務是將其acase()
函數編寫為如下所示:
acase() case "$a" in
(--lopt1) f=lopt1; aset "?$(($f)):";;
(--lopt2) f=lopt2; aset "?$(($f)):";;
(--*) f=ignored; aset "?$(($f)):";;
(*) aset "" "$a";;esac
並在旁邊shift 3
。acase()
當呼叫 shell 建構函數的輸入 here-documents 時,會計算函數定義中的命令替換,但acase()
絕不會在呼叫 shell 中呼叫或定義。當然,它是在子 shell 中呼叫的,因此您可以在命令列上動態指定感興趣的選項。
如果你給它一個未分隔的數組,它只會填入acase()
以 string 開頭的所有參數的匹配項--
。
函數幾乎在子 shell 中完成所有處理 - 迭代地將每個 arg 的值保存到分配有關聯名稱的別名。當它完成時,它會列印它保存的每個值alias
- 這是 POSIX 指定的列印所有已儲存的值,以這樣的方式引用它們的值,以便它們的值可以重新輸入到 shell。所以當我這樣做時...
aopts --lopt1 --lopt2 -- "$@"
它的輸出如下所示:
...ignored...
lopt1='8'
lopt1_1='-s'
lopt1_2='some '\'' args'
lopt1_3='here'
lopt1_4='and'
lopt1_5='just'
lopt1_6='a'
lopt1_7='few'
lopt1_8='more'
lopt2='1'
lopt2_1='and
some "`more'
當它遍歷 arg 列表時,它會檢查 case 區塊是否匹配。如果它在那裡找到匹配項,它會拋出一個標誌 - f=optname
。在它再次找到有效選項之前,它將把每個後續參數添加到它基於當前標誌構建的數組中。如果多次指定相同選項,結果會復合且不會覆蓋。任何不以防萬一的東西 - 或忽略選項後面的任何參數 - 都被分配給被忽略大批。
輸出是 shell 安全的,由 shell 自動進行 shell 輸入,因此:
eval "$(: $((SHIFT$$=3));aopts --lopt1 --lopt2 -- "$@")"
……應該是絕對安全的。如果因為任何原因不是安全,那麼您應該向 shell 維護人員提交錯誤報告。
它為每個匹配分配兩種別名值。首先,它設定一個標誌 - 無論選項是否位於不匹配的參數之前,都會發生這種情況。因此--flag
arg 清單中的任何出現都會觸發flag=1
。這並不復合 ---flag --flag --flag
只是得到flag=1
。這個值做但遞增 - 對於可能跟隨它的任何參數。它可以用作索引鍵。完成上述操作後eval
我可以這樣做:
printf %s\\n "$lopt1" "$lopt2"
....要得到...
8
1
所以:
for o in lopt1 lopt2
do list= i=0; echo "$o = $(($o))"
while [ "$((i=$i+1))" -le "$(($o))" ]
do list="$list $o $i \"\${${o}_$i}\" "
done; eval "printf '%s[%02d] = %s\n' $list"; done
輸出
lopt1 = 8
lopt1[01] = -s
lopt1[02] = some ' args
lopt1[03] = here
lopt1[04] = and
lopt1[05] = just
lopt1[06] = a
lopt1[07] = few
lopt1[08] = more
lopt2 = 1
lopt2[01] = and
some "`more
對於不匹配的參數我會替換被忽略在上面的for ... in
字段中得到:
ignored = 10
ignored[01] = this
ignored[02] = is
ignored[03] = ignored
ignored[04] = by
ignored[05] = default
ignored[06] = and
ignored[07] = these
ignored[08] = are
ignored[09] = ignored
ignored[10] = andthis