Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Linux 在getopts中解释${!OPTIND}。危险?选择?_Linux_Bash_Shell_Getopts - Fatal编程技术网

Linux 在getopts中解释${!OPTIND}。危险?选择?

Linux 在getopts中解释${!OPTIND}。危险?选择?,linux,bash,shell,getopts,Linux,Bash,Shell,Getopts,我一直在学习命令行参数解析。关于这一点已经有很多线索了,我不想在这里挑起一条: 使用getopts,如果您想解析像“-opt value”这样的参数/值对,一种方法是让getopts将其视为名为“-”的参数,然后值变为“-opt”。然后我们解析它,并通过符号${!OPTIND}获取用户值。我需要更多地了解它 在我上面引用的第一个线程中,使用了${!OPTIND},有人说“那是什么?”回答是“这是一个间接替换”。在阅读了关于间接引用的注释之后,尤其是和,我通常理解间接引用,但我不理解作为例子的

我一直在学习命令行参数解析。关于这一点已经有很多线索了,我不想在这里挑起一条:

使用getopts,如果您想解析像“-opt value”这样的参数/值对,一种方法是让getopts将其视为名为“-”的参数,然后值变为“-opt”。然后我们解析它,并通过符号
${!OPTIND}
获取用户值。我需要更多地了解它

在我上面引用的第一个线程中,使用了
${!OPTIND}
,有人说“那是什么?”回答是“这是一个间接替换”。在阅读了关于间接引用的注释之后,尤其是和,我通常理解间接引用,但我不理解作为例子的
${!OPTIND}

$OPTIND
的值是一个整数,是下一个命令行参数的索引。它不是另一个数组中的值

在上面的BashFAQ/006链接中,有关于间接寻址的警告和不使用间接寻址的一般建议。也许这没什么大不了的,但我想尽量避免危险

我们能避免间接吗?似乎我应该能够使用
${OPTIND}
作为整数,从
$@
$@[$OPTIND]}
中获取一个值

如果您想要示例,这里有一个我称为“cli-6.sh”的脚本,它将接收不带等号的长格式参数。像这样跑:

$ ./cli-6.sh -v --fred good --barney bad --wilma happy
省去-v以减少冗长

$ ./cli-6.sh --fred good --barney bad --wilma happy

After Parsing values, ordinary getopts

VERBOSE  0
Arrays of opts and values
optary:  fred barney wilma
valary:  good bad happy
希望这也适用于您:)我没有使用关联数组来保存值,因为我希望这最终能在其他shell中工作

#/usr/bin/env bash

die() {
    printf '%s\n' "$1" >&2
    exit 1
}


printparse(){
    if [ ${VERBOSE} -gt 0 ]; then
        printf 'Parse: %s%s%s\n' "$1" "$2" "$3" >&2;
    fi
}

showme(){
    if [ ${VERBOSE} -gt 0 ]; then
        printf 'VERBOSE: %s\n' "$1" >&2;
    fi
}


VERBOSE=0

## index for imported values in optary and valary arrays
idx=0
## Need v first so VERBOSE is set early
optspec=":vh-:"
while getopts "$optspec" OPTCHAR; do
    case "${OPTCHAR}" in
        -)
            showme "OPTARG:  ${OPTARG[*]}"
            showme "OPTIND:  ${OPTIND[*]}"
            showme "OPTCHAR: ${OPTCHAR}"
            showme "There is no equal sign in ${OPTARG}"
            opt=${OPTARG}
            val="${!OPTIND}"; OPTIND=$(( $OPTIND + 1 ))
            printparse "--${OPTARG}" " " "\"${val}\""
            if [[ "$val" == -* ]]; then
                die "ERROR: $opt value must be supplied"
            fi
            optary[${idx}]=${opt}
            valary[${idx}]=${val}
            idx=$(($idx + 1))
            ;;
        h)
            echo "usage: $0 [-v] [--anyOptYouQant[=]<valueIsRequired>] [--another[=]<value>]" >&2
            exit 2
            ;;
        v)
            ## if -v flag is present, it means TRUE
             VERBOSE=1
             ;;
        *)
             if [ "$OPTERR" != 1 ] || [ "${optspec:0:1}" = ":" ]; then
                 die "Undefined argument: '-${OPTARG}'"
             fi
             ;;
    esac
done

echo "After Parsing values, ordinary getopts"
echo "VERBOSE  $VERBOSE" 

