Shell 脚本小记1

Posted hebbely

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Shell 脚本小记1相关的知识,希望对你有一定的参考价值。

简述:

        收集一些常用或实用的命令。

目录

1. getopt 命令

1.1 getopt 选项

1.2  getopt如何解析选项和参数

1.3 处理getopt解析的结果

2. case in esac 命令

2.1 case in esac 格式:

2.2 case in esac格式说明

2.3 case in 和正则表达式

2.4 case in 样例

3. shift 命令

4. eval 命令

4.1 eval可回显简单的变量

4.2 eval 执行含有字符串的命令

4.3 eval 显示最后一个参数


1. getopt 命令

        写shell脚本时,通过whilecaseshift来设计脚本的命令行选项是一件比较麻烦的事,因为Unix命令行的选项和参数自由度很高,支持短选项长选项,参数可能是可选的,选项顺序可能是无所谓的,等等。

bash下的getopt命令可以解析命令行的选项和参数,将散乱自由的命令行选项和参数进行改造,得到一个完整的、规范化的参数列表,这样再使用whilecaseshift进行处理就简单的太多了。

getopt有不同的版本,本文介绍的是它的增强版(enhanced),相比传统的getopt(也称为兼容版本的getopt),它提供了引号保护的能力。另外,除了不同版本的getopt,bash还有一个内置命令getopts(注意,有个尾随的字符s),也用来解析命令行选项,但只能解析短选项

要验证安装的getopt是增强版还是传统版,使用getopt -T判断即可。如果它什么都不输出,则是增强版,此时它的退出状态码为4。如果输出"--",则是传统版的getopt,此时它的退出状态码为0

        bash的getopt命令经常用在shell脚本内部函数内部,用来解析脚本执行或函数执行时传递的选项、参数

1.1 getopt 选项

        下面这个是最常用的getopt解析方式

    getopt -o SHORT_OPTIONS -l LONG_OPTIONS -n "$0" -- "$@"

        其中:

选项说明
-o SHORT_OPTIONS通过"-o"选项收集命令行传递的短选项和它们对应的参数
--options SHORT_OPTIONS
-l LONG_OPTIONS通过"-l"选项收集命令行传递的长选项和它们对应的参数
--longoptions LONG_OPTIONS
-n NAME

在解析命令行时,如果解析出错将会报告错误信息,

getopt将使用该NAME作为报错的脚本名称

-- "$@"

--” 表示getopt命令自身的选项到此结束,后面的元素都是要

被getopt解析的命令行参数。这里使用"$@",表示所有的命令

行参数。注意,不能省略双引号

1.2  getopt如何解析选项和参数

        getopt使用"-o""-l"解析短、长选项和参数时,将会对每个解析到的选项、参数进行输出,然后不断放进一个字符串中。这个字符串的内容就是完整的、规范化的选项和参数。

使用"-o"选项解析短选项

多个短选项可以连在一起

若选项需要一个参数,则在选项名后面跟一个冒号
若选项的参数可选,则在选项名后面跟两个冒号

例如,getopt -o ab:c::中,将解析为-a -b arg_b -c [arg_c]参数arg_b-b选项必须的,参数arg_c-c选项可选的参数,"-a"选项无需参数
 

使用"-l"选项解析长选项

可以一次性指定多个选项名称,需要使用逗号分隔它们

可以多次使用-l选项,多次解析长选项

若选项需要一个参数,则在选项名后面跟一个冒号

若选项的参数可选,则在选项名后面跟两个冒号

例如,getopt -l add:,remove::,show中,将解析为--add arg_add --remove [arg_rem] --show,其中参数arg_add--add选项必须的,--remove选项的参数arg_rem可选的,--show无需参数

1.3 处理getopt解析结果

        getopt解析得到了完整规范化的结果,当然要拿来应用。例如直接传递个函数,或者根据while、case、shift将选项、参数进行分割单独保存。

        如果要进行分割,由于getopt的解析结果通常保存在一个变量中,要解析这个结果字符串,需要使用eval函数将变量的内容进行还原,一般来说会将其设置为一个位置参数(因为shift只能操作位置变量)。

        一般来说,整个处理流程是这样的:

parameters=$(getopt -o SHORT_OPTIONS -l LONG_OPTIONS -n "$0" -- "$@")
[ $? != 0 ] && exit 1
eval set -- "$parameters"   # 将$parameters设置为位置参数
while true ; do             # 循环解析位置参数
    case "$1" in
        -a|--longa) ...;shift ;;    # 不带参数的选项-a或--longa
        -b|--longb) ...;shift 2;;   # 带参数的选项-b或--longb
        -c|--longc)                 # 参数可选的选项-c或--longc
            case "$2" in 
                "")...;shift 2;;  # 没有给可选参数
                *) ...;shift 2;;  # 给了可选参数
            esac;;
        --) ...; break ;;       # 开始解析非选项类型的参数,break后,它们都保留在$@中
        *) echo "wrong";exit 1;;
    esac
done

         需要注意,getopt解析既可以放在脚本中解析命令行参数,也可以放在某个函数中解析函数参数。

        样例1.1

show_usage="args: [-s -p]\\
           	[--src-path=,--project-name=]"
explain="-s, --src-path: 原路径\\n\\
	-p, --project-name: 软件程序名称\\n\\
	-h, --help: 帮助"

SrcPath=""
ProjectName=""

GETOPT_ARGS=`getopt -o s:p:h -al src-path:,project-name:,help -- "$@"`
eval set -- "$GETOPT_ARGS"

while [ -n "$1" ]
do
        case "$1" in
                -s|--src-path) SrcPath=$2; shift 2;;
                -p|--project-name) ProjectName=$2; shift 2;;
                -h|--help) echo $show_usage; echo -e $explain; exit 0; break ;;
                *) break ;;
        esac
