shell脚本编程(五)
https://blog.csdn.net/xiaochenXIHUA/article/details/156825515
一、shell中的判断
1.1、简单的if结构
bash
#简单的if结构语法
if expression
then
command
command
......
fi
在使用这种简单if结构时,要特别注意【if 测试条件后】若没有使用分号【;】则【then】语句要换行,否则会产生不必要的错误。如果if与then处于同一行,则必须使用分号分隔,如下所示:
bash
if expression;then
command
command
......
fi
简单的if结构是【单分支】当"条件成立"时执行相应的操作,执行流程图如下:

bash
#简单if结构示例
vi testreply.sh
#【testreply.sh】文件的完整内容:
#!/bin/bash
#filename:testreply.sh
echo "你确定选择计算机专业?"
read reply
#在if 的条件判断部分使用扩展的test语句[[]]
#在[[]]中可以使用shell通配符进行条件匹配
if [[ $reply == [Yy]* || $reply == [Mm]aybe ]];then
echo "你的选择是【$reply】"
fi
#执行这个脚本
bash testreply.sh
#调试脚本命令
bash -x testreply.sh




1.2、if/else结构
bash
#if/else结构语法
if expression1
then
command
command
......
else
command
command
......
fi
if/else命令是双向选择语句,当用户执行脚本时,若不满足if后的表达式也会转到else后的命令执行,具有较好的交互性。
if/else结构是【双分支】当"条件成立"、"条件不成立"时分别执行不同操作,执行的流程图如下:

