ive*_*son 34 bash getopt getopts
while getopts "hd:R:" arg; do
case $arg in
h)
echo "usgae"
;;
d)
dir=$OPTARG
;;
R)
if [[ $OPTARG =~ ^[0-9]+$ ]];then
level=$OPTARG
else
level=1
fi
;;
\?)
echo "WRONG" >&2
;;
esac
done
Run Code Online (Sandbox Code Playgroud)
level是指参数-R
,dir是指参数-d
当我输入 ./count.sh -R 1 -d test/
它正确的工作
当我输入./count.sh -d test/ -R 1
它正确的工作
但我想在输入./count.sh -d test/ -R
或输入时使其工作./count.sh -R -d test/
这意味着我想要-R
一个默认值,命令序列可以更灵活.
And*_*ler 22
错误.实际上getopts
确实支持可选参数!从bash手册页:
If a required argument is not found, and getopts is not silent,
a question mark (?) is placed in name, OPTARG is unset, and a diagnostic
message is printed. If getopts is silent, then a colon (:) is placed in name
and OPTARG is set to the option character found.
Run Code Online (Sandbox Code Playgroud)
当手册页显示"无声"时,它表示无声错误报告.要启用它,optstring的第一个字符必须是冒号:
while getopts ":hd:R:" arg; do
# ...rest of iverson's loop should work as posted
done
Run Code Online (Sandbox Code Playgroud)
由于Bash的getopt无法识别--
结束选项列表,因此-R
在最后一个选项时可能无效,后跟一些路径参数.
PS:传统上,getopt.c使用两个冒号(::
)来指定可选参数.但是,Bash使用的版本没有.
tri*_*eee 16
getopts
并不真的支持这一点; 但是写自己的替代品并不难.
while true; do
case $1 in
-R) level=1
shift
case $1 in
*[!0-9]* | "") ;;
*) level=$1; shift ;;
esac ;;
# ... Other options ...
-*) echo "$0: Unrecognized option $1" >&2
exit 2;;
*) break ;;
esac
done
Run Code Online (Sandbox Code Playgroud)
Ako*_* Cz 10
我同意tripleee,getopts不支持可选参数处理.
我已经解决的妥协解决方案是使用相同选项标志的大写/小写组合来区分采用参数的选项和不参数的选项.
例:
COMMAND_LINE_OPTIONS_HELP='
Command line options:
-I Process all the files in the default dir: '`pwd`'/input/
-i DIR Process all the files in the user specified input dir
-h Print this help menu
Examples:
Process all files in the default input dir
'`basename $0`' -I
Process all files in the user specified input dir
'`basename $0`' -i ~/my/input/dir
'
VALID_COMMAND_LINE_OPTIONS="i:Ih"
INPUT_DIR=
while getopts $VALID_COMMAND_LINE_OPTIONS options; do
#echo "option is " $options
case $options in
h)
echo "$COMMAND_LINE_OPTIONS_HELP"
exit $E_OPTERROR;
;;
I)
INPUT_DIR=`pwd`/input
echo ""
echo "***************************"
echo "Use DEFAULT input dir : $INPUT_DIR"
echo "***************************"
;;
i)
INPUT_DIR=$OPTARG
echo ""
echo "***************************"
echo "Use USER SPECIFIED input dir : $INPUT_DIR"
echo "***************************"
;;
\?)
echo "Usage: `basename $0` -h for help";
echo "$COMMAND_LINE_OPTIONS_HELP"
exit $E_OPTERROR;
;;
esac
done
Run Code Online (Sandbox Code Playgroud)
小智 7
这实际上非常简单.只需在R之后删除尾部冒号并使用OPTIND
while getopts "hRd:" opt; do
case $opt in
h) echo -e $USAGE && exit
;;
d) DIR="$OPTARG"
;;
R)
if [[ ${@:$OPTIND} =~ ^[0-9]+$ ]];then
LEVEL=${@:$OPTIND}
OPTIND=$((OPTIND+1))
else
LEVEL=1
fi
;;
\?) echo "Invalid option -$OPTARG" >&2
;;
esac
done
echo $LEVEL $DIR
Run Code Online (Sandbox Code Playgroud)
count.sh -d test
测试
count.sh -d test -R
1测试
count.sh -R -d test
1测试
count.sh -d test -R 2
2测试
count.sh -R 2 -d测试
2测试
此解决方法定义了不带参数的R(不带“:”),测试了-R之后的任何参数(在命令行上管理最后一个选项),并测试现有参数是否以短划线开头。
# No : after R
while getopts "hd:R" arg; do
case $arg in
(...)
R)
# Check next positional parameter
eval nextopt=\${$OPTIND}
# existing or starting with dash?
if [[ -n $nextopt && $nextopt != -* ]] ; then
OPTIND=$((OPTIND + 1))
level=$nextopt
else
level=1
fi
;;
(...)
esac
done
Run Code Online (Sandbox Code Playgroud)