shell脚本命令行参数 | while getopts

bash内置的getopts工具了,用于解析shell脚本中的参数。

一、格式如下

# 代码格式参考的这篇文章:https://cloud.tencent.com/developer/article/1629932
#!/usr/bin/bash
while getopts ":a:b:h" opt_arg
do
    case "$opt_arg" in
      "a")
        echo "参数 -a,值 $OPTARG"
        ;;
      "b")
        echo "参数 -b ,值 $OPTARG"
        ;;
      "h")
        echo "参数 -h,无值"
        ;;
      ":")
        echo "-$OPTARG 选项需要指定其value值"
        ;;
      "?")
        echo "不支持 -$OPTARG 选项"
        ;;
      *)
        echo "Unknown error while processing options"
        ;;
    esac
    echo "option index is $OPTIND"
done

二、执行结果

三、参数解释

while getopts ":a:b:h",此时在 shell 界面,就可以指定给 a 或者 b 或者c 单独或者同时赋值,如while_getopt_1 -a 1 -b 2 -h 3,在 shell 中 a = 1  b = 2  c = 3

while getopts ":a:b:h" opt_arg  将 opt_arg 接收 a 或者 b 或者 c ,随后通过 case 去匹配

case "$opt_arg" in
      "a")
        echo "参数 -a,值 $OPTARG"
        ;;
      "b")

3.1、其他参数解释:

  • OPTARG 表示选项值

    ○ case "$opt_arg" in
          "a")
           echo "参数 -a,值 $OPTARG"
        比如匹配上了a参数,此时$OPTARG 就是参数 a 的数值,也就是sh while_getopt_1 -a 1  中的 1

  • OPTIND 表示参数索引位置

    ○ 输入命令 cmd -a 1。 此时命中a选项,那么OPTIND为3,表示当前在第三个参数位置。
    ○ 命令cmd -a 1 -b 2 。同理,当命中a之后,命中b时,OPTIND为5,表示当前在第五个参数位置。

  • a后面有:,表示该选项需要参数,h后面没有:,表示不需要参数。如果是可选参数,跟 “::” 。

3.2、注意

  • 这里第一个:表示,使用抑制错误报告模式

    ○ 该模式在识别到无效选项时,会命中?,且当前选项字符会保存在OPTARG中。
    ○ 在识别到需要参数的选项,没有携带参数时,会命中:,且当前选项字符会保存在OPTARG中。

逻辑参数:参数列表【abc:d:】
- copy -x 
	- 命中“?”, OPTARG被设置为x
- copy -c 	# 没有指定c的参数
	-  命中 “:”,OPTARG被设置为c
  • 如果输入未知参数,比如 -d 在shell 中没有定义,会匹配 "?") 或者 *) ,具体匹配谁看谁在第一位

  • 参数中出现正确、和未知的参数,比如 sh while_getopt_1 -a 1 -d 3 ,其中 -d 是未知参数,那 -a 执行还是不执行,回答是-a 是执行的,shell 是按照循序执行的,故 -d 3 之前没发生错误,-a 执行,但如果是 -d 3 -a 1 ,则一开始就未知,后续 while getopts  都不会执行,但 while getopts 外还是会执行,除非在  while getopts 中增加 exit 1 或者 break 

[root@master02 bash_scritp]# cat while_getopt_1
#!/bin/bash

yanzheng1 (){
    echo "yanzheng1"
}

yanzheng (){
   echo "yanzheng"
}

while getopts :a:b:h: opt_arg
do
    case $opt_arg in
      a)
        echo "参数 -a,值 $OPTARG"
        REDIS_NODES=(${OPTARG//;/ })
        yanzheng;
        ;;
      b)
        echo "参数 -b ,值 $OPTARG"
        ;;
      h)
        echo "参数 -h,无值"
        ;;
      *)
        echo "Unknown error while processing options 111"
        ;;
      :)
        echo "-$OPTARG 选项需要指定其value值"
        ;;
      ?)
        echo "不支持 -$OPTARG 选项"
        ;;
    esac
    echo "option index is $OPTIND"
done

echo "nihao"


[root@master02 bash_scritp]# sh while_getopt_1 -a 1
参数 -a,值 1
yanzheng
option index is 3
nihao
yanzheng1

[root@master02 bash_scritp]# sh while_getopt_1 -b 2
参数 -b ,值 2
option index is 3
nihao
yanzheng1

[root@master02 bash_scritp]# sh while_getopt_1 -d 3 -a 1
Unknown error while processing options 111
option index is 2
nihao
yanzheng1
[root@master02 bash_scritp]# sh while_getopt_1 -a 1 -d 3
参数 -a,值 1
yanzheng
option index is 3
Unknown error while processing options 111
option index is 4
nihao
yanzheng1
[root@master02 bash_scritp]#

  • 遇到未知参数的后,立马退出,不进行执行整个shell
            exit 1

[root@master02 bash_scritp]# cat while_getopt_1
#!/bin/bash

yanzheng1 (){
    echo "yanzheng1"
}

yanzheng (){
   echo "yanzheng"
}

while getopts :a:b:h: opt_arg
do
    case $opt_arg in
      a)
        echo "参数 -a,值 $OPTARG"
        REDIS_NODES=(${OPTARG//;/ })
        yanzheng;
        ;;
      b)
        echo "参数 -b ,值 $OPTARG"
        ;;
      h)
        echo "参数 -h,无值"
        ;;
      *)
        echo "Unknown error while processing options 111"
        exit 1
        ;;
      :)
        echo "-$OPTARG 选项需要指定其value值"
        ;;
      ?)
        echo "不支持 -$OPTARG 选项"
        ;;
    esac
    echo "option index is $OPTIND"