bash
#if/else结构示例
vi test-host-is-up-down.sh
#【test-host-is-up-down.sh】文件的完整内容:
#!/bin/bash
#filename:test-host-is-up-down.sh
#if条件部分可以使用普通命令测试
#当命令正确执行($?=0)时返回真,否则($?<>0)返回假
#ping命令中【-c1】表示只发送 1 个 ping 包;【-w2】表示超时时间为 2 秒
myhost=coffeemilk.blog.csdn.net
if ping -c1 -w2 $myhost &>/dev/null
then
echo "$myhost is up"
else
echo "$myhost is down"
fi
#执行脚本
bash test-host-is-up-down.sh
#调试脚本,可以查看到更多细节
bash -x test-host-is-up-down.sh
|--------|------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 序号 | 命令或参数 | 说明 |
| 1 | 在Linux/Unix系统中,进程启动时会默认打开3个标准文件描述符(文件句柄): 《1》【0】标准输入(stdin):默认对应键盘输入,程序从这里读取输入数据; 《2》【1】标准输出(stdout):默认对应终端窗口,程序的正常执行结果(如:echo输出、命令正常返回内容)都会输出到这里。 《3》【2】标准错误(stderr):默认对应终端窗口,程序的错误信息(如:命令不存在、参数错误)都会输出到这里。 ||
| 2 | >/dev/null 2>&1 | 这是两个连续的重定向操作,执行时有先后顺序: 《1》【>/dev/null】等价于【1>/dev/null】含义是:将程序的标准输出重定向到/dev/null中(/dev/null是Linux的"空设备"也叫"黑洞",任何写入到这里的数据都会被直接丢弃,不会留存也不会输出到终端中)。 《2》【2>&1】表示将标准错误重定向到标准输出当前所指向的目标(其中1前面的&符号不能省略)。 由于执行顺序是先执行【1>/dev/null】然后在执行【2>&1】因此呈现的效果是:标准输出与标准错误的输出都会被丢弃,不会显示在终端上。 |
| 3 | &>/dev/null | 这是Bash shell提供的简化语法糖,含义也是:直接将标准输出和标准错误同时重定向到/dev/null中丢弃,不会显示在终端上。 这个命令的功能与【>/dev/null 2>&1】完全一致,只是写法更加简洁。 |
| 【>/dev/null 2>&1】命令的兼容性更好,是POSIX标准规范的写法。适用于所有符合POSIX标准的shell (如:Bash、Sh、Ksh、Zsh等)。即使在非Bash环境(如:系统默认的/bin/sh,很多系统中的sh是dash软链接,不支持&>)也能正常运行【推荐在编写可移植性要求较高的脚本中使用(如:系统初始化脚本、跨环境运行的脚本)】。 【&>/dev/null】是Bash的专属简化写法,只能在Bash shell中有效。不兼容POSIX标准,在sh、dash等非Bash环境中执行会报错【推荐仅在Bash环境中允许的脚本使用(如:个人使用的脚本,明确指定#!/bin/bash作为解释器的脚本)】。 |||
[丢弃命令解析]



bash
#if/else示例二
vi idcheck.sh
#【idcheck.sh】脚本的完整内容:
#!/bin/bash
## filename: idcheck.sh
# purpose: check user id to see if user is root.
# Only root has a uid of 0.
# Format for id output:
# uid=9496(ellie) gid=40 groups=40
# root's uid=0
#
id=`id | awk -F'[=(]' '{print $2}'` # get user ID
echo "your user id is: $id"
if (( id == 0 )) # [ $id -eq 0 ]
then
echo "you are superuser."
else
echo "you are not superuser."
fi
#执行脚本
bash idcheck.sh


二、if/elif/else结构
bash
if/elif/else结构语法
if expr1 #若expr1为真(返回值为0)
then #那么
commands1 #执行语句块commands1
elif expr2 #若expr1为假,而expr2为真
then #那么
commands2 #执行语句块commands2
...... #可以有多个elif语句
else #else最多只能有一个
commands6 #执行语句块commands6
fi #if语句必须以单次fi终止
|--------|-----------------------------------------------------------------|
| 序号 | 说明 |
| 1 | if语句必须以【fi】结束 |
| 2 | 【elif】可以有任意多个(0个或多个) |
| 3 | 【else】最多只能有一个(0个或1个) |
| 4 | 【if】语句可以嵌套使用 |
| 5 | 【expr】通常为条件测试表达式;也可以是多个命令,以最后一个命令的退出状态为条件值。 |
| 6 | 【commands】为可执行语句块,如果为空,需使用shell提供的空命令【冒号 :】该命令不做任何事情,只返回一个退出状态0 |
[if/else判断的一些注意项]
if/elif/else语句结构是【多分支】可针对多个条件执行不同操作,执行流程图如下:

bash
#if/elif/else结构示例
vi ask-age.sh
#【ask-age.sh】文件的完整内容:
#!/bin/bash
#filename:ask-age.sh
read -p "你现在是几岁?" age
#使用shell算术运算符(())进行条件测试
if ((age<0||age>120));then #[[ age < 0 || age > 120 ]]
echo "超过年龄限制!"
exit 1
fi
if ((age>=0&&age<7 ));then
echo "儿童"
elif ((age>=7&&age<18));then
echo "少年"
elif ((age>=18&&age<40));then
echo "青年"
elif ((age>=40&&age<65));then
echo "中年"
elif ((age>=65&&age<100));then
echo "老年"
else
echo "百岁老人"
fi
#执行脚本
bash ask-age.sh


bash
#if嵌套语句示例一:
vi existuser.sh
#【existuser.sh】脚本的完整内容:
#!/bin/bash
#filename:existuser.sh
#if语句的嵌套使用(【$#】用于判断参数的个数;【$1】获取第一个参数;【$0】获取脚本名称)
if [ $# -eq 1 ] #或者使用[[ $# -eq 1 ]] 或(($#==1))
then
if who | grep $1 >/dev/null;then
echo $1 is active
else
echo $1 is not active
fi
else
echo "用法:$0 <username>"
exit 1
fi
#执行脚本
chmod +x ./existuser.sh
./existuser.sh coffeemilk
#调试脚本
bash -x ./existuser.sh


bash
#if嵌套示例二:
vi filetype.sh
#【filetype.sh】文件的完整内容:
#!/bin/bash
#filename:filetype.sh
#if的嵌套使用
file=$1
#【$#】是获取参数的个数【$# -ne 1】表示获取到的参数个数不等于1时返回0为真【&&】表示逻辑运算与
[ $# -ne 1 ] && echo "用法:$0 <filename>" && exit 1
if [ -d $file ];then
echo "$file is a directory"
elif [ -f $file ];then
if [ -r $file -a -w $file -a -x $file ];then
# if [[ -r $file && -w $file && -x $file ]] ;then
echo "你对【$file】拥有可读可写可执行【rwx】权限"
fi
else
echo "$file 不是一个目录或者一个文件!"
fi
#执行脚本
bash filetype.sh /etc
#调试脚本
bash -x filetype.sh /etc


三、case选择语句
bash
#case选择语句的语法
case expr in #expr为表达式,关键词in不要忘记
pattern1) #若expr与pattern1匹配(注意pattern1后的右括号)
commands1 #执行语句块commands1
;; #跳出case结构
pattern2) #若expr与pattern2匹配
commands2 #执行语句块commands2
;; #跳出case结构
...... #可以有任意多个模式匹配
*) #若expr与上面的模式都不匹配
commands #执行语句块commands
;; #跳出case结构
esac #case语句必须以esac终止
case选择语句的执行流程图如下:

|--------|--------------------------------------------------------------|
| 序号 | 说明 |
| 1 | 表达式【expr】按顺序匹配每个模式,一旦有一个模式匹配成功,则执行该模式后面的所有命令,然后退出case。 |
| 2 | 如果【expr】没有找到匹配的模式,则执行缺省值【*)】后面的命令块(类似于if中的else);【*)】可以不出现。 |
| 3 | 所给的匹配模式【pattern】中可以含有通配符和【|】。 |
| 4 | 每个命令块的最后必须有一个双分号【;;】可以独占一行,或放在最后一个命令的后面。 |
[case选择语句的一些注意项]
bash
#case选择语句示例
vi favorite-language.sh
#【favorite-language.sh】文件的完整内容
#!/bin/bash
#filename:favorite-language.sh
echo "你最喜欢哪个脚本语言:"
echo "1)bash"
echo "2)perl"
echo "3)python"
echo "4)ruby"
echo "5)我不知道"
read lang
readonly tip="你选择了"
case $lang in
1) echo "$tip【bash】";;
2) echo "$tip【perl】";;
3) echo "$tip【python】";;
4) echo "$tip【ruby】";;
5) echo "$tip【我不知道】";;
esac
#执行脚本
bash favorite-language.sh
#调试脚本
bash -x favorite-language.sh

bash
#case选择的示例二
vi yesorno.sh
#【yesorno.sh】文件的完整内容
#!/bin/bash
## filename: yesorno.sh
echo -n "Do you agree with this? [yes or no]: "
read yn
case $yn in
[Yy] | [Yy][Ee][Ss])
echo "Agreed."
;;
[Nn] | [Nn][Oo])
echo "Not agreed."
exit 1
;;
*)
echo "Invalid input."
;;
esac
#测试脚本
bash yesorno.sh

bash
#case选择的示例三
vi backup.sh
#【backup.sh】文件的完整内容:
#!/bin/bash
## filename: backup.sh
# A shell script to backup mysql, webserver and files.
# opt=$1
case $1 in
sql) echo "Running mysql backup using mysqldump tool..." ;;
sync) echo "Running backup using rsync tool..." ;;
git) echo "Running backup using gistore tool..." ;;
tar) echo "Running tape backup using tar tool..." ;;
*)
echo "Backup shell script utility"
echo "Usage: $0 {sql|sync|git|tar}"
echo " sql : Run mySQL backup utility."
echo " sync : Run web server backup utility."
echo " git : Run gistore backup utility."
echo " tar : Run tape backup utility."
;;
esac
#执行脚本
bash backup.sh

bash
#case选择语句的示例四
vi disktest.sh
#【disktest.sh】文件的完整内容:
#!/bin/bash
## filename: disktest.sh
# This script does a very simple test for checking disk space.
max_usage=$(LANG=C df -Ph | awk '{print $5}' | grep % | grep -v Use | sort -n | tail -1 | cut -d "%" -f1)
mountlabel=`LANG=C df -Ph|awk '{print $5,$6}'|grep -v Use|sort -n|tail -1|awk '{print $2}'`
case ${max_usage} in
[1-6]*)
MSG="All is quiet."
;;
[7-8]*)
MSG="Start thinking about cleaning out some stuff. "
MSG="$MSG There's a partition ${mountlabel} is ${max_usage}% used."
;;
9[1-8])
MSG="Better hurry with that new disk... "
MSG="$MSG One partition is ${max_usage}% used."
;;
99)
MSG="I'm drowning here! There's a partition at ${max_usage}% used"
;;
*)
MSG="I seem to be running with an nonexitent amount of disk space..."
;;
esac
#echo $MSG | mail -s "disk report `date`" root
echo $MSG
#执行脚本
bash disktest.sh