echo 'Arrays of opts and values'
echo "optary:  ${optary[*]}"
echo "valary:  ${valary[*]}"
#/usr/bin/env bash
死(){
printf'%s\n'$1'>&2
出口1
}
printparse(){
如果[${VERBOSE}-gt 0];则
printf'解析:%s%s%s\n'$1'$2'$3'>&2;
fi
}
showme(){
如果[${VERBOSE}-gt 0];则
printf'VERBOSE:%s\n'$1>&2;
fi
}
详细=0
##optary和valary数组中导入值的索引
idx=0
##首先需要v,以便尽早设置详细信息
optspec=“:vh-:”
而getopts“$optspec”OPTCHAR;做
中的案例“${OPTCHAR}”
-)
showme“OPTARG:${OPTARG[*]}”
显示“OPTIND:${OPTIND[*]}”
showme“OPTCHAR:${OPTCHAR}”
showme“在${OPTARG}中没有等号”
opt=${OPTARG}
val=“${!OPTIND}”;OPTIND=$($OPTIND+1))
printparse“-${OPTARG}”“\”${val}”
如果[[“$val”==-*];然后
die“错误:$opt值必须提供”
fi
光学[${idx}]=${opt}
valary[${idx}]=${val}
idx=$($idx+1))
;;
h)
echo“用法:$0[-v][--anyOptYouQant[=]][--other[=]]]”>&2
出口2
;;
(五)
##如果存在-v标志,则表示为真
详细=1
;;
*)
如果[“$OPTERR”!=1]|[“${optspec:0:1}”=”:“];然后
die“未定义参数:'-${OPTARG}'”
fi
;;
以撒
完成
echo“解析值后,普通getopts”
回显“VERBOSE$VERBOSE”
回显“选项和值数组”
echo“optary:${optary[*]}”
echo“valary:${valary[*]}”

不确定这是否有帮助,但这是一个仅限bash版本的CLI选项解析器,它不使用getopts,但接受短参数和长参数。它还处理一组短格式参数。这在不支持最新版本的getopts的系统上应该很有用

#!/bin/bash
#
# Copyright (c) 2017 by Joe Linoff
# MIT Open Source License.
#
# This script shows how to implement an argument parser with
# 4 options. Two of the options are simply flags, one of
# of them has a single argument and the other has 2 arguments.
#
# It is meant to show bash can support reasonably complex
# argument parsing idioms that will make shell scripts
# more user friendly without using getopts. It is useful
# for cases where getopts is not available.
#
# The options demonstrated are:
#
#    1. -h or --help
#    2. -v or --verbose
#    3. -f ARG or --file ARG or --file=ARG
#    4. -c ARG1 ARG2 or --compare ARG1 ARG2
#
# The options parsing allows the following specifications.
#
#    1. -h
#    2. --help
#    3. -v
#    4. --verbose
#    5. -vv
#    6. -f ARG1
#    7. --file ARG1
#    8. --file=ARG1
#    9. -c ARG1 ARG2
#   10. --compare ARG1 ARG2
#
# This example does not show how to implement best match which would
# mean accepting an option like "--com" (because it is the best unique
# match to --compare). That could be added but i am not convinced
# that it is worth the overhead.
#
# The options parser is global in this example because it is setting
# global (script wide) variables.

# ========================================================================
# Functions
# ========================================================================
# Simple error function that prints the line number of the caller and
# highlights the message in red.
function _err() {
    echo -e "\033[31;1mERROR:\033[0;31m:${BASH_LINENO[0]} $*\033[0m"
    exit 1
}

# ========================================================================
# Main
# ========================================================================
CARGS=()
FILE=''
HELP=0
VERBOSE=0

