- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我一直在学习命令行参数解析。关于这个已经有很长的线索了,我不想在这里挑起一个:
Using getopts in bash shell script to get long and short command line options
How do I parse command line arguments in Bash?
使用 getopts,如果你想解析像“--opt value”这样的参数/值对,一种方法是让 getopts 将其视为名为“-”的参数,并将值变为“-opt”。然后我们解析它并通过符号 ${!OPTIND}
获取用户值.我需要了解更多。
在我上面引用的第一个线程中,${!OPTIND}
被用过,有人说“那是什么?”答案是“它是一种间接替代”。阅读间接引用的注释后,尤其是 https://unix.stackexchange.com/questions/41292/variable-substitution-with-an-exclamation-mark-in-bash和 http://mywiki.wooledge.org/BashFAQ/006 ,我一般理解间接寻址,但我不理解${!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[*]}"
最佳答案
不确定这是否有帮助,但这里是仅 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}"
该代码也可从 https://gist.github.com/jlinoff/1876972c0b37259c82367d51c8313171 获得.
关于linux - 说明getopts中的${!OPTIND}。危险?备择方案?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46813395/
编辑:澄清一下,我明白为什么这段代码不起作用,我并不是要修复它,而是想了解如果这段代码可以在没有语义错误的情况下编译会有什么危险。 我发现下面的代码会导致静态语义错误。我知道这是因为 std::lis
我想知道 C# 枚举以及重复值会发生什么。我创建了以下小程序来测试: namespace ConsoleTest { enum TestEnum { FirstElem
正如我在另一个 SO 问题中指出的那样,我遇到了 this article .当我通过 MSVC7.1 编译 boost 1.40 时出现了这个问题,并且弹出了几个 C4251 警告。 现在,在阅读上
我有以下弹出窗口代码(客户端请求)。它使用 eval ,我知道这是危险的。有没有办法重写下面的脚本,使其不使用 (eval)? /* exported popup_default , popup_he
NTFS 文件可以有对象 ID。可以使用 FSCTL_SET_OBJECT_ID 设置这些 ID .然而,msdn article说: Modifying an object identifier c
我一直在学习命令行参数解析。关于这个已经有很长的线索了,我不想在这里挑起一个: Using getopts in bash shell script to get long and short com
这个问题在这里已经有了答案: How to configure ContextMenu buttons for delete and disabled in SwiftUI? (4 个回答) 4 个月
为什么在 linux 的中断处理程序中禁止 printk 或 (I/O)。?在什么情况下中断处理程序中的 I/O 会导致 linux 系统中的死锁? 最佳答案 关于 printk(),它是侵入性的。例
不是 Invoking virtual function and pure-virtual function from a constructor 的重复项: 以前的问题与 C++ 03 相关,而不是
我正在使用 lateinit 属性以避免使用 ?运算符(operator)。我有很多 View 属性是第一次在 getViews() 函数中分配的。如果该功能不存在,我的应用程序将与来自 Kotlin
我最近在使用 fputs 时遇到了问题:当使用 fputs 在文本文件中打印一些字符串时,我碰巧得到了除 A-Z、a-z、0-9 之外的其他字符(不属于字符串的字符) .我绝对确保所有字符串都以空字符
在仅包含字节数组的结构上使用 #pragma pack(1) 是否危险/有风险?例如。这个: #pragma pack(1) struct RpcMessage { uint8_t proto
我是一名优秀的程序员,十分优秀!