天天看点

Linux下Shell脚本命令行参数:getopt、getopts用法简介getopt简介支持选项用法getopts

目录

简介

getopt

简介

支持选项

用法

getopt optstring parameters

getopt [options] [--]

 getopt [options] -o|--options [options] [--]

在shell中使用它

getopts

简介

简介

我们通常在编写shell脚本时简单的方式是通过参数的方式来取到我们想要的参数,如:

#!/bin/bash
 
SYSCODE=$1
APP_NAME=$2
MODE_NAME=$3
           

但是这有一个问题,就是参数的位置是固定的,倘若用户在调用脚本时参数位置不固定那么就会出现问题,这种方法一般只适用于一两个参数的情况,我们可以使用更高阶的方案,在Linux中提供了两个命令:getopt与getopts,getopts是getopt更高阶的命令,我们先从最简单的介绍,先从getopt开始介绍

getopt

简介

getopt是linux下一个用于解析选项参数的命令行工具

支持选项

选项名 作用
-a, --alternative 允许长选项以 - 开始
-h, --help 用法指南
-l, --longoptions <长选项> 要识别的长选项
-n, --name <程序名> 将错误报告给的程序名
-o, --options <选项字符串> 要识别的短选项
-q, --quiet 禁止 getopt(3)的错误报告
-Q, --quiet-output 无正常输出
-s, --shell <shell> 设置 shell 引用规则
-T, --test 测试 getopt(1) 版本
-u, --unquoted 不引用输出
-V, --version 输出版本信息

用法

getopt optstring parameters

示例:

$ getopt abcd -a -b -c -d
-a -b -c -d --
           

上面的abcd每一个单词都视为一个短命令,getopt会拆分成:a、b、c、d

$ getopt abcd -a -b -c -d -h
getopt: invalid option -- 'h'
 -a -b -c -d --
           

如果我们期望某个选项需要一个输入值,那么可以在这个选项的后面加上":"

示例:

$ getopt ab:cd -a -b this -c -d
 -a -b this -c -d --
           

可以看到b后面跟了一个:符号,这个符号的作用是代表这个选项是一个需要输入值的选项,如果不给就会报错:

$ getopt ab:cd -b
getopt: option requires an argument -- 'b'
 --
           

需要注意如果你没有给这个选项一个参数的情况下后面跟了一个选项,那么这个选项会被视为参数:

$ getopt ab:cd -b -d
 -b -d --
           

也就是说当你这个选项定义为需要输入参数时它会读取这个选项空格后的一个字符串,以空格分隔作为它的输入参数

如果你想这个选项可有输入值也可以没有输入值那么可以使用"::"符号

$ getopt ab::cd -b
 -b  --
           

getopt [options] [--] <optstring> <parameters>

示例:

$ $ getopt -q -- abcd -a -b -c -d -e
 -a -b -c -d --
           

上面示例示范了一个-q选项,禁止getopt产生错误报告,可以看到-e并不存在于我们定义的短命令之中,但是这次它没有报错,当然我们也可以使用-n来改变报错文件名:

getopt -n test.sh -- abcd -a -b -c -d -e
test.sh: invalid option -- 'e'
 -a -b -c -d --
           

可以看到出错的文件名从getopt变成了test.sh

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

示例:

getopt -q -o abcd -l arg1,arg2,arg3 -- -a -b -c --arg1 --arg2 --arg3
 -a -b -c --arg1 --arg2 --arg3 --
           

这种方案是可以使用多个选项组合,这里我们也使用了长选项

需要值得注意的是,长命令是使用","符号分割的,并且在给选项时需要使用"--"

长选项包含输入值的方法如下:

$ getopt -o abcd -l arg1:,arg2::,arg3 -- -a -b -c --arg1 test --arg2 --arg3
 -a -b -c --arg1 'test' --arg2 '' --arg3 --
           

与短命令一样使用的是":"符号

同时可以看到输出后面跟了--,--后面的代表的是没有被绑定的参数选项,比如:

$ getopt -o abcd -l arg1:,arg2::,arg3 -- -a -b -c --arg1 test --arg2 --arg3 test111
 -a -b -c --arg1 'test' --arg2 '' --arg3 -- 'test111'
           

可以看到我们增加了一个没有任何意义的参数值,test111,它被输出到了--符号的后面,最终我们解析时可以通过解析--后面的字符串来取到一些信息来做响应的操作

当然你也可以主动使用--来让后面的字符变成特殊参数:

$ getopt -o abcd -l arg1:,arg2::,arg3 -- -a -b -c --arg1 test --arg2 --arg3 -t
getopt: invalid option -- 't'
 -a -b -c --arg1 'test' --arg2 '' --arg3 --
           

可以看到-t报错了,因为没有这个短命令,但是如果我们主动使用--就会把它变成特殊参数:

$ getopt -o abcd -l arg1:,arg2::,arg3 -- -a -b -c --arg1 test --arg2 --arg3 -- -t
 -a -b -c --arg1 'test' --arg2 '' --arg3 -- '-t'
           

在shell中使用它

先来看一段简单的代码示例:

#/bin/bash
set -- $(getopt ab:cd "$@")
while [ -n "$1" ]
do
  case "$1" in
  -a) echo "Found the -a option";;
  -b) par="$2"
      echo "Found the -b option,par = $par"
      shift;;
  -c) echo "Found the -c option";;
  -d) echo "Found the -d option";;
  --) shift
      break ;;
   *) echo "$1 is not option";;
