比如,我有一个脚本,用这行代码调用:
./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?
比如,我有一个脚本,用这行代码调用:
./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?
当前回答
另一个Shell参数分析器(ASAP)
符合POSIX,无getopt
我受到@bronson相对简单的回答的启发,并试图改进它(不增加太多复杂性)。结果如下:
使用-n[arg]、-abn[arg],--name[arg]和--name=arg样式中的任意一种选项;参数可以按任何顺序出现,循环后$@中只留下位置参数;使用--强制将剩余的参数视为位置参数;检测无效选项和缺少的参数;不依赖于getopt或外部工具(一个功能使用简单的sed命令);便携式,紧凑,可读性强,具有独立功能。
# Convenience functions.
usage_error () { echo >&2 "$(basename $0): $1"; exit 2; }
assert_argument () { test "$1" != "$EOL" || usage_error "$2 requires an argument"; }
# One loop, nothing more.
if [ "$#" != 0 ]; then
EOL=$(printf '\1\3\3\7')
set -- "$@" "$EOL"
while [ "$1" != "$EOL" ]; do
opt="$1"; shift
case "$opt" in
# Your options go here.
-f|--flag) flag='true';;
-n|--name) assert_argument "$1" "$opt"; name="$1"; shift;;
# Arguments processing. You may remove any unneeded line after the 1st.
-|''|[!-]*) set -- "$@" "$opt";; # positional argument, rotate to the end
--*=*) set -- "${opt%%=*}" "${opt#*=}" "$@";; # convert '--name=arg' to '--name' 'arg'
-[!-]?*) set -- $(echo "${opt#-}" | sed 's/\(.\)/ -\1/g') "$@";; # convert '-abc' to '-a' '-b' '-c'
--) while [ "$1" != "$EOL" ]; do set -- "$@" "$1"; shift; done;; # process remaining arguments as positional
-*) usage_error "unknown option: '$opt'";; # catch misspelled options
*) usage_error "this should NEVER happen ($opt)";; # sanity test for previous patterns
esac
done
shift # $EOL
fi
# Do something cool with "$@"... \o/
注:我知道。。。二进制模式为0x01030307的参数可能会破坏逻辑。但是,如果有人在命令行中传递这样的参数,他们应该得到它。
其他回答
混合位置和基于标志的参数
--param=arg(等于分隔符)
在位置参数之间自由混合标志:
./script.sh dumbo 127.0.0.1 --environment=production -q -d
./script.sh dumbo --environment=production 127.0.0.1 --quiet -d
可以用相当简洁的方法完成:
# process flags
pointer=1
while [[ $pointer -le $# ]]; do
param=${!pointer}
if [[ $param != "-"* ]]; then ((pointer++)) # not a parameter flag so advance pointer
else
case $param in
# paramter-flags with arguments
-e=*|--environment=*) environment="${param#*=}";;
--another=*) another="${param#*=}";;
# binary flags
-q|--quiet) quiet=true;;
-d) debug=true;;
esac
# splice out pointer frame from positional list
[[ $pointer -gt 1 ]] \
&& set -- ${@:1:((pointer - 1))} ${@:((pointer + 1)):$#} \
|| set -- ${@:((pointer + 1)):$#};
fi
done
# positional remain
node_name=$1
ip_address=$2
--参数arg(空格分隔)
通常情况下,不混合--flag=value和--flag值样式会更清晰。
./script.sh dumbo 127.0.0.1 --environment production -q -d
这读起来有点冒险,但仍然有效
./script.sh dumbo --environment production 127.0.0.1 --quiet -d
来源
# process flags
pointer=1
while [[ $pointer -le $# ]]; do
if [[ ${!pointer} != "-"* ]]; then ((pointer++)) # not a parameter flag so advance pointer
else
param=${!pointer}
((pointer_plus = pointer + 1))
slice_len=1
case $param in
# paramter-flags with arguments
-e|--environment) environment=${!pointer_plus}; ((slice_len++));;
--another) another=${!pointer_plus}; ((slice_len++));;
# binary flags
-q|--quiet) quiet=true;;
-d) debug=true;;
esac
# splice out pointer frame from positional list
[[ $pointer -gt 1 ]] \
&& set -- ${@:1:((pointer - 1))} ${@:((pointer + $slice_len)):$#} \
|| set -- ${@:((pointer + $slice_len)):$#};
fi
done
# positional remain
node_name=$1
ip_address=$2
getopt()/getopts()是一个很好的选项。从此处复制:
“getopt”的简单用法如下小脚本所示:
#!/bin/bash
echo "Before getopt"
for i
do
echo $i
done
args=`getopt abc:d $*`
set -- $args
echo "After getopt"
for i
do
echo "-->$i"
done
我们所说的是,-b、 -c或-d将被允许,但-c后面跟着一个参数(“c:”表示)。如果我们称之为“g”并尝试:
bash-2.05a$ ./g -abc foo
Before getopt
-abc
foo
After getopt
-->-a
-->-b
-->-c
-->foo
-->--
我们从两个参数开始“getopt”将选项和每个人都有自己的论点。它也是添加了“--”。
这是我在函数中如何避免在堆栈的较高位置同时中断getopts运行:
function waitForWeb () {
local OPTIND=1 OPTARG OPTION
local host=localhost port=8080 proto=http
while getopts "h:p:r:" OPTION; do
case "$OPTION" in
h)
host="$OPTARG"
;;
p)
port="$OPTARG"
;;
r)
proto="$OPTARG"
;;
esac
done
...
}
我认为这个很简单:
#!/bin/bash
#
readopt='getopts $opts opt;rc=$?;[ "$rc$opt" = "0?" ]&&exit 1;[ $rc = 0 ]||{ shift $[OPTIND-1];false; }'
opts=vfdo:
# Enumerating options
while eval "$readopt"
do
echo OPT:$opt ${OPTARG+OPTARG:$OPTARG}
done
# Enumerating arguments
for arg
do
echo ARG:$arg
done
调用示例:
./myscript -v -do /fizz/someOtherFile -f ./foo/bar/someFile
OPT:v
OPT:d
OPT:o OPTARG:/fizz/someOtherFile
OPT:f
ARG:./foo/bar/someFile
使用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!"