Как я могу добавить метод справки в сценарий оболочки?


Ответы:


173

вот пример для bash:

usage="$(basename "$0") [-h] [-s n] -- program to calculate the answer to life, the universe and everything

where:
    -h  show this help text
    -s  set the seed value (default: 42)"

seed=42
while getopts ':hs:' option; do
  case "$option" in
    h) echo "$usage"
       exit
       ;;
    s) seed=$OPTARG
       ;;
    :) printf "missing argument for -%s\n" "$OPTARG" >&2
       echo "$usage" >&2
       exit 1
       ;;
   \?) printf "illegal option: -%s\n" "$OPTARG" >&2
       echo "$usage" >&2
       exit 1
       ;;
  esac
done
shift $((OPTIND - 1))

Чтобы использовать это внутри функции:

  • использовать "$FUNCNAME"вместо$(basename "$0")
  • добавить local OPTIND OPTARGперед звонкомgetopts

1
Я пытаюсь сделать это внутри функции, но когда я пытаюсь запустить функцию, я получаю сообщение об ошибке «basename: invalid option - 'b'». Похоже, он пытается передать "-bash" basenameс ведущим тире.
Морган Эстес,

5
внутри функции использовать "$FUNCNAME"нет "$0". Также добавлюlocal OPTIND OPTARG
Гленн Джекман

Спасибо. FUNCNAMEработает. У меня все функции находятся в одном файле, так что это идеально подходит для расширения их во что-то полезное для других.
Морган Эстес,

5
@sigur, не забудьте процитировать "$usage" каждое место, где вы его используете.
Гленн Джекман

1
Для чего shift $((OPTIND - 1))?
hpaknia

45

Первый аргумент сценария оболочки доступен как переменная $1, поэтому простейшей реализацией будет

if [ "$1" == "-h" ]; then
  echo "Usage: `basename $0` [somestuff]"
  exit 0
fi

Но что сказал анубхава.


Спасибо @MarkBooth, опечатка исправлена ​​(плюс улучшение за счет
заключения

Вы должны иметь привычку заключать if в [[...]] для условных
выражений,

2
Да, хотя OP не указывал bash и [является версией, совместимой с POSIX.
сен

Примечание. Для использования внутри function: следует заменить exit 0на, returnесли вы не хотите завершать работу оболочки после запуска функции. (Я делал это раньше 😂)
Illuminator

29

вот часть, которую я использую для запуска сервера VNC

#!/bin/bash
start() {
echo "Starting vnc server with $resolution on Display $display"
#your execute command here mine is below
#vncserver :$display -geometry $resolution
}

stop() {
echo "Killing vncserver on display $display"
#vncserver -kill :$display
}

#########################
# The command line help #
#########################
display_help() {
    echo "Usage: $0 [option...] {start|stop|restart}" >&2
    echo
    echo "   -r, --resolution           run with the given resolution WxH"
    echo "   -d, --display              Set on which display to host on "
    echo
    # echo some stuff here for the -a or --add-options 
    exit 1
}

################################
# Check if parameters options  #
# are given on the commandline #
################################
while :
do
    case "$1" in
      -r | --resolution)
          if [ $# -ne 0 ]; then
            resolution="$2"   # You may want to check validity of $2
          fi
          shift 2
          ;;
      -h | --help)
          display_help  # Call your function
          exit 0
          ;;
      -d | --display)
          display="$2"
           shift 2
           ;;

      -a | --add-options)
          # do something here call function
          # and write it in your help function display_help()
           shift 2
           ;;

      --) # End of all options
          shift
          break
          ;;
      -*)
          echo "Error: Unknown option: $1" >&2
          ## or call function display_help
          exit 1 
          ;;
      *)  # No more options
          break
          ;;
    esac
done

###################### 
# Check if parameter #
# is set too execute #
######################
case "$1" in
  start)
    start # calling function start()
    ;;
  stop)
    stop # calling function stop()
    ;;
  restart)
    stop  # calling function stop()
    start # calling function start()
    ;;
  *)
#    echo "Usage: $0 {start|stop|restart}" >&2
     display_help

     exit 1
     ;;
esac

Немного странно, что я поместил старт-стоп-рестарт в отдельный случай, но он должен работать


если вы дадите пустую опцию -d; не будет бесконечного цикла?
zerobane

Почему вы выходите из 1 во вспомогательной функции?
jeantimex

17

Для быстрого решения с одним вариантом используйте if

Если у вас есть только один вариант для проверки, и он всегда будет первым вариантом ( $1), то самым простым решением является использование iftest ( [). Например:

if [ "$1" == "-h" ] ; then
    echo "Usage: `basename $0` [-h]"
    exit 0
fi

Обратите внимание, что для совместимости с posix =будет работать так же, как ==.

Зачем цитировать $1?

Причина, по которой $1необходимо заключить в кавычки, заключается в том, что, если их нет, $1оболочка попытается запустить if [ == "-h" ]и потерпит неудачу, потому ==что был дан только один аргумент, когда он ожидал два:

$ [ == "-h" ]
bash: [: ==: unary operator expected

Для более сложного использования getoptилиgetopts

Как предложено на других , если у вас есть более чем один вариант простой, или нужна ваша возможность принять аргумент, то вы должны обязательно пойти на дополнительную сложность использования getopts.

В качестве краткого справочника мне понравился 60-секундный учебник по getopts .

Вы также можете рассмотреть getoptпрограмму вместо встроенной оболочки getopts. Он позволяет использовать длинные параметры и параметры после аргументов без параметров (например, foo a b c --verboseа не просто foo -v a b c). Этот ответ Stackoverflow объясняет, как использовать GNU getopt.

Джеффбирнес упомянул, что исходная ссылка умерла, но, к счастью , машина на обратном пути ее заархивировала.


Спасибо! Я с удовольствием использую getopts уже год, но я тоже посмотрю на getopt.
tttppp 01

1
К сожалению, ссылка на 60-секундное руководство по getopts мертва; похоже, что bashcurescancer.com больше нет. Вот ссылка на версию Wayback Machine .
jeffbyrnes


Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.