Linux Shell笔记(2)

此篇博客主要讲述Shell中的参数解析和条件判断

shell中的参数解析

与在Linux中写其他程序一样,Shell脚本在执行时也是可以在命令行输入参数的,Shell中使用参数可以提高脚本运行的目的性和效率。参数解析的引入可以为Shell中的过程控制提供有效的条件判断方法。

先看看下面的例子:

#!/bin/bash
##FileName: argu.sh

echo "The total count of the argument is: "$#
echo -e "\nAll of the arguments are: "
for i in "$*"; do
	echo $i 
done
echo -e "\nThe sequence of the arguments is: "
for i in "$@"; do 
	echo $i
done

以上就是一个参数解析的例子,上面的Shell代码实现了计算参数个数、打印参数值、打印参数列表的功能,此Shell脚本的执行结果如下:

[shallwing@centos ~]$ bash argu.sh Baidu Alibaba Tencent Google Apple Microsoft       
The total count of the argument is: 6

All of the arguments are: 
Baidu Alibaba Tencent Google Apple Microsoft

The sequence of the arguments is: 
Baidu
Alibaba
Tencent
Google
Apple
Microsoft

在上面的脚本源码里:
$#表示参数的个数,上述例子里面,本人在命令行输入了6个参数,所以输出的$#的值是6;$i表示的是第i个参数的值,例如在上面的例子里,$3的值就是"Tencent";$*表示的所有参数连接构成一个字符串之后的值,上面的例子里面,$*的值是“Baidu Alibaba Tencent Google Apple Microsoft”;$@表示所有参数构成的一个参数序列,$*$@的区别正在于此,上面的例子里,$@的值便是序列“Baidu” “Alibaba” “Tencent” “Google” “Apple” “Microsoft” 。

脚本中的for是一个循环控制的语句,这个用法本人会在之后的博客中再次讲述,一般来说,用于for循环条件控制的是序列,而非单个的值,所以在实际脚本编写当中都是使用$@做条件控制,而非$*

Shell中参数解析的部分容易理解和上手。

Shell中的条件判断

Shell中的条件判断的关键字是if-else或case,与C语言中的if-else和case相似,但是其中多了很多的符号,并且使用时必须遵循特定的格式,Shell中的常用关系运算符如下:

  • 字符串比较的运算符
字符串比较运算符 含义
= 等于
!= 不等于
-z 判断字符串是否长度为0(is zero)
-n 判断字符串长度是否不为0(is not zero)
$ 判断字符串是否为空($[variable])
  • 仅可用于数字比较的运算符
数字关系运算符 含义
-gt 大于(greater than)
-lt 小于(littler than)
-eq 等于(equal)
-ne 不等于(not equal )
-ge 大于或等于(greater or equal)
-le 小于或等于(littler or equal)
  • 逻辑运算符
    shell中的逻辑运算符同C语言中的逻辑运算符一样,&&表示逻辑与,||表示逻辑或。

下面便是shell中条件判断的两个例子:

#!/bin/bash
##Filename=gussWhoami.sh

answer=`whoami`

if [ -z $1 ] ; then
    echo "gussWhoami.sh: Invalid argument -- 'empty'"
    echo "please input a name: 'gussWhoami.sh [NameString]'"
    exit
fi

if [ $answer = $1 ] ; then
    echo "You're right, my name is $1"
else
    echo "Sorry, I'm not $1"
fi

#end
#!/bin/bash
##FileName=numCompare.sh

null=

if [[ $1 = $null || $2 = $null ]] ; then
        echo "numCompare.sh: Invalid argument"
        echo "Please input two numbers."
        exit
fi

echo "num1=$1, num2=$2"

if [ $1 -eq $2 ] ; then
        echo "Num1 is equal to Num2."
fi
if [ $1 -lt $2 ] ; then
        echo "Num1 is litter than Num2."
fi
if [ $1 -gt $2 ] ; then
        echo "Num1 is greater than Num2."
fi

#end

第一个例子是用if-else完成字符串的比较,这个脚本里面需要用户自己输入一个姓名对应的字符串,然后再在系统中使用whoami的命令查看当前的用户的名字,完成输入的名字同当前用户名字的比较,也就是一个“猜猜我是谁”的简单shell游戏,其中的exit命令表示退出当前的shell脚本执行的进程

第二个例子就是用if-else完成数字的比较,脚本需要用户输入两个数字,然后来判断这两个数字谁大谁小,之后再打印出比较的结果。

