Ще одне рішення без getopt [s], POSIX, старий стиль Unix
Подібно до рішення, яке Бруно Броноскі опублікував, це тут одне без використання getopt(s)
.
Основна відмінна риса мого рішення полягає в тому, що воно дозволяє об'єднати параметри разом так, як tar -xzf foo.tar.gz
дорівнюєtar -x -z -f foo.tar.gz
. І так само, як tar
і ps
т.д., провідний дефіс необов'язковий для блоку коротких опцій (але це можна легко змінити). Також підтримуються довгі варіанти (але коли блок починається з одного, тоді потрібні два провідні дефіси).
Код з прикладними параметрами
#!/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
Для прикладу використання див. Приклади далі.
Позиція варіантів з аргументами
Для чого варто, параметри з аргументами не є останніми (потрібні лише довгі варіанти). Тож, наприклад, наприклад, tar
(принаймні, в деяких реалізаціях) f
параметри повинні бути останніми, оскільки наступне ім'я файлу ( tar xzf bar.tar.gz
працює, алеtar xfz bar.tar.gz
не робить), це не так (див. Пізніші приклади).
Кілька варіантів з аргументами
В якості іншого бонусу параметри опції споживаються в порядку опцій за параметрами з необхідними параметрами. Просто подивіться на вихід мого сценарію тут із командним рядком abc X Y Z
(або -abc X Y Z
):
Option AAA activated!
Option BBB with argument 'X' activated!
Option CCC with arguments 'Y' and 'Z' activated!
Довгі варіанти також поєднуються
Також ви можете також мати довгі параметри в блоці опцій, враховуючи те, що вони відбуваються останніми в блоці. Отже, наступні командні рядки є рівнозначними (включаючи порядок, в якому обробляються параметри та його аргументи):
-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
Все це призводить до:
Option CCC with arguments 'Z' and 'Y' activated!
Option BBB with argument 'X' activated!
Option AAA activated!
Doing something...
Не в цьому рішенні
Необов’язкові аргументи
Варіанти з необов'язковими аргументами повинні бути можливі з невеликою роботою, наприклад, дивлячись вперед, чи є блок без дефісу; Потім користувачеві потрібно буде поставити дефіс перед кожним блоком після блоку з параметром, що має необов'язковий параметр. Можливо, це занадто складно для спілкування з користувачем, тому краще просто вимагати провідного дефісу взагалі.
Все ускладнюється за допомогою декількох можливих параметрів. Я б радив не робити параметри, намагаючись бути розумними, визначаючи, чи може аргумент є для нього чи ні (наприклад, опція просто приймає число як необов'язковий аргумент), оскільки це може порушитися в майбутньому.
Я особисто віддаю перевагу додатковим варіантам замість необов'язкових аргументів.
Варіанти аргументів, введені знаком рівності
Так само, як і з необов'язковими аргументами, я не є прихильником цього (BTW, чи є тема для обговорення плюсів / мінусів різних стилів параметрів?), Але якщо ви хочете, це, можливо, ви можете реалізувати його самостійно, як це робиться на http: // mywiki.wooledge.org/BashFAQ/035#Manual_loop із випискою--long-with-arg=?*
справи та видаленням знака рівності (це BTW-сайт, який говорить про те, що з’єднання параметрів можливо з деякими зусиллями, але "залишило [це] як вправу для читача ", що змусило мене прийняти їх під слово, але я почав з нуля).
Інші примітки
POSIX-сумісний, працює навіть на древніх установках BusyBox мені доводилося мати справу з (з , наприклад cut
, head
і НЕ getopts
вистачає).
zparseopts -D -E -M -- d=debug -debug=d
І мають і те,-d
і--debug
в$debug
масивіecho $+debug[1]
поверне 0 або 1, якщо використовується один із них. Посилання: zsh.org/mla/users/2011/msg00350.html