Dunno về getopt
nhưng getopts
được xây dựng trong có thể được sử dụng để xử lý chỉ tùy chọn dài như thế này:
while getopts :-: o
do case "$o$OPTARG" in
(-longopt1) process ;;
(-longopt2) process ;;
esac; done
Tất nhiên, như vậy, điều đó sẽ không hoạt động nếu các tùy chọn dài được cho là có đối số. Nó có thể được thực hiện, mặc dù, nhưng, như tôi đã học được khi làm việc này. Mặc dù ban đầu tôi đưa nó vào đây nhưng tôi nhận ra rằng đối với các tùy chọn dài, nó không có nhiều tiện ích. Trong trường hợp này, nó chỉ rút ngắn case
(match)
các lĩnh vực của tôi bằng một nhân vật duy nhất, có thể dự đoán được. Bây giờ, những gì tôi biết, là nó rất tuyệt vời cho các tùy chọn ngắn - nó hữu ích nhất khi nó được lặp qua một chuỗi có độ dài không xác định và chọn các byte đơn theo chuỗi tùy chọn của nó. Nhưng khi tùy chọn là đối số, sẽ không có nhiều bạn đang làm với for var do case $var in
sự kết hợp mà nó có thể làm. Nó là tốt hơn, tôi nghĩ, để giữ cho nó đơn giản.
Tôi nghi ngờ điều tương tự cũng đúng getopt
nhưng tôi không biết đủ về điều đó để nói với bất kỳ sự chắc chắn. Đưa ra mảng arg sau đây, tôi sẽ chứng minh trình phân tích cú pháp arg nhỏ của riêng tôi - điều này phụ thuộc chủ yếu vào mối quan hệ đánh giá / phân công mà tôi đã đánh giá cao alias
và $((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
Đó là chuỗi arg tôi sẽ làm việc với. Hiện nay:
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
Điều đó xử lý mảng arg theo một trong hai cách khác nhau tùy thuộc vào việc bạn trao cho nó một hoặc hai bộ đối số được phân tách bằng --
dấu phân cách. Trong cả hai trường hợp, nó áp dụng cho các chuỗi xử lý cho mảng arg.
Nếu bạn gọi nó như:
: $((SHIFT$$=3)); aopts --lopt1 --lopt2 -- "$@"
Đơn hàng đầu tiên của doanh nghiệp sẽ là viết acase()
chức năng của nó giống như:
acase() case "$a" in
(--lopt1) f=lopt1; aset "?$(($f)):";;
(--lopt2) f=lopt2; aset "?$(($f)):";;
(--*) f=ignored; aset "?$(($f)):";;
(*) aset "" "$a";;esac
Và bên cạnh shift 3
. Thay thế lệnh trong acase()
định nghĩa hàm được đánh giá khi shell gọi xây dựng đầu vào của hàm ở đây - tài liệu, nhưng acase()
không bao giờ được gọi hoặc định nghĩa trong vỏ gọi. Tuy nhiên, nó được gọi trong subshell, và do đó, theo cách này, bạn có thể tự động chỉ định các tùy chọn quan tâm trên dòng lệnh.
Nếu bạn trao cho nó một mảng không phân cách, nó chỉ đơn giản là acase()
khớp với tất cả các đối số bắt đầu bằng chuỗi --
.
Hàm thực tế tất cả quá trình xử lý của nó trong lớp con - lặp lại lưu từng giá trị của đối số vào các bí danh được gán với các tên kết hợp. Khi thông qua nó sẽ in ra mọi giá trị mà nó đã lưu alias
- được chỉ định POSIX để in tất cả các giá trị đã lưu được trích dẫn theo cách mà các giá trị của chúng có thể được gửi lại vào trình bao. Vì vậy, khi tôi làm ...
aopts --lopt1 --lopt2 -- "$@"
Đầu ra của nó trông như thế này:
...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'
Khi nó đi qua danh sách arg, nó sẽ kiểm tra khối trường hợp để tìm trận đấu. Nếu nó tìm thấy một trận đấu ở đó, nó sẽ ném một lá cờ - f=optname
. Cho đến khi nó một lần nữa tìm thấy một tùy chọn hợp lệ, nó sẽ thêm từng đối số tiếp theo vào một mảng mà nó xây dựng dựa trên cờ hiện tại. Nếu cùng một tùy chọn được chỉ định nhiều lần hợp chất kết quả và không ghi đè. Bất cứ điều gì không có trong trường hợp - hoặc bất kỳ đối số nào sau các tùy chọn bị bỏ qua - đều được gán cho một mảng bị bỏ qua .
Đầu ra được bảo vệ an toàn cho shell-input tự động bởi shell, và vì vậy:
eval "$(: $((SHIFT$$=3));aopts --lopt1 --lopt2 -- "$@")"
... nên hoàn toàn an toàn. Nếu vì lý do nào đó không an toàn, thì có lẽ bạn nên gửi báo cáo lỗi với người bảo trì hệ vỏ của bạn.
Nó gán hai loại giá trị bí danh cho mỗi trận đấu. Đầu tiên, nó đặt cờ - điều này xảy ra cho dù tùy chọn có trước các đối số không khớp hay không. Vì vậy, bất kỳ sự xuất hiện của --flag
trong danh sách arg sẽ kích hoạt flag=1
. Điều này không hợp chất - --flag --flag --flag
chỉ được flag=1
. Giá trị này không tăng mặc dù - đối với bất kỳ đối số nào có thể theo sau nó. Nó có thể được sử dụng như một khóa chỉ mục. Sau khi làm như eval
trên tôi có thể làm:
printf %s\\n "$lopt1" "$lopt2"
... để có được ...
8
1
Và vì thế:
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
ĐẦU RA
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
Và để tranh luận không phù hợp, tôi sẽ thay thế bỏ qua trong trường trên for ... in
để có được:
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
getopts
, nhưng bạn đang sử dụng/usr/bin/getopt
lệnh.