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

128

Как проверить, -hпередан ли атрибут в сценарий оболочки? Я хотел бы отображать справочное сообщение при звонке пользователя myscript.sh -h.

tttppp
источник
Соответствующие примеры: stackoverflow.com/questions/14008125/…
Антон Тарасенко

Ответы:

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
-1

я думаю, вы можете использовать для этого случай ...

case $1 in 
 -h) echo $usage ;; 
  h) echo $usage ;;
help) echo $usage ;;
esac
новый пользователь
источник