Я пытаюсь создать сценарий оболочки, который принимает различные параметры и getopts
кажется хорошим решением, так как он может обрабатывать переменное упорядочение параметров и аргументов (я думаю!).
Я буду использовать только короткие опции, и каждому короткому варианту потребуется соответствующее значение, например: ./command.sh -a arga -g argg -b argb
но я бы хотел, чтобы параметры вводились в неконкретном порядке, так как большинство людей привыкли работать с командами оболочки ,
Другой момент заключается в том, что я хотел бы сделать свою собственную проверку значений аргумента option, в идеале внутри case
операторов. Причина этого в том, что мое тестирование :)
в моем case
утверждении дало противоречивые результаты (вероятно, из-за отсутствия понимания с моей стороны).
Например:
#!/bin/bash
OPTIND=1 # Reset if getopts used previously
if (($# == 0)); then
echo "Usage"
exit 2
fi
while getopts ":h:u:p:d:" opt; do
case "$opt" in
h)
MYSQL_HOST=$OPTARG
;;
u)
MYSQL_USER=$OPTARG
;;
p)
MYSQL_PASS=$OPTARG
;;
d)
BACKUP_DIR=$OPTARG
;;
\?)
echo "Invalid option: -$OPTARG" >&2
exit 2;;
:)
echo "Option -$OPTARG requires an argument" >&2
exit 2;;
esac
done
shift $((OPTIND-1))
echo "MYSQL_HOST='$MYSQL_HOST' MYSQL_USER='$MYSQL_USER' MYSQL_PASS='$MYSQL_PASS' BACKUP_DIR='$BACKUP_DIR' Additionals: $@"
Не удалось для подобных случаев ... ./command.sh -d -h
Когда я хочу, чтобы он пометил -d как требующий аргумента, но я получаю значение, -d=-h
которое не то, что мне нужно.
Поэтому я подумал, что было бы проще выполнить мою собственную проверку в операторах case, чтобы убедиться, что каждая опция установлена и установлена только один раз.
Я пытаюсь сделать следующее, но мои if [ ! "$MYSQL_HOST" ]; then
блоки не срабатывают.
OPTIND=1 # Reset if getopts used previously
if (($# == 0)); then
echo "Usage"
exit 2
fi
while getopts ":h:u:p:d:" opt; do
case "$opt" in
h)
MYSQL_HOST=$OPTARG
if [ ! "$MYSQL_HOST" ]; then
echo "host not set"
exit 2
fi
;;
u)
MYSQL_USER=$OPTARG
if [ ! "$MYSQL_USER" ]; then
echo "username not set"
exit 2
fi
;;
p)
MYSQL_PASS=$OPTARG
if [ ! "$MYSQL_PASS" ]; then
echo "password not set"
exit 2
fi
;;
d)
BACKUP_DIR=$OPTARG
if [ ! "$BACKUP_DIR" ]; then
echo "backup dir not set"
exit 2
fi
;;
\?)
echo "Invalid option: -$OPTARG" >&2
exit 2;;
#:)
# echo "Option -$opt requires an argument" >&2
# exit 2;;
esac
done
shift $((OPTIND-1))
echo "MYSQL_HOST='$MYSQL_HOST' MYSQL_USER='$MYSQL_USER' MYSQL_PASS='$MYSQL_PASS' BACKUP_DIR='$BACKUP_DIR' Additionals: $@"
Есть ли причина, по которой я не могу проверить, OPTARG
имеет ли an нулевую длину изнутри getopts ... while ... case
?
Какой лучший способ запустить мою собственную проверку аргументов getopts
в случае, когда я не хочу полагаться на :)
. Выполнить проверку моего аргумента за пределами while ... case ... esac
?
Тогда я мог бы получить значения аргументов и -d
т. Д. И не уловить пропущенную опцию.
while
цикл, работающий над опциями. Это метод, с которым я столкнулся, хотя он многословен по сравнению с другими, очень ясно, что происходит в сценарии. И ремонтопригодность других важна в этом случае.Поскольку другие ответы на самом деле не так много отвечают на ваш вопрос: это ожидаемое поведение, основанное на интерпретации POSIX :
Это все , что в настоящее время говорится, и поставить (не так долго) историю короткий:
getopts
не волшебно знать , что вполне веский аргумент он видит для опции , которые вам потребуется , чтобы иметь аргумент на самом деле не вариант аргумент , но другой вариант , Ничто не мешает вам иметь-h
в качестве действительного аргумента-d
параметр, который на практике означает, что онgetopts
выдаст ошибку только в том случае, если ваш параметр, требующий аргумента, будет последним в командной строке, например:test.sh
:Пример:
Причина, по которой ваш второй подход не работает, заключается в том, что синтаксический анализ
getopts
остается тем же, поэтому, как только вы попали в цикл, «повреждение» уже сделано.Если вы абсолютно хотите запретить это, то, как указал Benubird, вам придется самостоятельно проверить аргументы опций и выдать ошибку, если они равны действительной опции.
источник
Я бы продолжил использовать,
getopts
но сделаю дополнительную проверку после: (не проверено)требуется bash версии 4
источник
Встроенный в Gnu необолочечный getopt делает для вас меньше работы, но обеспечивает большую гибкость, позволяя вам определять, что происходит после обнаружения флага, в том числе самостоятельно отключая аргументы.
Я нашел статью, сравнивающую getopts и getopt, которая, вероятно, будет полезна, так как руководство довольно сложно понять (по крайней мере, перед кофе).
источник
Во-первых, вы должны использовать
if [ -z "$MYSQL_USER" ]
.Во-вторых, нет необходимости в назначении -
if [ -z "$OPTARG" ]
будет работать нормально.В-третьих, я подозреваю, что вы на самом деле хотите
if [ ${#OPTARG} = 0 ]
. $ {# x} - это элемент bash, возвращающий длину строки $ x (подробнее здесь ).В-четвертых, если вы делаете свою собственную проверку, я бы порекомендовал getopt вместо getopts, поскольку он обеспечивает гораздо большую гибкость.
Наконец, чтобы ответить на ваш первый вопрос, вы можете определить, когда флаг передается в качестве аргумента, поместив список флагов вверху, например так:
И затем наличие опции в опции, где вы хотите проверить, является ли предоставленный аргумент опцией, что-то вроде этого:
Не идеальный ответ, но это работает! Ваша проблема в том, что «-h» является совершенно допустимым аргументом, и вы не даете оболочке понять, что она ищет только те параметры, которые также не являются допустимыми флагами.
источник