done

echo "nihao"

yanzheng1;


[root@master02 bash_scritp]# sh while_getopt_1 -d 3 -a 1
Unknown error while processing options 111
[root@master02 bash_scritp]#

四、程序演示

1.正常输出所有值:

2.不带选项。注意这里不带选项是检测不到的。可以利用这个特性,实现省略选项直接使用命令的功能。

3.不在参数列表的选项,命中“?”

4.需要参数的选项没有带参数,命中“:” 

 

除此之外,还可以使用长参数。跟高级的用法可以参考此文章:https://www.cnblogs.com/f-ck-need-u/p/9758075.html

五、实战演练

写一个从安卓手机上传文件到pc上的脚本。代码参考如下:

#!/bin/bash

srcPath=/sdcard/DCIM/Camera/
srcFile=$(adb shell ls -ltr $srcPath | tail -n 1 | tr ' ' '\n' | tail -n 1 ) # adb可以轻松的执行Linux Shell命令,如adb shell dir 就是列举目录,在Linux中根目录为/而不是Windows上的C盘、D盘。具体看 https://blog.csdn.net/Jerry00713/article/details/129775730
dstPath=$(pwd)/
dstFile=
bool=false		# 是否使用了opt参数。没使用就走默认流程
is_opt_r=false	# 是否开启递归,这表示拷贝的可能是个目录文件

# 输出提示内容的字符串
Helper(){
    echo "使用说明:"
    echo "    -f 指定源文件名(安卓/sdcard/DICM/目录下)"
    echo "    -F 指定源文件的路径(不能与-f 一起使用)"
    echo "    -o 指定存放的文件名(PC当前脚本所在目录下)"
    echo "    -O 指定存放文件的路径(不能与-O 一起使用)"

	echo -e "\n示例参考:"
    echo -e "  ./copy \t\t\t拷贝 /sdcard/DICM/ 目录下最新生成的文件 到当前脚本所在目录 "
    echo -e "  ./copy -f xxx.png \t\t拷贝 /sdcard/DICM/xxx.png 文件     到当前脚本所在目录 "
    echo -e "  ./copy -F /aaa/bbb/xxx.png \t拷贝 /aaa/bbb/xxx.png 文件      到当前脚本所在目录 "
    echo -e "  ./copy -o file \t\t拷贝 /sdcard/DICM/ 目录下最新生成的文件 到当前脚本所在目录【命名为file】 "
    echo -e "  ./copy -O /ccc/ddd/file \t拷贝 /sdcard/DICM/ 目录下最新生成的文件 到当前脚本所在目录"

    echo -e "\n建议使用以下两种格式:"
    echo "  eg1: ./copy -f 1.png -o file_1.png"
    echo "  eg2: ./copy -F sdcard/DCIM/1.png -O /Users/rt/Desktop/file_1.png"
}
Param_error(){	# 参数互斥
	echo "参数错误:请检查参数列表"
	echo "	-f 与 -F 不能同时使用。"
	echo "	-o 与 -O 不能同时使用。"
	exit
}


# f与F互斥,不能同时用
or_op_f=`echo "$*" | grep -Eo '\-f | \-F ' | wc -l`
[ "$or_op_f" -eq 2 ] && Param_error

# o与O互斥,不能同时用
or_op_o=`echo "$*" | grep -Eo '\-o | \-O ' | wc -l`
[ "$or_op_o" -eq 2 ] && Param_error


while getopts ":f:F:o:O:rh" opt_arg
do
	bool=true
    case "$opt_arg" in
      "f")
		  srcFile=$OPTARG
		  #echo "set | srcFile name : $srcFile"
        ;;
      "F")
		  srcPath=""
		  srcFile=$OPTARG
		  #echo "set | srcPath/srcFile name : $srcFile"
        ;;
      "o")
		  dstFile=$OPTARG
		  #echo "set | dstFile name : $dstFile"
        ;;
      "O")
		  dstPath=""
		  dstFile=$OPTARG
		  #echo "set | dstPath/dstFile name : $dstFile"
        ;;
      "r")
		  is_opt_r=true
        ;;
      "h")
		  Helper && exit
        ;;
      ":")
        echo "请添加$OPTARG的参数"
        ;;
      "?")
		  echo "参数错误!!"
        ;;
      *)
        echo "Unknown error while processing options"
        ;;
    esac
done

if [ "$bool" != "true" ]; then
	if [ -n "$1" ]; then
		secFile=$1
		if [ -n "$2" ]; then
			dstFile=$2
		fi
	fi
fi


# 检查安卓端源文件是否为目录
is_dir="$(adb shell [ -d "$srcPath$srcFile" ] && echo "true")"
# 源文件是否为目录
if [ "$is_dir" == "true" ] && [ "$is_opt_r" == "false" ]; then
  echo "error: $fsrcPath$srcFile 是一个目录"
  echo "    对目录操作,请使用 -r 参数,进行递归拷贝"
  exit
  
fi

echo "adb pull $srcPath$srcFile $dstPath$dstFile"
adb pull $srcPath$srcFile $dstPath$dstFile

执行:

在这里插入图片描述

 需要注意的是,如果源文件是一个目录我们应该怎样操作。(这里提供了 -r 参数,用户手动确认会对目录进行拷贝时,才进行该操作)

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值