# The OPT_CACHE is to cache short form options.
OPT_CACHE=()
while (( $# )) || (( ${#OPT_CACHE[@]} )) ; do
    if (( ${#OPT_CACHE[@]} > 0 )) ; then
        OPT="${OPT_CACHE[0]}"
        if (( ${#OPT_CACHE[@]} > 1 )) ; then
            OPT_CACHE=(${OPT_CACHE[@]:1})
        else
            OPT_CACHE=()
        fi
    else
        OPT="$1"
        shift
    fi
    case "$OPT" in
        # Handle the case of multiple short arguments in a single
        # string:
        #  -abc ==> -a -b -c
        -[!-][a-zA-Z0-9\-_]*)
            for (( i=1; i<${#OPT}; i++ )) ; do
                # Note that the leading dash is added here.
                CHAR=${OPT:$i:1}
                OPT_CACHE+=("-$CHAR")
            done
            ;;
        -h|--help)
            (( HELP++ ))
            ;;
        -v|--verbose)
            # Increase the verbosity.
            # Can accept: -v -v OR -vv.
            (( VERBOSE++ ))
            ;;
        -f|--file|--file=*)
            # Can be specified multiple times but we only accept the
            # last one.
            # Can accept: --file foo and --file=foo
            if [ -z "${OPT##*=*}" ] ; then
                FILE="${OPT#*=}"
            else
                FILE="$1"
                shift
            fi
            [[ -z "$FILE" ]] && _err "Missing argument for '$OPT'."
            ;;
        -c|--compare)
            # Can be specified multiple times but we only accept the
            # last one.
            # Can accept:
            #   --compare ARG1 ARG2
            # Cannot accept:
            #   --compare=*
            # The reason for not accepting the '=' sign is to reduce
            # complexity because of the ambiguity of separators. If
            # you decide that you will always use a comma as the
            # separator, that is fine until one of the arguments
            # contains a comma.
            CARG1="$1"
            CARG2="$2"
            shift 2
            [[ -z "$CARG1" ]] &&  _err "Missing both arguments for '$OPT'."
            [[ -z "$CARG2" ]] &&  _err "Missing second argument for '$OPT'."
            CARGS=()
            CARGS+=("$CARG1")
            CARGS+=("$CARG2")
            ;;
        -*)
            _err "Unrecognized option '$OPT'."
            ;;
        *)
            _err "Unrecognized argument '$OPT'."
            ;;
    esac
done

echo "COMPARE : ${CARGS[@]}"
echo "FILE    : ${FILE}"
echo "HELP    : ${HELP}"
echo "VERBOSE : ${VERBOSE}"
#/bin/bash
#
#Joe Linoff版权所有(c)2017
#麻省理工开放源码许可证。
#
#此脚本演示如何使用实现参数解析器
#4种选择。其中两个选项是简单的标志,其中一个是
#其中一个有一个参数,另一个有两个参数。
#
#这意味着bash可以支持相当复杂的
#将生成shell脚本的参数解析习惯用法
#无需使用getopts,更加用户友好。这是有用的
#对于getopts不可用的情况。
#
#演示的选项包括:
#
#    1. -h或者——救命
#    2. -v或--verbose
#    3. -f ARG或--file ARG或--file=ARG
#    4. -c ARG1 ARG2或--比较ARG1 ARG2
#
#选项解析允许以下规范。
#
#    1. -H
#    2. --帮助
#    3. -v
#    4. --冗长的
#    5. -vv
#    6. -f ARG1
#    7. --文件ARG1
#    8. --文件=ARG1
#    9. -c ARG1 ARG2
#   10. --比较ARG1 ARG2
#
#此示例未显示如何实现最佳匹配,这将
#意味着接受像“-com”这样的选项(因为它是最好的唯一选项)
#匹配到——比较)。这是可以补充的,但我不相信
#这是值得的开销。
#
#在本例中,选项解析器是全局的,因为它正在设置
#全局(脚本范围)变量。
# ========================================================================
#功能
# ========================================================================
#简单的错误函数,用于打印调用方的行号和
#以红色突出显示消息。
函数_err(){
echo-e“\033[31;1mERROR:\033[0;31m:${BASH_LINENO[0]}$*\033[0m”
出口1
}
# ========================================================================
#主要
# ========================================================================
CARGS=()
文件=“”
帮助=0
详细=0
#OPT_缓存用于缓存短格式选项。
OPT_CACHE=()
而($)| |(${OPT|u CACHE[@]})呢
如果(${OPT#u CACHE[@]}>0),那么
OPT=“${OPT_缓存[0]}”
如果(${OPT#u CACHE[@]}>1),那么
OPT_CACHE=(${OPT_CACHE[@]:1})
其他的
OPT_CACHE=()
fi
其他的
OPT=“$1”
转移
fi
案例“$OPT”加入
#在单个文件中处理多个短参数的情况
#字符串:
#-abc==>-a-b-c
-[!-][a-zA-Z0-9\-\\\\\\\*)

对于((i=1;i因为它是一个整数,所以它将您引导到一个位置参数,$1,$2,…使用它似乎是一种非常反常的攻击