比如,我有一个脚本,用这行代码调用:

./myscript -vfd ./foo/bar/someFile -o /fizz/someOtherFile

或者这个:

./myscript -v -f -d -o /fizz/someOtherFile ./foo/bar/someFile 

什么是公认的解析方式,以便在每种情况下(或两者的某种组合)$v、$f和$d都将设置为true,而$outFile将等于/fiz/someOtherFile?


当前回答

使用bash模块中的模块“参数”

例子:

#!/bin/bash
. import.sh log arguments

NAME="world"

parse_arguments "-n|--name)NAME;S" -- "$@" || {
  error "Cannot parse command line."
  exit 1
}

info "Hello, $NAME!"

其他回答

我使用它从末尾迭代key=>值。循环后捕获第一个可选参数。

用法为/script.sh可选的第一个参数-key value-key2 value2

#!/bin/sh

a=$(($#-1))
b=$(($#))
while [ $a -gt 0 ]; do
    eval 'key="$'$a'"; value="$'$b'"'
    echo "$key => $value"
    b=$(($b-2))
    a=$(($a-2))
done
unset a b key value

[ $(($#%2)) -ne 0 ] && echo "first_arg = $1"

当然,你可以从左到右做一些改变。

此代码段显示key=>值对和第一个参数(如果存在)。

#!/bin/sh

a=$((1+$#%2))
b=$((1+$a))

[ $(($#%2)) -ne 0 ] && echo "first_arg = $1"

while [ $a -lt $# ]; do
    eval 'key="$'$a'"; value="$'$b'"'
    echo "$key => $value"
    b=$(($b+2))
    a=$(($a+2))
done

unset a b key value

测试了100000个参数,速度很快。

您还可以从左到右迭代key=>value和第一个可选arg,而不使用eval:

#!/bin/sh

a=$(($#%2))
b=0

[ $a -eq 1 ] && echo "first_arg = $1"

for value; do
    if [ $b -gt $a -a $(($b%2)) -ne $a ]; then
        echo "$key => $value"
    fi
    key="$value"
    b=$((1+$b))
done

unset a b key value

这里有一个getopts,它用最少的代码实现解析,并允许您在一种情况下使用eval和substring定义要提取的内容。

基本上eval“local key='val'”

function myrsync() {

        local backup=("${@}") args=(); while [[ $# -gt 0 ]]; do k="$1";
                case "$k" in
                    ---sourceuser|---sourceurl|---targetuser|---targeturl|---file|---exclude|---include)
                        eval "local ${k:3}='${2}'"; shift; shift    # Past two arguments
                    ;;
                    *)  # Unknown option  
                        args+=("$1"); shift;                        # Past argument only
                    ;;                                              
                esac                                                
        done; set -- "${backup[@]}"                                 # Restore $@


        echo "${sourceurl}"
}

在这里,将变量声明为局部变量,而不是全局变量。

调用为:

myrsync ---sourceurl http://abc.def.g ---sourceuser myuser ... 

${k:3}基本上是一个从键中删除第一个---的子字符串。

这也可能很有用:您可以设置一个值,如果有人提供输入,则使用该值覆盖默认值。

myscript.sh-f/serverlist.txt或只是/myscript.sh(它采用默认值)

    #!/bin/bash
    # --- set the value, if there is inputs, override the defaults.

    HOME_FOLDER="${HOME}/owned_id_checker"
    SERVER_FILE_LIST="${HOME_FOLDER}/server_list.txt"

    while [[ $# > 1 ]]
    do
    key="$1"
    shift
    
    case $key in
        -i|--inputlist)
        SERVER_FILE_LIST="$1"
        shift
        ;;
    esac
    done

    
    echo "SERVER LIST   = ${SERVER_FILE_LIST}"

getopts非常有用,如果您首先安装了它,然后您打算在同一平台上运行它。例如,OSX和Linux在这方面的表现不同。

这里有一个(非getopts)解决方案,它支持等于、非等于和布尔标志。例如,您可以通过以下方式运行脚本:

./script --arg1=value1 --arg2 value2 --shouldClean

# parse the arguments.
COUNTER=0
ARGS=("$@")
while [ $COUNTER -lt $# ]
do
    arg=${ARGS[$COUNTER]}
    let COUNTER=COUNTER+1
    nextArg=${ARGS[$COUNTER]}

    if [[ $skipNext -eq 1 ]]; then
        echo "Skipping"
        skipNext=0
        continue
    fi

    argKey=""
    argVal=""
    if [[ "$arg" =~ ^\- ]]; then
        # if the format is: -key=value
        if [[ "$arg" =~ \= ]]; then
            argVal=$(echo "$arg" | cut -d'=' -f2)
            argKey=$(echo "$arg" | cut -d'=' -f1)
            skipNext=0

        # if the format is: -key value
        elif [[ ! "$nextArg" =~ ^\- ]]; then
            argKey="$arg"
            argVal="$nextArg"
            skipNext=1

        # if the format is: -key (a boolean flag)
        elif [[ "$nextArg" =~ ^\- ]] || [[ -z "$nextArg" ]]; then
            argKey="$arg"
            argVal=""
            skipNext=0
        fi
    # if the format has not flag, just a value.
    else
        argKey=""
        argVal="$arg"
        skipNext=0
    fi

    case "$argKey" in 
        --source-scmurl)
            SOURCE_URL="$argVal"
        ;;
        --dest-scmurl)
            DEST_URL="$argVal"
        ;;
        --version-num)
            VERSION_NUM="$argVal"
        ;;
        -c|--clean)
            CLEAN_BEFORE_START="1"
        ;;
        -h|--help|-help|--h)
            showUsage
            exit
        ;;
    esac
done

使用bash模块中的模块“参数”

例子:

#!/bin/bash
. import.sh log arguments

NAME="world"

parse_arguments "-n|--name)NAME;S" -- "$@" || {
  error "Cannot parse command line."
  exit 1
}

info "Hello, $NAME!"