如何在shell脚本中添加帮助方法?


Answers:


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前导破折号。
Morgan Estes

5
内置功能"$FUNCNAME"不能使用"$0"。此外,请添加local OPTIND OPTARG
glenn jackman

谢谢。FUNCNAME作品。我将所有函数都放在一个文件中,因此非常适合将它们扩展为对其他人有用的东西。
Morgan Estes 2013年

5
@sigur,请确保引用"$usage" 每个使用它的地方。
glenn jackman

1
有什么shift $((OPTIND - 1))
hpaknia '19

45

Shell脚本的第一个参数可以作为变量使用$1,因此最简单的实现是

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

但是阿努巴瓦怎么说。


感谢@MarkBooth,纠正了错字(加上引号引起的改进)
2013年

您应该养成在条件[[... ...]中包装if的习惯,​​以避免对变量进行错误的解析,来源:github.com/bahamas10/bash-style-guide#bashisms
JREAM

2
是的,尽管OP没有指定bash,并且[它是POSIX兼容的版本。
SEB

注意-对于inside function如果您不想在运行函数后终止shell,则应替换exit 0return。(我已在before之前完成过)
照明器

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),那么最简单的解决方案是if带有测试([)。例如:

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

请注意,对于posix兼容性=将同样有效==

为什么要报价$1

$1需要用引号引起来的原因是,如果没有引号,则$1外壳程序将尝试运行if [ == "-h" ]并失败,因为==在期望两个参数时仅给出了一个参数:

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

对于更复杂的用途getoptgetopts

正如其他人建议的 那样 ,如果您有一个以上的简单选项,或者需要您的选项来接受参数,那么您绝对应该使用来增加额外的复杂性。getopts

作为快速参考,我喜欢60秒的getopts教程

您可能还需要考虑使用该getopt程序而不是内置的shell getopts。它允许使用长选项,并非选项参数之后使用选项(例如,foo a b c --verbose而不只是foo -v a b c)。这个Stackoverflow答案说明了如何使用GNU getopt

jeffbyrnes提到原始链接已终止,但值得庆幸的是,回机已将其存档。


谢谢!我已经很开心地使用getopts一年了,但是我也将看看getopt。
tttppp

1
可悲的是,与“ 60 Seconds getopts教程”的链接已死;看来bashcurescancer.com不再是。这是Wayback Machine版本的链接。
jeffbyrnes 2014年


-1

我认为您可以为此使用案例...

case $1 in 
 -h) echo $usage ;; 
  h) echo $usage ;;
help) echo $usage ;;
esac
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.