# Parse the command line and set variables to control logic.
parseCommandLine() {
local additionalOpts exitCode optstring optstringLong
# Indicate specification for single character options:
# - 1 colon after an option indicates that an argument is required
# - 2 colons after an option indicates that an argument is optional, must use -o=argument syntax
optstring="h"
# Indicate specification for long options:
# - 1 colon after an option indicates that an argument is required
# - 2 colons after an option indicates that an argument is optional, must use --option=argument syntax
optstringLong="help"
# Parse the options using getopt command:
# - the -- is a separator between getopt options and parameters to be parsed
# - output is simple space-delimited command line
# - error message will be printed if unrecognized option or missing parameter but status will be 0
# - if an optional argument is not specified, output will include empty string ''
GETOPT_OUT=$(getopt --options ${optstring} --longoptions ${optstringLong} -- "$@")
exitCode=$?
if [ ${exitCode} -ne 0 ]; then
# Call a separate function to print usage.
printUsage
exit 1
fi
# The following constructs the command by concatenating arguments:
# - the $1, $2, etc. variables are set as if typed on the command line
# - special cases like --option=value and missing optional arguments are generically handled
# as separate parameters so shift can be done below
eval set -- "${GETOPT_OUT}"
# Loop over the options:
# - the error handling will catch cases were argument is missing
# - shift over the known number of options/arguments
while true; do
#echo "Command line option is ${opt}"
case "$1" in
-h|--help) # Print usage of this script
printUsage
shift
;;
--) # No more arguments - following arguments are passed to the second program.
shift
break
;;
*) # Unknown option - will never get here because getopt catches up front
# and remaining options are after --
echo "Invalid option $1." >&2
printUsage
exit 1
;;
esac
done
# Get a list of all command line options that do not correspond to dash options:
# - These are "non-option" arguments after --
# - For example, one or more file or folder names that need to be processed.
# - If multiple values, they will be delimited by spaces.
# - Command line * will result in expansion to matching files and folders.
shift $((OPTIND-1))
additionalOpts=$*
echo "Additional options: ${additionalOpts}"
# The additional options would be passed to the second program.
}
单个连字符后可以跟多个单字符标志。双连字符作为单个多字符选项的前缀。
考虑这个例子:
在此示例中,
-czf
指定三个单字符标志:c
、z
和f
。现在考虑另一个例子:
在这种情况下,
--exclude
指定一个名为 的单个多字符选项exclude
。双连字符消除了命令行参数的歧义,确保将其tar
解释为, , , , , , 和exclude
的组合。e
x
c
l
u
d
e
这完全取决于程序。通常“-”用于“短”选项(一个字母,-h),“--”用于“长”(er)选项(--help)。
短选项通常可以组合(所以“-h -a”与“-ha”相同)
资源
这真的是一个约定。但是,它可以帮助解析器更有效地了解传递给程序的选项。此外,还有一些简洁的实用程序可以帮助解析这些命令,例如帮助解析程序参数的
getopt(3)
非标准实用getopt_long(3)
程序。这很好,因为我们可以组合多个短选项,就像其他答案所说的那样,比如
tar -xzf myfile.tar.gz
.如果 有一个“lisa”参数
ls
,那么键入的含义可能与ls -lisa
不同ls --lisa
。前者是l
,i
,s
, 和a
参数,而不是单词。事实上,您可以写
ls -l -i -s -a
, 与 的含义完全相同ls -lisa
,但这取决于程序。也有不遵守此约定的程序。最值得注意的是我的视力,
dd
和gcc
。短选项可以组合成一个参数;
如果我们允许带有单个破折号的长选项,则会导致歧义。为了解决这个问题,我们对长选项使用双破折号。
另一种情况是当脚本调用另一个程序时,可能需要将第一个脚本的选项与传递给第二个程序的选项分开。例如,您可以编写一个 bash 函数来解析命令行,类似于下面的函数。然后使用类似于以下的命令行。在这种情况下,双破折号将每个程序的选项分开,并允许内置解析器的错误处理按预期工作。当然,可能会有特殊情况需要处理。