#bash #shell #case #getopt
#bash #оболочка #случай #getopt
Вопрос:
Я использую getopt
(не getops
), чтобы предоставить моему сценарию bash возможность обрабатывать параметры и переключатели (как длинные —option, так и короткие -o формы).
Я хотел бы иметь возможность перехватывать недопустимые параметры и обрабатывать их, обычно повторяя, что пользователь должен попробовать cmd --help
, а затем выйти из скрипта.
Дело в том, что недопустимые параметры перехватываются getopt, который сам выводит сообщение, такое как «getopt: недопустимый параметр — ‘x'»
Вот шаблон, который я использую для настройки параметров getopt:
set -- $(getopt -o $SHORT_OPTIONS -l $LONG_OPTIONS -- "$@")
где как $ LONG_OPTIONS, так и $ SHORT_OPTIONS представляют собой список параметров, разделенных запятыми.
Вот как я обрабатываю обработку параметров:
while [ $# -gt 0 ]
do
case "$1" in
-h|--help)
cat <<END_HELP_OUTPUT
Help
----
Usage: ./cmd.sh
END_HELP_OUTPUT
shift;
exit
;;
--opt1)
FLAG1=true
shift
;;
--opt2)
FLAG2=true
shift
;;
--)
shift
break
;;
*)
echo "Option $1 is not a valid option."
echo "Try './cmd.sh --help for more information."
shift
exit
;;
esac
done
getopt -q
будет подавлять вывод, но моя схема захвата в case
инструкции по-прежнему не выполняет то, что я ожидаю. Вместо этого программа просто выполняется, несмотря на недопустимые аргументы.
Ответ №1:
Такой стиль работает для меня:
params="$(getopt -o d:h -l diff:,help --name "$cmdname" -- "$@")"
if [ $? -ne 0 ]
then
usage
fi
eval set -- "$params"
unset params
while true
do
case $1 in
-d|--diff)
diff_exec=(${2-})
shift 2
;;
-h|--help)
usage
exit
;;
--)
shift
break
;;
*)
usage
;;
esac
done
Комментарии:
1. В каком случае достигается *)?
2. @jarno Если у вас когда-либо возникнет несоответствие между вашим
case
оператором иgetopt
вызовом, оно будет перехвачено там. Это просто защитное программирование.
Ответ №2:
Это не самое надежное решение, но оно разумно; оно основывается на следующем:
- Выводимое сообщение об ошибке
getopt
имеет префикс «getopt: «. - Предполагается, что допустимо пропускать очищенную версию сообщения об
getopt
ошибке, дополненную пользовательской информацией.
Фрагмент кода:
# Invoke getopt; suppress its stderr initially.
args=$(getopt -o $SHORT_OPTIONS -l $LONG_OPTIONS -- "$@" 2>/dev/null)
if [[ $? -ne 0 ]]; then # getopt reported failure
# Rerun the same getopt command so we can capture stderr output *only* this time.
# Inefficient (and a potential maintenance headache, if literals were involved), but this will only execute in case of invalid input.
# Alternatively, redirect the first getopt invocation's stderr output to a temp. file and read it here.
errmsg=$(getopt -o $SHORT_OPTIONS -l $LONG_OPTIONS -- "$@" 2>amp;1 1>amp;-)
# Strip getopt's prefix and augment with custom information.
echo -e "${errmsg#getopt: }nTry './cmd.sh --help for more information." 1>amp;2
exit 1
fi
Комментарии:
1. @TomAuger: Если вы считаете, что «довольно хрупкий» адекватно перефразирует «не самый надежный, но разумный», вы, должно быть, используете несовместимую англоязычную оболочку. Неизменно, попытка надежно извлечь информацию
getopt
, которая не была предназначена для программного отчета, будет сложной. Тем не менее, часть о предположении, что вывод stderr идет первым, действительно шаткая, поэтому я пересмотрел код, чтобы решить эту проблему. Если вы знаете, как преобразовать stdout и stderr в отдельные переменные при выполнении одной команды (не включая явное создание временных файлов), дайте мне знать.
Ответ №3:
Нужно ли вам вообще использовать getopt? Если вы просто используете
while [ $# -gt 0 ]; do
case "$1" in
-d|--diff)
diff_exec=(${2-})
shift
;;
-h|--help)
usage
exit
;;
--)
break
;;
*)
usage
;;
esac
shift
done
Тогда ваш собственный код выполняет проверку.
Ответ №4:
Я обнаружил, что это работает как последний элемент в инструкции getopts case:
*) eval echo «Нераспознанный аргумент $$[OPTIND-1]»; использование; выход ;;
Ответ №5:
Я не уверен, что это может помочь, но getopt(1) использует getopt(3), и, если я правильно помню, getopt(3) подавляет сообщение об ошибке, если первым символом OPTSTRING является двоеточие.
Комментарии:
1. Использование ‘:’ в качестве первого символа в optstring подавляет вывод сообщения. Однако код возврата из getopt(1) по-прежнему отличен от нуля, и нераспознанный параметр не выводится getopt(1).
Ответ №6:
Вот синтаксический анализ командной строки, который я использовал. Это можно было бы улучшить с помощью дополнительной логики синтаксического анализа для обработки отсутствующих параметров и параметров.
Для командной строки: -a AA -b BB -c CC, результат s / b a= AA b= BB c= CC
OPT=( "$@" ) # Parses the command line into words.
for [[ I=0;I<${#OPT[@]};I ]]
do
case "${OPT[$I]}" in
-a) a=${OPT[$I 1]} ;;
-b) b=${OPT[$I 1]} ;;
-c) c=${OPT[$I 1]} ;;
esac
done