2

我正在尝试创建一个 shell 脚本,它有两个强制参数(arg1、arg2),然后是一个可选的 -b 标志以及用户选择使用该标志时需要遵循的参数。

让我解释:

这是一个安装脚本,它利用 GIT 从 Github 存储库中获取应用程序。用户在终端 f.ex. 中键入:

./shellscript.sh new <app_name> # fetches master branch by default

并且脚本从此存储库中获取主分支的一个实例。然而,用户是否应该选择使用可选的 -b 标志,这意味着他/她想要指定要获取的分支,例如开发分支。这意味着用户可以执行以下操作:

./shellscript.sh new <app_name> -b develop # or which ever branch there is available

我也很好奇如何让脚本工作,这样用户在“new”参数和“app_name”参数之前输入 -b flag+branch_name 就无关紧要了。但这也许不是目前最重要的事情。

要知道我到底要构建什么,这里有一个指向我当前脚本的链接,它只接受两个强制参数并且只获取主分支:My Super Cool Artisan Executable Script

PS:我一直在尝试使用 getopts 的许多示例,我在 Stackoverflow 和其他博客上都找到了这些示例,但没有一个可以帮助我完全使其工作。因此,我在这里向你们所有伟大的人寻求帮助。

非常感谢,请务必查看我的Linux Mint / Ubuntu - Post Install Script for only cool people(你们和那些从 Windows/Mac 切换到 Linux 的人)

问候, 维利

4

3 回答 3

6

我通常自己编写以允许短选项和长选项:

function Usage()
{
cat <<-ENDOFMESSAGE

$0 [OPTION] REQ1 REQ2

options:

    -b -branch  branch to use
    -h --help   display this message

ENDOFMESSAGE
    exit 1
}

function Die()
{
    echo "$*"
    exit 1
}

function GetOpts() {
    branch=""
    argv=()
    while [ $# -gt 0 ]
    do
        opt=$1
        shift
        case ${opt} in
            -b|--branch)
                if [ $# -eq 0 -o "${1:0:1}" = "-" ]; then
                    Die "The ${opt} option requires an argument."
                fi
                branch="$1"
                shift
                ;;
            -h|--help)
                Usage;;
            *)
                if [ "${opt:0:1}" = "-" ]; then
                    Die "${opt}: unknown option."
                fi
                argv+=(${opt});;
        esac
    done 
}

GetOpts $*
echo "branch ${branch}"
echo "argv ${argv[@]}"
于 2013-06-10T02:39:11.350 回答
2

Unix 实用程序通常在位置参数之前采用可选参数(“标志”),尽管大多数 GNU 实用程序,包括 C 库函数的 GNU 实现,都getopt将命令行参数打乱,以便可选参数排在第一位。但是,内置的 bashgetopts不会随机播放,这意味着您可以自行决定是否这样做。

getopts总是以编号为变量值的参数开头OPTIND。(每次执行 bash 函数时,OPTIND 都设置为 1,并且它是一个全局变量。因此需要注意相互调用的 bash 函数。)如果您愿意,您可以自己设置 OPTIND,然后下一个调用getopts将从该索引开始。或者,您可以使用shift来转移所有命令行参数。

因此,例如,您可以这样做:

# "shift" version: always shift consumed arguments
local verb="$1" branch=master app_name option
shift
case $verb in
  new)  app_name="$1"
        shift
        while getopts b: option; do
          case $option in
            b) branch=$OPTARG;;
            *) # handle the error;;
          esac
        done
        shift $((OPTIND - 1));;
  *) # handle the error or other subcommands;;
esac
# At this point, there are still arguments if ((OPTIND > 0))

或者:

# non-shift version: use OPTIND to index arguments
local verb="${!OPTIND}" branch=master app_name option
OPTIND=$((OPTIND + 1))
case $verb in
  new)  app_name="${!OPTIND}"
        OPTIND=$((OPTIND + 1))
        while getopts b: option; do
          case $option in
            b) branch=$OPTARG;;
            *) # handle the error;;
          esac
        done;;
  *) # handle the error or other subcommands;;
esac
# At this point, there are still arguments if ((OPTIND > $#))
于 2013-06-10T02:40:13.473 回答
1

稍微简化一点的版本,使用getopts会报错:

#!/usr/bin/bash

help() { echo -e "Usage\n\t$0: new <app_name> [-b <develop>]" >&2;}
die() { [ -n "$1" ] && echo -e "Error: $1\n" >&2; help; [ -z "$1" ]; exit;}

[ $# -lt 2 ] && die "Too few args"
[ $1 != "new" ] && die "Bad first arg ($1)"
app_name=$2
shift 2

unset develop
while getopts "b:" opt; do
  case $opt in
    \?) exit 1;;
    b) develop="$OPTARG";;
  esac
done

echo "app_name: $app_name, develop: $develop"

测试:

$./test new App
app_name: App, develop:
$./test new App -b Dev
app_name: App, develop: Dev

无论如何,我可能会建议使用标准的参数传递方式。而不是new你可以使用-n.

于 2013-06-11T08:30:33.427 回答