Getopt [s], POSIX, eski Unix stili olmayan başka bir çözüm
Bruno Bronosky bu çözüm gönderdi benzer bir kullanımı olmadangetopt(s)
.
Çözümümün ana ayırt edici özelliği, tıpkı tar -xzf foo.tar.gz
eşit olduğu gibi birlikte birleştirilmiş seçeneklere sahip olmasına izin vermesidir tar -x -z -f foo.tar.gz
. Ve tıpkı içindeki gibi tar
,ps
vs.'de kısa çizgi bir kısa seçenek bloğu için isteğe bağlıdır (ancak bu kolayca değiştirilebilir). Uzun seçenekler de desteklenir (ancak bir blok bir tane ile başladığında iki önde gelen tire gereklidir).
Örnek seçeneklerle kodlama
#!/bin/sh
echo
echo "POSIX-compliant getopt(s)-free old-style-supporting option parser from phk@[se.unix]"
echo
print_usage() {
echo "Usage:
$0 {a|b|c} [ARG...]
Options:
--aaa-0-args
-a
Option without arguments.
--bbb-1-args ARG
-b ARG
Option with one argument.
--ccc-2-args ARG1 ARG2
-c ARG1 ARG2
Option with two arguments.
" >&2
}
if [ $# -le 0 ]; then
print_usage
exit 1
fi
opt=
while :; do
if [ $# -le 0 ]; then
# no parameters remaining -> end option parsing
break
elif [ ! "$opt" ]; then
# we are at the beginning of a fresh block
# remove optional leading hyphen and strip trailing whitespaces
opt=$(echo "$1" | sed 's/^-\?\([a-zA-Z0-9\?-]*\)/\1/')
fi
# get the first character -> check whether long option
first_chr=$(echo "$opt" | awk '{print substr($1, 1, 1)}')
[ "$first_chr" = - ] && long_option=T || long_option=F
# note to write the options here with a leading hyphen less
# also do not forget to end short options with a star
case $opt in
-)
# end of options
shift
break
;;
a*|-aaa-0-args)
echo "Option AAA activated!"
;;
b*|-bbb-1-args)
if [ "$2" ]; then
echo "Option BBB with argument '$2' activated!"
shift
else
echo "BBB parameters incomplete!" >&2
print_usage
exit 1
fi
;;
c*|-ccc-2-args)
if [ "$2" ] && [ "$3" ]; then
echo "Option CCC with arguments '$2' and '$3' activated!"
shift 2
else
echo "CCC parameters incomplete!" >&2
print_usage
exit 1
fi
;;
h*|\?*|-help)
print_usage
exit 0
;;
*)
if [ "$long_option" = T ]; then
opt=$(echo "$opt" | awk '{print substr($1, 2)}')
else
opt=$first_chr
fi
printf 'Error: Unknown option: "%s"\n' "$opt" >&2
print_usage
exit 1
;;
esac
if [ "$long_option" = T ]; then
# if we had a long option then we are going to get a new block next
shift
opt=
else
# if we had a short option then just move to the next character
opt=$(echo "$opt" | awk '{print substr($1, 2)}')
# if block is now empty then shift to the next one
[ "$opt" ] || shift
fi
done
echo "Doing something..."
exit 0
Örnek kullanım için lütfen aşağıdaki örneklere bakın.
Bağımsız değişkenli seçeneklerin konumu
Orada değer ne argümanlar ile seçenekler son değildir (sadece uzun seçenekler olması gerekir). Bu nedenle, örneğin tar
(en azından bazı uygulamalarda) f
seçeneklerin son olması gerekir, çünkü dosya adı aşağıdaki gibidir ( tar xzf bar.tar.gz
çalışır, ancak tar xfz bar.tar.gz
çalışmaz) bu durum böyle değildir (sonraki örneklere bakın).
Bağımsız değişkenli çoklu seçenekler
Başka bir bonus olarak opsiyon parametreleri, gerekli seçeneklere sahip parametreler tarafından seçenekler sırasına göre tüketilir. Komut satırı abc X Y Z
(veya -abc X Y Z
) ile betiğimin çıktısına bakın :
Option AAA activated!
Option BBB with argument 'X' activated!
Option CCC with arguments 'Y' and 'Z' activated!
Uzun seçenekler de birleştirildi
Ayrıca, blokta en son meydana geldikleri göz önüne alındığında, seçenek bloğunda uzun seçeneklere sahip olabilirsiniz. Dolayısıyla, aşağıdaki komut satırlarının tümü eşdeğerdir (seçeneklerin ve bağımsız değişkenlerinin işlenme sırası dahil):
-cba Z Y X
cba Z Y X
-cb-aaa-0-args Z Y X
-c-bbb-1-args Z Y X -a
--ccc-2-args Z Y -ba X
c Z Y b X a
-c Z Y -b X -a
--ccc-2-args Z Y --bbb-1-args X --aaa-0-args
Bunların hepsi şunlara yol açar:
Option CCC with arguments 'Z' and 'Y' activated!
Option BBB with argument 'X' activated!
Option AAA activated!
Doing something...
Bu çözümde değil
İsteğe bağlı argümanlar
İsteğe bağlı argümanlara sahip seçenekler biraz çalışma ile mümkün olmalıdır, örneğin tire işareti olmayan bir blok olup olmadığını ileriye bakarak; daha sonra kullanıcının, isteğe bağlı bir parametresi olan bir parametreyle bir bloğu izleyen her bloğun önüne bir tire işareti koyması gerekir. Belki de bu, kullanıcıyla iletişim kurmak için çok karmaşık olduğundan, bu durumda önde gelen bir kısa çizgi gerektirir.
Olası çoklu parametrelerle işler daha da karmaşıklaşıyor. Ben bir argüman bunun için olup olmadığını belirleyerek akıllı olmaya çalışırken seçenekleri yapmaya karşı öneriyoruz (örneğin bir seçenek ile sadece isteğe bağlı bir argüman olarak bir sayı alır) çünkü bu gelecekte kırılabilir.
Ben şahsen isteğe bağlı argümanlar yerine ek seçenekleri tercih ediyorum.
Eşittir işaretiyle sunulan seçenek bağımsız değişkenleri
Tıpkı isteğe bağlı argümanlarda olduğu gibi bunun hayranı değilim (BTW, farklı parametre stillerinin artılarını / eksilerini tartışmak için bir konu var mı?) Ama bunu isterseniz, muhtemelen http: // mywiki.wooledge.org/BashFAQ/035#Manual_loop ile bir --long-with-arg=?*
case deyimi ve daha sonra eşittir işaretini sıyırma (bu, BTW'nin parametre birleştirmesinin biraz çaba ile mümkün olduğunu söyleyen site ama okuyucu için bir egzersiz olarak "bıraktı" "bu da onları sözlerine götürdü ama sıfırdan başladım).
Diğer notlar
POSIX uyumlu, (örneğin hatta ben uğraşmak zorunda antik Busybox kurulumları çalışır cut
, head
ve getopts
eksik).
zparseopts -D -E -M -- d=debug -debug=d
hem-d
ve hem--debug
de$debug
dizideecho $+debug[1]
0 veya 1 değerini döndürür. Referans: zsh.org/mla/users/2011/msg00350.html