以上的两个例子中明确的给出了if-else条件判断的写法:if后的条件语句要用中括号括起来,至于是使用双中括号还是单中括号的问题,在于变量的类型是否已经确定,但是用双中括号括起来是绝对正确的,实际情形中也是这样操作的;条件判断语句之后,紧跟着一条套用的语句 “;then”,这也是必不可少的,then之后就是一条条的命令语句,当命令语句写完之后,一定要加上一个fi(if的倒序写法),表示条件判断流程的结束

case型的条件判断语句同C语言中的使用的情形是一样的,主要用于多分支的条件判断,以下便是case型条件判断的一个例子:

#!/bin/bash
##FileName=score.sh

judge="The range of this score is in grade "

echo "Please input a student's score:"

read score

if [[ $score -lt 0 || $score -gt 100 ]] ; then 
	echo "The student score must in range [0,100]."
	echo "Fail to judge the score grade."
	exit
fi

score=`expr $score / 10`

case $score in 
	6) echo ${judge}"D." ;;
	7) echo ${judge}"C." ;;
	8) echo ${judge}"B." ;;
	9) echo ${judge}"A." ;;
	10) echo ${judge}"AA." ;;
	*) echo ${judge}"E." ;;
esac

#end

上面的case例子也是C语言中case的经典举例,就是输入一个学生的考试成绩,来判断这个成绩的等级,上面例子中的read同C语言中的scanf()类似,起着阻塞进程,等待用户输入数据的功能。以上的书写格式也是shell中case使用的基本格式。case语句的开头是case [value] in,然后再是[mode]) [command];;一条条的不同条件处理的语句,其中的mode就是不同的条件模式,command便是不同条件模式下的处理命令,可以是一条或多条,*)表示任意条件模式,每一个条件模式完成之后,需要输入";;"表示一个mode已经完成。当一个case完成之后,需要输入关键字esac(case的倒序写法),来表示case条件判断结束。

实战运用

在第一篇Linux Shell笔记的博客中,本人已经通过shell完成了网卡IP地址的获取,现在我们可以对之前的程序做一下功能的扩展与优化:

  • 通过命令行键入网卡的名字,作为参数,获取对应网卡的IP等配置信息
  • 若用户在命令行输入的参数不符合规定,则进行相应的报错与提醒

怎样才能知道用户键入的网卡是否存在呢,一般来说,通过“ip a”的命令便可以显示所有本机上所有使能网卡的名称,因此,我们可以利用“ip a”与管道和grep命令相结合的方式,来完成参数的解析。之后,再利用if条件判断,来指定不同的网卡获取哪些信息。

实现的代码如下:

#!/bin/bash

Usage="$1: Network interface '$1' does not exist!"

inter=$1

if [[ ${#inter} -lt 2 ]] ; then
    echo $Usage
	exit
fi

CHECK=`netstat -i | grep "$1   "`

if [[ $CHECK = $NULL ]] ; then 
    echo -e $1": Network interface '$1' does not exist!"
    exit
fi




ip="ip a sh $1"
if [[ $1 = "lo" ]] ; then
	ip_addr=`$ip | grep "scope host lo"`
	ip_addr=${ip_addr%"scope host lo"*}
	echo -e "$1:\n"${ip_addr}

	ip_addr=`$ip | grep "inet6"`
	ip_addr=${ip_addr%%"scope host"*}
	echo " inet6"${ip_addr##*"inet6"}

	ip_addr=`$ip | grep "brd"`
	ip_addr=${ip_addr##*"brd"}
	echo " broadcast"${ip_addr}
else
    if [[ `$ip | grep "inet"` != $NULL ]] ; then
	    ip_addr=`$ip | grep "brd" | grep "inet"`
	    ip_addr=${ip_addr%%"scope"*}
	    echo -e "$1:\n"${ip_addr}
	
	    ip_addr=`$ip | grep "inet6"`
	    ip_addr=${ip_addr%%"scope"*}
	    echo " inet6"${ip_addr##*"inet6"}
    else
        ip_addr=`$ip | grep "link"`
	    echo -e "$1:\n"${ip_addr}
    fi	
fi

#end	

以上例子中的参数解析的逻辑是:若没有在“ip a”命令执行的结果里查找到对应的网卡或用户键入参数为空,则直接退出并打印错误信息。
之后获取IP等网卡配置的信息,和之前的方法一样,通过观察不同网卡之前配置信息书写格式的共性,来指定一套统一的信息截取方法。比如,loopback网卡只有广播的信息,而无MAC地址等信息,所有就单独拿出来作为一个特殊的条件判断模式,Debian系列中eth0网卡的信息也是如此。

第二期shell笔记经验分享基本结束,下次将讲述的是shell中的函数、数组与循环。

你可能感兴趣的:(Linux,Shell)