getopt

解析命令行选项


语法格式

getopt optstring vars
getopt [-aqQTu] [-l longopts] [-n prog] [-s shell] [--] optstring vars
getopt [-aqQTu] [-l longopts] [-n prog] [-s shell] –o shortopts [--] vars
getopt [-h|--help] [-V|--version]

命令简介

getopt命令用于解析命令行选项,检测给定的选项是否合法。其中,optstring是需要解析的合法选项字符串,vars通常是一组变量,用于存储从命令行中获取的每个选项及参数。

在getopt命令中,选项部分主要用于影响getopt命令解析选项及参数的方式,参数部分是需要解析的选项、选项参数及命令参数等。非选项参数,尤其是“--”之后的参数均按命令参数解释。如果未指定“-o”选项(参见第二种语法格式),第一个参数optatring被用作短选项字符串。

如果设置了GETOPT_COMPATIBLE环境变量,或第一个参数并非选项(即首字符并非连字符“-”,即采用第一种语法格式),getopt将生成并输出兼容的解析结果,包括选项、选项参数、选用的选项参数和命令参数等。

getopt命令的传统实现无法解析选项、选项参数及命令参数中的空白字符及其他特殊字符。为解决这个问题,新版的getopt命令能够生成加引号的输出数据,再由Shell做进一步的解释(通常使用eval命令完成)。这时需要使用非兼容的第二种和第三种语法格式,才能保持空白字符及其他特殊字符。若想确定运行的getopt命令是否为增强版的getopt命令,可以使用特殊的测试选项“-T”,根据其返回代码是否为4来确定getopt命令的版本。

命令选项

-a, --alternative  允许GNU长选项以单个连字符“-”开始。

-l longopts, --longoptions longopts  识别多字符的长选项。其中的longopts是长选项的名字。一次可以同时指定多个选项名,中间加逗号分隔符。也可以同时指定多个“-l”选项,最终可以把多个longopts参数组合在一起。longopts参数中的每个长选项名后面可以跟一个冒号“:”,表示相应的选项需要提供参数。如果跟随两个冒号,表示还有一个选用的参数。

-n prog, --name prog  指定一个程序,供getopt(3)函数输出错误信息时使用。注意,即使如此,getopt命令本身仍然会输出错误信息(如果存在)。

-o shortopts, --options shortopts  识别单字符的短选项。如果未指定“-o”选项,getopt命令第一个首字符非连字符“-”的参数被用作短选项字符串。shortopts参数中的每个短选项字符后面可以跟一个冒号“:”,表示相应的选项需要提供参数。如果跟随两个冒号,表示还有一个选用的参数。shortopts参数的第一个字符可以是“+”或“-”号,用以影响选项解析的方式和生成的输出。详见“解析方式”一节。

-q, --quiet  禁止输出错误信息。

-Q, --quiet-output  禁止生成常规的输出信息。但允许显示出现的错误信息,除非指定了“-q”选项。

-s shell, --shell shell  指定Shell,从而指定Shell的引用惯例。如果未指定“-s”选项,则使用bash的引用惯例。当前有效的shell参数是sh、bash、csh和tcsh。

-T, --test  测试getopt命令是否增强版。使用这个选项通常不会生成任何输出信息,只能根据其结束状态是否为4做出判断。

-u, --unquoted  禁止在输出信息增加引用记号。注意,在此方式下,空白字符和特殊字符可能会引起混乱。

解析

getopt命令的主要功能是按照指定的格式定义,解析选项及其参数。所谓的选项及其参数通常是调用Shell命令或脚本时提供的命令选项及参数。在内部的处理过程中,所有的解析都是由GNU getopt(3)函数实现的。

选项与参数的解析从左到右依次处理。每个选项及参数可以归类为短选项、长选项、选项参数或命令参数。

最简单的选项是一个连字符“-”后面跟一个短选项字符。如果选项要求提供参数,则可以直接写在选项字符之后,也可以在选项字符与参数之间插入一个空白字符。如果参数是选用的,则需要提供时必须直接写在选项字符之后,中间不能有空格。

也可以在连字符“-”后面同时指定若干短选项,只要这些选项不需要提供必须提供的或选用的参数(最后一个除外)。

长选项通常以两个连续的连字符“--”开始,后面跟有较长的选项名。如果选项要求提供参数,可以直接写在长选项名之后,中间插入一个等号“=”或空白字符。如果参数是选用的,需要提供时必须直接写在选项名之后,中间插入一个等号(如果只加了等号,后面没有任何数据,可解释为没有参数)。长选项可以是缩写形式,只要缩写不会引起歧义即可。

每个首字符不是连字符“-”,也不是选项参数的参数,都是命令参数。“--”之后的每个参数总是按命令参数而非选项参数解释的。如果设置了POSIXLY_CORRECT环境变量,或短选项字符串的首字符为“+”,一旦发现第一个命令参数,剩余的所有参数均按命令参数解释。

输出

针对“解析”一节说明的每一个元素,可以生成适当的输出。除了命令参数,输出的顺序与输入中指定元素的顺序完全相同。输出形式可以是不加引号的兼容模式,或加引号的增强形式,使选项参数或命令参数中能够包括空白字符和其他特殊字符,以便在Shell脚本中处理getopt命令的输出数据时能够作为一个元素解释。在不加引号的兼容模式中,如果选项参数或命令参数中包括空白字符和其他特殊字符,将会出现不可预期的解释结果。

