说,我有一个用这行调用的脚本:
./myscript -vfd ./foo/bar/someFile -o /fizz/someOtherFile
或者这一个:
./myscript -v -f -d -o /fizz/someOtherFile ./foo/bar/someFile
什么是解析这个的可接受的方式,在每种情况下(或两者的某种组合) $v
, $f
和$d
都将设置为true
, $outFile
将等于/fizz/someOtherFile
?
传递键 - 值对参数的两种常用方法是:
--option argument
)(不带 getopt [s]) 用法./myscript.sh -e conf -s /etc -l /usr/lib /etc/hosts
#!/bin/bash
POSITIONAL=()
while [[ $# -gt 0 ]]
do
key="$1"
case $key in
-e|--extension)
EXTENSION="$2"
shift # past argument
shift # past value
;;
-s|--searchpath)
SEARCHPATH="$2"
shift # past argument
shift # past value
;;
-l|--lib)
LIBPATH="$2"
shift # past argument
shift # past value
;;
--default)
DEFAULT=YES
shift # past argument
;;
*) # unknown option
POSITIONAL+=("$1") # save it in an array for later
shift # past argument
;;
esac
done
set -- "${POSITIONAL[@]}" # restore positional parameters
echo FILE EXTENSION = "${EXTENSION}"
echo SEARCH PATH = "${SEARCHPATH}"
echo LIBRARY PATH = "${LIBPATH}"
echo DEFAULT = "${DEFAULT}"
echo "Number files in SEARCH PATH with EXTENSION:" $(ls -1 "${SEARCHPATH}"/*."${EXTENSION}" | wc -l)
if [[ -n $1 ]]; then
echo "Last line of file specified as non-opt/last argument:"
tail -1 "$1"
fi
--option=argument
)(不带 getopt [s]) 用法./myscript.sh -e=conf -s=/etc -l=/usr/lib /etc/hosts
#!/bin/bash
for i in "$@"
do
case $i in
-e=*|--extension=*)
EXTENSION="${i#*=}"
shift # past argument=value
;;
-s=*|--searchpath=*)
SEARCHPATH="${i#*=}"
shift # past argument=value
;;
-l=*|--lib=*)
LIBPATH="${i#*=}"
shift # past argument=value
;;
--default)
DEFAULT=YES
shift # past argument with no value
;;
*)
# unknown option
;;
esac
done
echo "FILE EXTENSION = ${EXTENSION}"
echo "SEARCH PATH = ${SEARCHPATH}"
echo "LIBRARY PATH = ${LIBPATH}"
echo "Number files in SEARCH PATH with EXTENSION:" $(ls -1 "${SEARCHPATH}"/*."${EXTENSION}" | wc -l)
if [[ -n $1 ]]; then
echo "Last line of file specified as non-opt/last argument:"
tail -1 $1
fi
为了更好地理解${i#*=}
,请在本指南中搜索 “Substring Removal”。它在功能上等同于`sed 's/[^=]*=//' <<< "$i"`
它调用一个不必要的子进程或`echo "$i" | sed 's/[^=]*=//'`
它调用两个不必要的子进程。
来自: http : //mywiki.wooledge.org/BashFAQ/035#getopts
getopt(1)限制 (较旧的,相对较新的getopt
版本):
最近的getopt
版本没有这些限制。
此外,POSIX shell(和其他)提供了没有这些限制的getopts
。这是一个简单的getopts
示例:
#!/bin/sh
# A POSIX variable
OPTIND=1 # Reset in case getopts has been used previously in the shell.
# Initialize our own variables:
output_file=""
verbose=0
while getopts "h?vf:" opt; do
case "$opt" in
h|\?)
show_help
exit 0
;;
v) verbose=1
;;
f) output_file=$OPTARG
;;
esac
done
shift $((OPTIND-1))
[ "${1:-}" = "--" ] && shift
echo "verbose=$verbose, output_file='$output_file', Leftovers: $@"
# End of file
getopts
的优点是:
dash
。 -vf filename
。 getopts
的缺点是它只能处理短选项( -h
,而不是--help
)而无需额外的代码。
有一个getopts 教程 ,解释了所有语法和变量的含义。在 bash 中,还有help getopts
,这可能是提供信息的。
没有回答提到增强的 getopt 。而最高投票的答案是误导性的:它忽略了-vfd
样式的短选项(由 OP 请求),位置参数后的选项(也是 OP 请求的)并忽略了解析错误。代替:
getopt
。 1 getopt_long()
使用 GNU glibc 的 C 函数。 script.sh -o outFile file1 file2 -v
script.sh --outfile=fileOut --infile fileIn
=
-style long 选项: script.sh --outfile=fileOut --infile fileIn
getopt --test
→返回值 4。 getopt
或 shell-builtin getopts
的用途有限。 以下电话
myscript -vfd ./foo/bar/someFile -o /fizz/someOtherFile
myscript -v -f -d -o/fizz/someOtherFile -- ./foo/bar/someFile
myscript --verbose --force --debug ./foo/bar/someFile -o/fizz/someOtherFile
myscript --output=/fizz/someOtherFile ./foo/bar/someFile -vfd
myscript ./foo/bar/someFile -df -v --output /fizz/someOtherFile
一切都回归
verbose: y, force: y, debug: y, in: ./foo/bar/someFile, out: /fizz/someOtherFile
以下是myscript
#!/bin/bash
# saner programming env: these switches turn some bugs into errors
set -o errexit -o pipefail -o noclobber -o nounset
! getopt --test > /dev/null
if [[ ${PIPESTATUS[0]} -ne 4 ]]; then
echo "I’m sorry, `getopt --test` failed in this environment."
exit 1
fi
OPTIONS=dfo:v
LONGOPTS=debug,force,output:,verbose
# -use ! and PIPESTATUS to get exit code with errexit set
# -temporarily store output to be able to check for errors
# -activate quoting/enhanced mode (e.g. by writing out “--options”)
# -pass arguments only via -- "$@" to separate them correctly
! PARSED=$(getopt --options=$OPTIONS --longoptions=$LONGOPTS --name "$0" -- "$@")
if [[ ${PIPESTATUS[0]} -ne 0 ]]; then
# e.g. return value is 1
# then getopt has complained about wrong arguments to stdout
exit 2
fi
# read getopt’s output this way to handle the quoting right:
eval set -- "$PARSED"
d=n f=n v=n outFile=-
# now enjoy the options in order and nicely split until we see --
while true; do
case "$1" in
-d|--debug)
d=y
shift
;;
-f|--force)
f=y
shift
;;
-v|--verbose)
v=y
shift
;;
-o|--output)
outFile="$2"
shift 2
;;
--)
shift
break
;;
*)
echo "Programming error"
exit 3
;;
esac
done
# handle non-option arguments
if [[ $# -ne 1 ]]; then
echo "$0: A single input file is required."
exit 4
fi
echo "verbose: $v, force: $f, debug: $d, in: $1, out: $outFile"
在大多数 “bash 系统” 上都有1 个增强的 getopt,包括 Cygwin; 在 OS X 上尝试brew install gnu-getopt或sudo port install getopt
2 POSIX exec()
约定没有可靠的方法在命令行参数中传递二进制 NULL; 那些字节过早地结束了论证
3第一个版本发布于 1997 年或之前(我只跟踪它回到 1997 年)
来自: digitalpeer.com稍作修改
用法myscript.sh -p=my_prefix -s=dirname -l=libname
#!/bin/bash
for i in "$@"
do
case $i in
-p=*|--prefix=*)
PREFIX="${i#*=}"
;;
-s=*|--searchpath=*)
SEARCHPATH="${i#*=}"
;;
-l=*|--lib=*)
DIR="${i#*=}"
;;
--default)
DEFAULT=YES
;;
*)
# unknown option
;;
esac
done
echo PREFIX = ${PREFIX}
echo SEARCH PATH = ${SEARCHPATH}
echo DIRS = ${DIR}
echo DEFAULT = ${DEFAULT}
为了更好地理解${i#*=}
,请在本指南中搜索 “Substring Removal”。它在功能上等同于`sed 's/[^=]*=//' <<< "$i"`
它调用一个不必要的子进程或`echo "$i" | sed 's/[^=]*=//'`
它调用两个不必要的子进程。