zl程序教程

您现在的位置是:首页 >  后端

当前栏目

shell脚本命令行参数 | while getopts

命令行shell 参数 脚本 while
2023-09-27 14:28:31 时间

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

参数列表':a:b:c:h 解释:

  • OPTARG表示选项值,OPTIND表示参数索引位置。
    • 输入命令 cmd -a 1。 此时命中a选项,那么OPTIND为3,表示当前在第三个参数位置。
    • 命令cmd -a 1 -b 2 。同理,当命中a之后,命中b时,OPTIND为5,表示当前在第五个参数位置。
  • a后面有:,表示该选项需要参数,h后面没有:,表示不需要参数。如果是可选参数,跟 “::” 。

注意

  • 这里第一个:表示,使用抑制错误报告模式。
    • 该模式在识别到无效选项时,会命中?,且当前选项字符会保存在OPTARG中。
    • 在识别到需要参数的选项,没有携带参数时,会命中:,且当前选项字符会保存在OPTARG中。
逻辑参数:参数列表【abc:d:】
- copy -x 
	- 命中“?”, OPTARG被设置为x
- copy -c 	# 没有指定c的参数
	-  命中 “:”,OPTARG被设置为c

程序演示:
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 )
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 参数,用户手动确认会对目录进行拷贝时,才进行该操作)
在这里插入图片描述