在解析过程中如果出现问题,如没有提供必要的参数或提供的选项不合法,getopt将利用标准错误输出显示存在的问题,停止处理有问题的元素,返回非0的错误代码。

对于短选项而言,作为一个参数生成单个连字符“-”与选项字符。如果选项本身也有参数,生成的下一个参数将是选项参数。如果选项的参数是选用的,且没有发现选项参数,在引用模式下,仍然会生成下一个参数,只不过这个参数是一个加引号的空串。而在非引用(兼容)模式下,不会生成第二个参数。注意,有些getopt命令不支持选用的参数。

如果在单个连字符“-”后面指定了若干短选项,每个选项将作为一个单独的参数逐一输出。

对于长选项而言,“--”与完整的选项名都是作为单个参数生成的。采用长选项时,指定的选项可以是缩写,也可以省略一个连字符“-”。此外,选项参数同短选项的处理方式是一样的。

通常,在所有的选项及其参数都生成之后,才会生成并输出命令参数。之后,作为单个参数生成“--”,紧接着生成命令参数(按照发现的顺序依次生成)。

引用

在兼容模式中,getopt命令无法正确地处理参数或非选项命令参数中的空白字符及特殊字符。把getopt命令的输出提供给Shell脚本时,脚本并不知道怎样把输出数据分解成单独的选项及参数。因此,为避免此类问题出现,getopt命令提供一种引用机制。在生成输出的选项及参数时,getopt将在输出的每个选项及参数前后增加引号。把这种输出数据提供给Shell脚本时,脚本就能够正确地分解每个单独的选项及参数。

如果设置了GETOPT_COMPATIBLE环境变量,或者采用第一种语法格式,又或指定了“-u”选项,则不会启用引用机制。

不同的Shell使用不同的引用惯例。可以使用“-s”选项选择适用的Shell。getopt当前支持sh、bash、csh和tcsh。实际上,目前只有两种风格的Shell引用惯例:sh类型的引用惯例和csh类型的引用惯例。

解析方式

在兼容模式(第一种语法格式)中,短选项字符串的第一个字符可以是“-”或“+”,用作兼容解析方式的标记,getopt命令实际上并不处理。

如果第一个字符是“+”,或设置了POSIXLY_CORRECT环境变量,一旦发现第一个命令参数(其首字符并非连字符“-”),而非选项参数,立即停止解析。余下的任何参数均按命令参数解释。

如果第一个字符是“-”,在其被发现的位置输出命令参数。在常规的处理过程中,命令参数都会收集在一起,在生成“--”输出之后集中输出。注意,“--”总会生成,但在此模式下,它总是最后一个参数。

应用实例

1. ftpget是一个Shell脚本,其主要功能是根据用户提供的参数,利用ftp实现文件的自动下载。下例说明了怎样利用getopt命令处理其合法选项“-h”、“-d”、“-c”、“-f”和“-m”,解析和验证命令行参数。

$ cat ftpget
#!/bin/bash
CMDFILE=/tmp/ftp.$$
TMPFILE=/tmp/ftp2.$$
usage="Usage: $0 [-h rhost] [-d rdir] [-c ldir] [-f rfile:lfile] [-m fpattern]"
ftpopts="-i -n -v"
set -f
set -- `getopt h:d:c:f:m: $*`
# echo $*
if [ "$#" -lt 2 -o "$?" -ne 0 ]; then
        echo $usage
        exit 1
fi
trap 'rm -f ${CMDFILE} ${TMPFILE}; exit' 0 1 2 3 15
echo "user gqxing 123456" > ${CMDFILE}
for i in $*
do
        case $i in
                -h)     remhost=$2; shift 2;;
                -d)     echo cd $2 >> ${CMDFILE};
                        echo pwd >> ${CMDFILE};
                        shift 2;;
                -c)     echo lcd $2 >> ${CMDFILE}; shift 2;;
                -m)     echo mget "$2" >> ${TMPFILE}; shift 2;;
                -f)     f1=`echo "$2" | cut -d: -f1`; f2=`echo "$2" | cut -d: -f2`;
                        echo get ${f1} ${f2} >> ${TMPFILE}; shift 2;;
                --)     shift; break;;
        esac
done
if [ $# -ne 0 ]; then
        echo $usage
        exit 2
fi
echo quit >> ${TMPFILE}
cat $TMPFILE >> $CMDFILE
ftp ${ftpopts} ${remhost:-169.254.78.100} < ${CMDFILE}
cat ${CMDFILE} >> ftplog
rm -f ${CMDFILE} ${TMPFILE}
exit 0
$ ftpget –d docs –c /tmp -f design
Connected to 169.254.78.100.
220 (vsFTPd 2.2.0)
331 Please specify the password.
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
250 Directory successfully changed.
257 "/home/gqxing/docs"
Local directory now /tmp
local: design remote: design
200 PORT command successful. Consider using PASV.
150 Opening BINARY mode data connection for design (308522 bytes).
226 File send OK.
308522 bytes received in 0.01 secs (53802.0 kB/s)
221 Goodbye.
$

索引:A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z