esac
        shift
done

count=1
for param in "$@"
do
  echo "Parameter #$count: $param"
  count=$[ $count + 1 ]
done
           

这里一步一步解释一下上面每段代码的含义,首先第一段代码:

set -- $(getopt ab:cd "$@")
           

学过shell的都知道,在shell里简单的参数变量可以通过如下方式获取:

at = $1
           

上面的--符号就是将getopt的输出按空格为分割顺序替换到这个里面去,$@符号是代表输入参数字符串

如:

$ form.sh -a -b -c
           

其中的-a -b -c会在进入shell的时候写入到@这个变量里去了,然后我们在将它取出作为getopt的参数执行一次,然后在替换到$1、$2里面去

-a -b -c 就等于:$1、$2、$3

如下这段代码也比较简单:

while [ -n "$1" ]
do
  case "$1" in
  -a) echo "Found the -a option";;
  -b) par="$2"
      echo "Found the -b option,par = $par"
      shift;;
  -c) echo "Found the -c option";;
  -d) echo "Found the -d option";;
  --) shift
      break ;;
   *) echo "$1 is not option";;
esac
        shift
done
           

这段代码就是使用了while、case、shift的方式来实现的

首先刚刚执行set指令之后-a、-b、-c已经顺序写入到$1、$2里了,我们这里是先判断$1是否为空,用-n指令来判断,如果为空则逻辑false,那么就会跳出while

while [ -n "$1" ]
           

case的特性是匹配到一次之后会自动跳转到esac里,而shift的特性是将参数向前挪移一步,如:

$1、$2、$3,执行一次shift指令之后会将2、3向前挪移,2变成1,3变成2,而1会被丢弃

然后case会根据字符串)来比对,如果通用可以用*

然后在--符号里跳出,这个是因为最开始我们说过,一些特殊参数会被getopt输出到--后面,所以当遇到--的时候代表已经到了选项尾部了,那么挪移一步并跳出去

case "$1" in
  -a) echo "Found the -a option";;
  -b) par="$2"
      echo "Found the -b option,par = $par"
      shift;;
  -c) echo "Found the -c option";;
  -d) echo "Found the -d option";;
  --) shift
      break ;;
   *) echo "$1 is not option";;
esac
        shift
           

当跳出去之后来到了这里:

count=1
for param in "$@"
do
  echo "Parameter #$count: $param"
  count=$[ $count + 1 ]
done
           

那么这里我们就可以去取到所有的参数了,这里利用了for in的方式去把@里的数据看作为列表,然后去取,在for里如果是字符串则按空格作为分割,然后取到以后输出就可以了

这里的跳两次是为了把输入值跳出去:

-b) par="$2"
      echo "Found the -b option,par = $par"
      shift;;
           

如-a test,那么执行shift之后test就位于$1了,显然这是不对的,因为test是输入值,所以这里shift一次之后在esac里在shift一次就是两次,就跳过了输入值

最终执行结果:

$ ./form.sh -a -b test fassfa -c -d fwqgqwg
Found the -a option
Found the -b option,par = test
Found the -c option
Found the -d option
Parameter #1: fassfa
Parameter #2: fwqgqwg
           

getopts

简介

getopts不同于getopt,它没有提供那么多选项,也没有那么多种用法,它只有一种用法:getopts option_string variable ,且它是专门为shell提供的,并且它更加的灵活,先来看一段简单的代码示例:

#!/bin/bash

while getopts "a:" opt; do
  case $opt in
    a)
      echo "this is -a the arg is ! $OPTARG"
      ;;
    \?)
      echo "Invalid option: -$OPTARG"
      ;;
  esac
done
           

运行输出:

$ ./form.sh -a hello
this is -a the arg is ! hello
           

与之前的getopt对比是不是变得更加简洁了?我们不需要去使用set命令以及shift命令了,这些getopts会为我们做好,它会自动去读输入参数,同时在执行的时候会产生两个变量:

OPTIND 和 OPTARG,OPTIND为下一个要处理的参数索引,当调用getopts时如果发现OPTIND索引处的选项有输入值则设置OPTARG并返回true即便没有输入值若索引处存在选项也会返回true,同时为OPTIND递增1,这也是为什么它一般用在while的原因

OPTIND在最初shell就会设置这个值,它不是getopts设置的,而是shell为了支持getopts而在最初就会设置它

while getopts "a:" opt; do
           

这段代码也很简单,这里就是对opt作为列表进行遍历,opt在shell里为参数列表,同理你不使用getopt说这些你用opt也是一样可以实现选项功能的:

#!/bin/bash
echo "opt:" ${opt}
for opt; do
    case $opt in
      a)
         echo "a "
         ;;
      b)
         echo "b "
         ;;
       *)
         echo "other " 
         ;;
     esac
done
           

同时getopts里是没有-q选项的,如果你想屏蔽错误则可以在选项字符串的前面加上:

#!/bin/bash

while getopts ":a:" opt; do
  case $opt in
    a)
      echo "this is -a the arg is ! $OPTARG"
      ;;
    \?)
      echo "Invalid option: -$OPTARG"
      ;;
  esac
done
           

当你在前面加上:之后当你输入没有注册的选项时也不会报错,如果没有则会产生一个错误并设置输出符号为\?,同时OPTARG就会设置为错误选项

最后补充一点,case里也是支持|符号的,比如:-a|-b)这样的方式,如果是-a或者-b都执行这条指令

继续阅读