shell命令行选项与参数处理--getopt--getopts ——Linux编程

 

目录

 

简介

1. 手工处理选项和参数

2. 使用 getopts 处理多命令行选项

3. 使用 getopt 处理多命令行选项


简介

本文介绍了linux shell中使用命令行选项与命令行参数的方法,在bash中,可以用以下三种方式来处理命令行参数,每种方式都有自己的应用场景。

1,直接处理,依次对$1,$2,...,$n进行解析,分别手工处理;

2,getopts来处理,单个字符选项的情况(如:-n 10 -f file.txt等选项);

3,getopt,可以处理单个字符选项,也可以处理长选项long-option(如:--prefix=/home等)。
总结:小脚本手工处理即可,getopts能处理绝大多数的情况,getopt较复杂、功能也更强大。

1. 手工处理选项和参数

当我们编写的 Shell 脚本只接收少量命令行选项时,且已知选项和参数位置格式,使用 case 语句对其进行处理是比较方便的。下面是一个简单的使用示例

#! /bin/bash

# 将第一个命令行参数赋值给变量 opt
opt=$1
# 将第二个命令行参数赋值给变量 filename
filename=$2

# 定义函数 checkfile
checkfile() {
        # 如果没有指定文件名,则显示缺少文件名,并退出脚本的运行
        if [ -z $filename ]
        then
                echo "File name missing"
                exit 1
        elif [ ! -f $filename ]
        then
                echo "The file $filename doesn't exist!"
                exit 2
        fi
}

case $opt in
        -e|-E)
                checkfile
                echo "Editing $filename file..."
                ;;
        -p|-P)
                checkfile
                echo "Displaying $filename file..."
                ;;
        *)
                echo "Bad argument!"
                echo "Usage: `basename $0` -e|-p filename"
                echo "          -e filename : Edit file."
                echo "          -f filename : Display file."
                ;;
esac

处理过程中,一下shell内置参数命令如下:

*    $0 :即命令本身,相当于c/c++中的argv[0]
*    $1 :第一个参数.
*    $2, $3, $4 ... :第2、3、4个参数,依次类推。
*    $#  参数的个数,不包括命令本身
*    $@ :参数本身的列表,也不包括命令本身
*    $* :和$@相同,但"$*" 和 "$@"(加引号)并不同,"$*"将所有的参数解释成一个字符串,而"$@"以IFS(默认为空格)来划分字段,如果空格在“”里面,不划分。举例如下:
    Listing args with"$*":
    Arg #1=1 2 3 4
    所有的参数被认为是一个单词

    Listing args with "$@":
    Arg #1=1
    Arg #2=2
    Arg #3=3
    Arg #4=4
    所有的参数被认为是各个独立的单词

    Listing args with $* (未被引用):
    Arg #1=1
    Arg #2=2
    Arg #3=3
    Arg #4=4

2. 使用 getopts 处理多命令行选项

getopts 的特点:

  • 我们不需要通过外部程序来处理位置参数;
  • getopts 可以容易地设置我们可以用来解析的 Shell 变量(这对于一个外部进程是不可能的);
  • getopts 定义在 POSIX 中。
  • 只处理短选项

getopts 会识别所有这些选项格式,指定的选项可以是大写或小写字母,或是数字。虽然它也能识别其他字符,但是不推荐使用。通常情况下,在处理命令行选项和参数时,我们需要多次调用 getopts。getopts 本身不会更改位置参数的设置,如果我们想要将位置参数移位,必须仍使用 shift 命令来处理位置参数。因为当没有内容可以解析时,getopts 会设置一个退出状态 FALSE,所以它很容易在 while 循环中使用:

while getopts ...; do
...
done

 

getopts 将解析选项和它们可能的参数。它将在第一个非选项参数(不以连字符“-”开头的,且不是它前面的任何选项的参数的字符串)的位置停止解析。当遇到双连字符“--”(表示选项的结束)时,它也将停止解析。

getopts 会使用到如下 3 个变量:

  • OPTIND:存放下一个要处理的参数的索引。这是 getopts 在调用过程中记住自己状态的方式。同样可以用于移位使用 getopts 处理后的位置参数。OPTIND 初始被设置为 1,并且如果你想再次使用 getopts 解析任何内容,都需要将其重置为 1;
  • OPTARG:这个变量被设置为由 getopts 找到的选项所对应的参数;
  • OPTERR:它的值为 0 或者 1。指示 Bash 是否应该显示由 getopts 产生的错误信息。在每个 Shell 启动时,它的值都被初始化为 1。如果我们不想看到烦人的信息,可以将它的值设置为 0。

getopts 命令的基本语法:

getopts OPTSTRING VARNAME [ARGS...]
  • OPTSTRING:告诉 getopts 会有哪些选项和在哪会有参数;
  • VARNAME:告诉 getopts 哪个变量用于选项报告;
  • ARGS:告诉 getopts 解析这些可选的参数,而不是位置参数。

例如,如下的命令告诉 getopts 查找 -f、-A 和 -x 选项:

getopts fAx VARNAME

而下面的命令告诉 getopts -A 选项后面会有一个参数:

getopts fA:x VARNAME

默认情况下 getopts 命令是解析当前 Shell 或函数的位置参数。我们可以指定自己的参数让 getopts 来解析。一旦额外的参数指定在了 VARNAME 之后,getopts 将不再尝试解析位置参数,而是解析这些额外指定的参数。

getopts 命令还支持两种错误报告的模式,分别为:详细错误报告模式和抑制错误报告模式。对于产品中的脚本,推荐使用抑制错误报告模式,因为这样看起来更专业,不会看到恼人的标准信息。同样它也更容易处理,因为我们以更简单的方法显示了失败的情况。

在详细错误报告模式下,如果 getopts 遇到了一个无效的选项,VARNAME 的值会被设置为问号(?),并且变量 OPTARG 不会被设置;如果需要的参数没有找到,VARNAME 的值同样会被设置为问号(?),变量 OPTARG 也不会被设置,并且会打印一个错误信息。

在抑制错误报告模式下,如果 getopts 遇到了一个无效的选项,VARNAME 的值会被设置为问号(?),并且变量 OPTARG 会被设置为选项字符;如果需要的参数没找到,VARNAME 的值同样会被设置为冒号(:),并且变量 OPTARG 中会包含选项字符。

#安全CP实现
while getopts ":adpfiRr" opt
do
    case $opt in
        a)
            echo "option a"
            exit 
            ;;
    esac
    case $opt in
        ?)
            ;;
    esac
done

#移动到参数位置
shift $[ $OPTIND -1  ]    

#处理参数
while [ $# -gt 1 ]
do
    src="${src} $1"
    shift 
done
dst=$1

3. 使用 getopt 处理多命令行选项

getopt 命令与 getopts 的功能很相似,也是用于解析命令行的选项和参数,使其可以被 Shell 程序简单地解析。不同的是,getopt 命令是 Linux 下的命令行工具,并且 getopt 支持命令行的长选项(比如,--some-option)。另外,在脚本中它们的调用方式也不同。getopt 的语法类似如下:

getopt [options] [--] optstring parameters
getopt [options] -o|--options optstring [options] [--] parameters

下面是一个示例:

$ getopt f:vl -vl -f/local/filename.conf param_1
-v -l -f /local/filename.conf -- param_1

上例中,“f:vl” 对应 getopt 命令语法中的 optstring(选项字符串),“-vl -f/local/filename.conf param_1” 对应 getopt 命令语法中的 parameters(getopt 命令的参数)。因此,getopt 会按照 optstring 的设置,将 parameters 解析为相应的选项和参数。所以,“-vl” 被解析为了 “-v” 和 “-l”。与 getopts 类似,因为在选项字符串中 “f” 后有一个冒号(:),所以 “-f/local/filename.conf” 被解析为 “-f /local/filename.conf”。然后解析后的命令行选项和参数之间使用双连字符(--)分隔

tgt_flag=false

#增加了eval后,选项参数可用,否则参数为‘param’形式
eval set -- `getopt -o t:S:Z:: -l target:,backup::,suffix:,preserve::,reflink::,sparse:,no-preserve:,context:: -- "$@" 2>/dev/null`>/dev/null 2>&1 

while [ $# -gt 0 ]
do
	case $1 in
		-t|--target)
			tgt_flag=true
			dst=$2
			shift 2
			;;
			#必接参数的,偏移2位
			-S|--no-preserve|--sparse|--suffix)
			shift 2
			;;
		?)
			shift
			;;
#--表示选项结束,剩下的是参数。
		--)
			shift
			break
			;;
	esac
done

if ${tgt_flag}
then
	src=$*
else
	while [ $# -gt 1 ]
	do
		src="${src} $1"
		shift 
	done
	dst=$1
fi

 

getopt 命令遵循如下规则:

  • 每一个字符代表一个选项;
  • 字符后跟一个冒号(:)表示选项需要一个参数;
  • 字符后跟两个冒号(::)表示选项有个可选参数。
  • -o表示短选项,两个冒号表示该选项有一个可选参数,可选参数必须紧贴选项,如-carg 而不能是-c arg
  • -l 或者 --long表示长选项
  • 命令行选项和参数之间使用双连字符(--)分隔。
  • man getopt

 

 

 

 

你可能感兴趣的:(Linux,C语言,shell)