done

2. case in esac 命令

2.1 case in esac 格式:

case expression in
	pattern 1)
		statement1
		;;
	pattern 2)
		statement2
		;;
……
	*)
		statementn
esac	

2.2 case in esac格式说明

        1> casein esac 都是 Shell 关键字,expression 表示表达式,pattern 表示匹配模式

                a. expression 既可以是一个变量、一个数字、一个字符串,还可以是一个数学计算表达式,或者是命令的执行结果,只要能够得到 expression 的值就可以。

                b. pattern 可以是一个数字、一个字符串,甚至是一个简单的正则表达式

        2> case 会将 expression  的值与 pattern1pattern2pattern3 逐个进行匹配

                如果 expression 和某个模式(比如 pattern2匹配成功,就会执行这模式(比如 pattern2)后面对应的所有语句(该语句可以有一条,也可以有多条),直到遇见双分号;;才停止;然后整个 case 语句就执行完了,程序会跳出整个 case 语句,执行 esac 后面的其它语句。
如果 expression 没有匹配任何一个模式,那么就执行*)后面的语句(*表示其它所有值),直到遇见双分号;;或者esac才结束。*)相当于多个 if 分支语句中最后的 else 部分。

        3> 对*)的几点说明:

        *)部分可以省略,*)部分主要用于在 expression 没有匹配到任何一个模式时做一些“善后”工作,或者给用户一些提示。

        注:除最后一个分支外(这个分支可以是普通分支,也可以是*)分支),其它的每个分支都必须以;;结尾,;;代表一个分支的结束,不写的话会有语法错误。最后一个分支可以写;;,也可以不写,因为无论如何,执行到 esac 都会结束整个 case in 语句。

2.3 case in 和正则表达式

        case in 的 pattern 部分支持简单的正则表达式,具体来说,可以使用以下几种格式:

格式说明
表示任意字符串
[abc]表示a、b、c三个字符中的任意一个
[m-n]  表示从m到n的任意一个字符
[0-9]表示0-9的任意一个数字
[0-9a-zA-Z]表示任意数字或字母
|表示多重选择,类似逻辑运算中的或运算
abc|xyz 表示abc或者xyz

2.4 case in 样例

        样例2.1:

#!/bin/bash
echo "Input a character: "
read -n 1 char
# 如果此处需要用echo输出的话就不能用read -n 1 因为没有用户输入数据完成后是没有换行符的
# -n 1 表示只读取一个字符,运行脚本后 只要用户输入一个字符 立即读取结束 不用等用户按下回车键
# 解决方法:在echo语句中手动添加换行符
case $char in
	[a-zA-Z])
	echo -e "\\nletter"
	;;
	[0-9])
	echo -e "\\ndigit"
	;;
	[.,?!@])
	echo -e "\\npunctuation"
	;;
	*)
	echo -e "\\nerror"
esac

        echo -n 不换行输出

        echo -e 处理特殊字符

        若字符串中出现以下字符,则特别加以处理,而不会将它当成一般文字输出:

    \\a 发出警告声;
    \\b 删除前一个字符;
    \\c 最后不加上换行符号;
    \\f 换行但光标仍旧停留在原来的位置;
    \\n 换行且光标移至行首;
    \\r 光标移至行首,但不换行;
    \\t 插入tab;
    \\v 与\\f相同;

        样例2.2:

while [ -n "$1" ]
do
        case "$1" in
                -s|--src-path) SrcPath=$2; shift 2;;
                -p|--project-name) ProjectName=$2; shift 2;;
                -h|--help) echo $show_usage; echo -e $explain; exit 0; break ;;
                *) break ;;
        esac
done

3. shift 命令

        位置参数可以用shift命令左移。比如shift 3表示原来的$4现在变成$1,原来的$5现在变成$2等等,原来的$1、$2、$3丢弃$0不移动。不带参数的shift命令相当于shift 1

        样例请参考样例2.2,样例1.1

4. eval 命令

        当我们在命令行前加上eval时,shell就会在执行命令之前扫描两次。eval命令将首先会先扫描命令行进行所有的置换,然后再执行该命令。该命令适用于那些一次扫描无法实现其功能的变量。该命令对变量进行两次扫描

4.1 eval回显简单的变量

root@ubuntu:~# val=10
root@ubuntu:~# echo $val
10
root@ubuntu:~# eval echo $val
10
root@ubuntu:~# 

        这样和普通的没有加eval关键字的命令的作用一样。

4.2 eval 执行含有字符串的命令

root@ubuntu:~# cat file
hello shell
welcome to beijing
root@ubuntu:~# myfile="cat file"
root@ubuntu:~# echo $myfile
cat file
root@ubuntu:~# eval $myfile
hello shell
welcome to beijing
root@ubuntu:~# 

        由上可知,直接echo $myfile的内容将不会输出file文件里面的文本。当用eval $myfile命令后,就会输出file文件里面的文本。因为eval命令不但可以置换该变量,还能执行相应的命令。在第一次扫描中进行了变量置换第二次扫描就执行了该变量所包含的字符串里面的cat file 命令,所以就输出file文件里面的文本了。

4.3 eval 显示最后一个参数

root@ubuntu:~# set -- hello shell
root@ubuntu:~# eval "echo \\$$#"
shell
root@ubuntu:~# 

参考:

        设计shell脚本选项:getopt
    
 
    
    
    
   

以上是关于Shell 脚本小记1的主要内容,如果未能解决你的问题,请参考以下文章

Shell 脚本小记1

shell脚本使用小记

shell脚本使用小记

Linux shell 脚本小记2

shell expect spawnlinux expect 用法小记 看着舒服点

expect spawnlinux expect 用法小记