Linux之处理用户输入(三)

mark

使用getopt命令

getopt能够识别命令行参数,从而在脚本中解析它们。getopt可以接受一系列任意形式的命令行选项和参数,并自动将它们转换为适当的格式。其命令行格式如下:

getopt optstring paramaters

optstring是这个过程的关键所在,它定义了命令行有效的选项字母,还定义了哪些选项字母需要参数值,在optstring中列出你要在脚本中用到的每个命令行选项字母,然后在每个需要参数值的选项字母后加一个冒号,getopt命令会基于你定义的optstring解析提供的参数。

举个例子:

$ getopt ad:cd -a -b test1 -cd test2 test3
-a -b test1 -c -d -- test2 test3

optstring定义了四个有效选项字母,冒号在b之后,因为b选项需要一个参数值,当getopt命令运行时,它会检查提供的参数列表(-a -b test1 -cd test2 test3),并基于提供的optstring进行解析,它会自动将-cd选项分成两个独立的选项,并插入双破折线来分隔行中的额外参数。

如果指定了一个不在optstring中的选项,会报错,这时可以在命令行中加入-q选项以忽略错误消息

$ getopt ab:cd -a -b test1 -cde test2 test3
getopt: invalid option -- e
-a -b test1 -c -d -- test2 test3
$ getopt -q ab:cd -a -b test1 -cde test2 test3
-a -b 'test1' -c -d -- 'test2' 'test3'

脚本中使用getopt

通过set命令来完成,set命令的选项之一是双破折线,它会将命令行参数替换成set命令的命令行值。该方法首先将原始脚本中的命令行参数传给getopt命令,之后再将getopt命令的输出传给set命令,用getopt格式化后的命令行参数来替换原始的命令行参数,具体如下:

set --$(gteopt -q ab:cd "$@")

现在原始的命令行参数变量的值就会被getopt命令行的输出替换,getopt已经将命令行参数全部格式化好了。

$ cat test18.sh
#!/bin/bash
# Extract command line options & values with getopt
#
set -- $(getopt -q ab:cd "$@")
#
echo
while [ -n "$1" ]
do
    case "$1" in
    -a) echo "Found the -a option" ;;
    -b) param="$2"
        echo "Found the -b option, with parameter value $param"
        shift ;;
    -c) echo "Found the -c option" ;;
    --) shift
        break ;;
    *) echo "$1 is not an option";;
esac
    shift
done
#
count=1
for param in "$@"
do
    echo "Parameter #$count: $param"
    count=$[ $count + 1 ]
done

现在运行含有复杂选项的脚本

$ ./test18.sh -ac
Found the -a option
Found the -c option
$ ./test18.sh -a -b test1 -cd test2 test3 test4
Found the -a option
Found the -b option, with parameter value 'test1'
Found the -c option
Parameter #1: 'test2'
Parameter #2: 'test3'
Parameter #3: 'test4'

但是还是存在一个问题,就是无法处理带空格和引号的参数值,它会将空格当作参数分隔符,而不是根据双引号将两者当作一个参数。

$ ./test18.sh -a -b test1 -cd "test2 test3" test4
Found the -a option
Found the -b option, with parameter value 'test1'
Found the -c option
Parameter #1: 'test2
Parameter #2: test3'
Parameter #3: 'test4'

getopts

getopts相对于getopt来说更高级,它可以提供getopt无法实现的功能。每次调用getopts时,它一次只会处理命令行上检测到的一个参数,处理完所有参数后,它会退出并返回一个大于0的退出状态码,因此可以与while结合运行。getopts命令用到两个环境变量,如果选项需要跟一个参数值,OPTARG环境变量会保存这个值,OPTIND环境变量保存了参数列表中getopts正在处理的参数位置,这样就能在处理完选项之后继续处理其他命令行参数了,其主要格式如下:

getopts optstring variable

optstring存有效的选项字母,如果选项字母要求有个参数值,就加一个冒号,要去掉错误信息,在optstring之前加一个冒号,getopts命令会将当前参数保存到命令行中定义的variable中

$ cat test19.sh
#!/bin/bash
# simple demonstration of the getopts command
#
echo
while getopts 🆎c opt
do
case "$opt" in
a) echo "Found the -a option" ;;
b) echo "Found the -b option, with value $OPTARG";;
c) echo "Found the -c option" ;;
*) echo "Unknown option: $opt";;
esac
done
$
$ ./test19.sh -ab test1 -c
Found the -a option
Found the -b option, with value test1
Found the -c option

getopts在解析命令行选项时会移除开头的破折线所以在case定义中不用单破折线。getopts支持空格参数值输入及其他输入

$ ./test19.sh -b "test1 test2" -a
Found the -b option, with value test1 test2
Found the -a option
$ ./test19.sh -abtest1
Found the -a option
Found the -b option, with value test1

getopts会将在命令行上找到的未定义的选项统一输出为问号

$ ./test19.sh -d
Unknown option: ?
$
$ ./test19.sh -acde
Found the -a option
Found the -c option
Unknown option: ?
Unknown option: ?

getopts知道何时停止处理选项,在getopts处理每个选项时会将OPTIND环境变量值加一,在完成getopts之后,可以使用shift命令和OPTIND值来移动参数。

$ cat test20.sh
#!/bin/bash
# Processing options & parameters with getopts
#
echo
while getopts 🆎cd opt
do
case "$opt" in
a) echo "Found the -a option" ;;
b) echo "Found the -b option, with value $OPTARG" ;;
c) echo "Found the -c option" ;;
d) echo "Found the -d option" ;;
*) echo "Unknown option: $opt" ;;
esac
done
#
shift $[ $OPTIND - 1 ]
#
echo
count=1
for param in "$@"
do
echo "Parameter $count: $param"
count=$[ $count + 1 ]
done
$ ./test20.sh -a -b test1 -d test2 test3 test4
Found the -a option
Found the -b option, with value test1
Found the -d option
Parameter 1: test2
Parameter 2: test3
Parameter 3: test4

选项标准化

主要是与Linux里已经存在含有某种程度的标准含义的字母相吻合,比如o一般代表输出等。

选 项 描 述
-a 显示所有对象
-c 生成一个计数
-d 指定一个目录
-e 扩展一个对象
-f 指定读入数据的文件
-h 显示命令的帮助信息
-i 忽略文本大小写
-l 产生输出的长格式版本
-n 使用非交互模式(批处理)
-o 将所有输出重定向到的指定的输出文件
-q 以安静模式运行
-r 递归地处理目录和文件
-s 以安静模式运行
-v 生成详细输出
-x 排除某个对象
-y 对所有问题回答yes
Researcher

I am a PhD student of Crop Genetics and Breeding at the Zhejiang University Crop Science Lab. My research interests covers a range of issues:Population Genetics Evolution and Ecotype Divergence Analysis of Oilseed Rape, Genome-wide Association Study (GWAS) of Agronomic Traits.

comments powered by Disqus