(很明显,这个问题主要涉及如何将信息应用于getopts
以及如何将shift
应用于手动定义的数组。
我正在编写一个程序来启动一些Bash函数,这些函数以通常的getopts
方式解析函数的参数,而也解析意外的参数(通过多次循环getopts
处理)。
在下面的代码中可以看到一个小函数process_arguments()
,它基本上包含getopts
处理和作用于位置参数的结束shift
操作。因为参数解析的整个过程是针对函数而不是脚本,所以我想将函数process_arguments
中包含的处理移动到主while
循环中。剧本。这涉及修改函数中过程的输入和输出信息。
getopts
处理的输入信息可以传递到数组getopts
中的args
:
getopts optstring name [args]
但是,我不确定如何更改程序的输出。目前,它会移动位置参数,然后打印位置参数(echo "${@}"
)。
所以,问题......
getopts
args
是否以正确的方式将信息传递给程序?shift
应用于传递给getopts
的参数,然后如何将这些已移位的参数输出到脚本处理的其余部分?感谢您的帮助。我欢迎任何其他指导。总体目标是删除函数process_arguments()
并将其功能合并到主``while```循环中。
#!/bin/bash
################################################################################
#
# This is a test of command line parameter parsing that is explicitly non-POSIX.
# This approach handles
# - options (for getopts)
# - arguments of options (for getopts)
# - positional arguments (for getopts) and
# - non-option arguments (command line parameters not expected by getopts).
# All non-option arguments are placed in the string non_option_parameters. The
# silent error reporting mode of getopts is required. Following command line
# parameter parsing, input information can be accepted based on internal
# priority assumptions.
#
# example usage:
# ./script.sh
# non-option parameters:
# ./script.sh -a Dirac
# -a triggered with parameter Dirac
# non-option parameters:
# ./script.sh -a Dirac -b
# -a triggered with parameter Dirac
# -b triggered
# non-option parameters:
# ./script.sh -a Dirac Feynman -b
# -a triggered with parameter Dirac
# -b triggered
# non-option parameters: Feynman
# ./script.sh -a Dirac Feynman Born -b
# -a triggered with parameter Dirac
# -b triggered
# non-option parameters: Feynman Born
# ./script.sh -a Dirac Feynman Born Born -b
# -a triggered with parameter Dirac
# -b triggered
# non-option parameters: Feynman Born
# ./script.sh -a Dirac Feynman Born Born -b
# -a triggered with parameter Dirac
# -b triggered
# non-option parameters: Feynman Born Born
#
################################################################################
process_arguments(){
OPTIND=1
while getopts "${option_string}" option; do
case ${option} in
a)
echo "-a triggered with parameter "${OPTARG}"" >&2 # output to STDERR
;;
b)
echo "-b triggered" >&2 # output to STDERR
;;
\?)
echo "invalid option: -"${OPTARG}"" >&2 # output to STDERR
;;
esac
done
shift $(expr ${OPTIND} - 1)
echo "${@}"
}
option_string=":a:b"
non_option_parameters=""
parameters="${@}"
while [ ! -z "${parameters}" ]; do
parameters="$(process_arguments ${parameters})"
non_option_parameters="${non_option_parameters} "$(awk -F '[ \t]*-' '{print $1}' <<< "${parameters}")
parameters=$(awk -F '[ \t]*-' 'NF > 1{print substr($0, index($0, "-"))}' <<< "${parameters}")
done
echo "non-option parameters:${non_option_parameters}"
答案 0 :(得分:1)
我没有花很多时间阅读你的代码。我同意你的看法:在脚本的“主要级别”处理你的选项,这样你就可以直接使用脚本的位置参数。
这是重写:
#!/bin/bash
while getopts ":a:b" option; do
case $option in
a)
echo "-a triggered with parameter $OPTARG" >&2
;;
b)
echo "-b triggered" >&2
;;
:)
echo "missing argument for option -${OPTARG}" >&2
;;
\?)
echo "invalid option: -${OPTARG}" >&2
;;
esac
done
shift $(( OPTIND - 1 ))
echo "remaining arguments:"
for (( i=1; i<=$#; i++ )); do
printf "%d: '%s'\n" $i "${!i}"
done
行动中:
$ bash ./opts.sh -a A -b B -c -d "foo bar" baz
-a triggered with parameter A
-b triggered
remaining arguments:
1: 'B'
2: '-c'
3: '-d'
4: 'foo bar'
5: 'baz'
“-c”和“-d”没有看到任何“无效选项”错误,因为while getopts
循环在达到第一个非选项参数“B”时结束。
更新:多次调用getopts:
extra_args=()
while (( $# > 0 )); do
OPTIND=1
while getopts ":a:b" option; do
case $option in
a) echo "-a triggered with parameter $OPTARG" >&2 ;;
b) echo "-b triggered" >&2 # output to STDERR ;;
:) echo "missing argument for option -$OPTARG" >&2 ;;
?) echo "invalid option: -$OPTARG" >&2 ;;
esac
done
shift $(( OPTIND - 1 ))
if (( $# > 0 )); then
extra_args+=( "$1" )
shift
fi
done
echo "non-option arguments:"
printf "%s\n" "${extra_args[@]}"
$ bash ~/tmp/opts.sh -a A B -c -d "foo bar" baz -b
-a triggered with parameter A
invalid option: -c
invalid option: -d
-b triggered
non-option arguments:
B
foo bar
baz
答案 1 :(得分:1)
无移位解决方案如下。
我使用bash数组来保存位置(非标志)参数,因为它是处理具有空格的参数的唯一有效方法。特别是,尽管有引用,但echo "${@}"
有效擦除了论据,因为echo
不会保留引用。
我也保留process_argument
,虽然您可以轻松地将其放入循环中。它差别很小(直接调用exit 1
而不是return 1
可以说更简单。)
# process_argument option
# Do whatever needs to be done to handle provided option. Fail on error.
OPTIONS=:a:b
process_argument() {
case "$1" in
a)
echo "-a triggered with parameter $OPTARG" >&2
;;
b)
echo "-b triggered" >&2 # output to STDERR
;;
:)
echo "missing argument for option -${OPTARG}" >&2
return 1
;;
\?)
echo "invalid option: -${OPTARG}" >&2
return 1
;;
esac
}
# Loop to handle all parameters
non_option_parameters=()
while true; do
while getopts "$OPTIONS" option; do
if ! process_argument "$option"; then exit 1; fi
done
if ((OPTIND > $#)); then break; fi
non_option_parameters+=(${!OPTIND})
((OPTIND++))
done
printf "Non-option parameters: "
printf "<%s> " "${non_option_parameters[@]}"; echo