【1】条件判断
① 按照文件类型进行判断
测试选项 | 作 用 |
-b 文件 | 判断该文件是否存在,并且是否为块设备文件(是块设备文件为真) |
-c文件 | 判断该文件是否存在,并且是否为字符设备文件(是字符设备文件为真) |
-d 文件 | 判断该文件是否存在,并且是否为目录文件(是目录为真) |
-e 文件 | 判断该文件是否存在(存在为真) |
-f 文件 | 判断该文件是否存在,并且是否为普通文件(是普通文件为真) |
-L 文件 | 判断该文件是否存在,并且是否为符号链接文件(是符号链接文件为真) |
-p 文件 | 判断该文件是否存在,并且是否为管道文件(是管道文件为真) |
-s 文件 | 判断该文件是否存在,并且是否为非空(非空为真) |
-S 文件 | 判断该文件是否存在,并且是否为套接字文件(是套接字文件为真) |
判断文件是否存在:
[root@localhost shell]# [ -e /home/shell ] [root@localhost shell]# echo $? 0 #输出为0 表示存在
test -e /home/shell 等同于 [ -e /home/shell ] 两种格式写法。
判断/home/shell是否为目录:
#这里用了&& || [root@localhost shell]# [ -d /home/shell ] && echo "yes" || echo "no" yes
② 按照文件权限进行判断
测试选项 | 作 用 |
-r 文件 | 判断该文件是否存在,并且是否该文件拥有读权限(有读权限为真) |
-w文件 | 判断该文件是否存在,并且是否该文件拥有写权限(有写权限为真) |
-x 文件 | 判断该文件是否存在,并且是否该文件拥有执行权限(有执行权限为真) |
-u 文件 | 判断该文件是否存在,并且是否该文件拥有SUID权限(有SUID权限为真) |
-g 文件 | 判断该文件是否存在,并且是否该文件拥有SGID权限(有SGID权限为真) |
-k 文件 | 判断该文件是否存在,并且是否该文件拥有SBit权限(有SBit权限为真) |
测试实例:
[root@localhost shell]# [ -w student.txt ] && echo "yes" || echo "no" yes
③ 两个文件之间进行比较
测试选项 | 作 用 |
文件1 -nt 文件2 | 判断文件1的修改时间是否比文件2的新(如果新则为真) |
文件1 -ot 文件2 | 判断文件1的修改时间是否比文件2的旧(如果旧则为真) |
文件1 -ef 文件2 | 判断文件1是否和文件2的Inode号一致,可以理解为两个文件是否为同一个文件。这个判断用于判断硬链接是很好的方法 |
如下测试硬链:
#创建硬链 [root@localhost shell]# ln ./student.txt student1.txt #进行测试 [root@localhost shell]# [ student.txt -ef student1.txt ] && echo "yes" || echo "no" yes #创建软连 [root@localhost shell]ln -s student.txt student3.txt # lrwxrwxrwx 1 root root 11 Jul 20 12:10 student3.txt -> student.txt [root@localhost shell]# [ student.txt -ef student3.txt ] && echo "yes" || echo "no" yes #判断是否符号链接文件 [root@localhost shell]# [ -L student3.txt ] && echo "yes" || echo "no" yes #判断是否符号链接文件 [root@localhost shell]# [ -L student1.txt ] && echo "yes" || echo "no" no
关于两个文件比较,还可以之间使用diff命令,如下所示:
[root@localhost shell]# diff student.txt student2.txt 2a3 > 中 Liming 82 95 86 87.66
④ 两个整数之间用来比较
测试选项 | 作 用 |
整数1 -eq 整数2 | 判断整数1是否和整数2相等(相等为真) |
整数1 -ne 整数2 | 判断整数1是否和整数2不相等(不相等为真) |
整数1 -gt 整数2 | 判断整数1是否大于整数2(大于为真) |
整数1 -lt 整数2 | 判断整数1是否小于整数2(小于位置) |
整数1 -ge 整数2 | 判断整数1是否大于等于整数2(大于等于为真) |
整数1 -le 整数2 | 判断整数1是否小于等于整数2(小于等于为真) |
测试实例如下:
[root@localhost shell]# [ 23 -ge 22 ] && echo "yes" || echo "no" yes
⑤ 字符串的判断
测试选项 | 作 用 |
-z 字符串 |
判断字符串是否为空(为空返回真) |
-n 字符串 |
判断字符串是否为非空(非空返回真) |
字串1 == 字串2 |
判断字符串1是否和字符串2相等(相等返回真) |
字串1 != 字串2 |
判断字符串1是否和字符串2不相等(不相等返回真) |
测试实例如下:
[root@localhost shell]# [ -z 22 ] && echo "yes" || echo "no" no [root@localhost shell]# [ -z "" ] && echo "yes" || echo "no" yes #给变量a b赋值 [root@localhost shell]# a=1 [root@localhost shell]# b=2 #注意==左右两边的空格 [root@localhost shell]# [ "$a" == "$b" ] && echo "yes" || echo "no" no
⑥ 多重条件判断
测试选项 | 作 用 |
判断1 -a 判断2 |
逻辑与,判断1和判断2都成立,最终的结果才为真 |
判断1 -o 判断2 |
逻辑或,判断1和判断2有一个成立,最终的结果就为真 |
!判断 |
逻辑非,使原始的判断式取反 |
测试实例如下:
#判断a是否非空且a==b [root@localhost shell]# [ -n "$a" -a "$a" == "$b" ] && echo "yes" || echo "no" no [root@localhost shell]# [ -n "$a" -a "$a" -gt 0 ] && echo "yes" || echo "no" yes #逻辑非测试 [root@localhost shell]# [ ! -n "$a" ] && echo "yes" || echo "no" no
【2】流程控制之if条件判断
① 单分支if条件语句
单分支条件语句最为简单,就是只有一个判断条件,如果符合条件则执行某个程序,否则什么事情都不做。语法如下:
if [ 条件判断式 ];then 程序 fi
单分支条件语句需要注意几个点:
- if语句使用fi结尾,和一般语言使用大括号结尾不同
[ 条件判断式 ]
就是使用test命令判断,所以中括号和条件判断式之间必须有空格- then后面跟符合条件之后执行的程序,可以放在[]之后,用“;”分割。也可以换行写入,就不需要“;”了,比如单分支if语句还可以这样写:
if [ 条件判断式 ] then 程序 fi
如下实例判断磁盘空间使用率$(df -h | grep "/dev/sda1" | awk '{print $5}' | cut -d "%" -f1)可得到磁盘使用率整数部分
:
[root@localhost shell]# vim if1.sh #/bin/bash rate=$(df -h | grep "/dev/sda1" | awk '{print $5}' | cut -d "%" -f1) if [ $rate -le 80 ];then echo "Releax! /dev/sda1 is empty!!" fi [root@localhost shell]# ./if1.sh Releax! /dev/sda1 is empty!!
② 双分支if条件语句
语法格式如下:
if [ 条件判断式 ] then 条件成立时,执行的程序 else 条件不成立时,执行的另一个程序 fi
如下数据备份实例:
#!/bin/bash #同步系统时间 ntpdate asia.pool.ntp.org &>/dev/null #把当前系统时间按照“年月日”格式赋予变量date date=$(date +%y%m%d) #统计mysql数据库的大小,并把大小赋予size变量 size=$(du -sh /var/lib/mysql) if [ -d /tmp/dbbak ] #判断备份目录是否存在,是否为目录 #如果判断为真,执行以下脚本 then #把当前日期写入临时文件 echo "Date : $date!" > /tmp/dbbak/dbinfo.txt #把数据库大小写入临时文件 echo "Data size : $size" >> /tmp/dbbak/dbinfo.txt #进入备份目录 cd /tmp/dbbak #打包压缩数据库与临时文件,把所有输出丢入垃圾箱(不想看到任何输出) tar -zcf mysql-lib-$date.tar.gz /var/lib/mysql dbinfo.txt &>/dev/null #删除临时文件 rm -rf /tmp/dbbak/dbinfo.txt else #如果判断为假,则建立备份目录 mkdir /tmp/dbbak #把日期和数据库大小保存到临时文件 echo "Date : $date!" > /tmp/dbbak/dbinfo.txt echo "Data size : $size" >> /tmp/dbbak/dbinfo.txt #压缩备份数据库与临时文件 cd /tmp/dbbak tar -zcf mysql-lib-$date.tar.gz dbinfo.txt /var/lib/mysql &>/dev/null #删除临时文件 rm -rf /tmp/dbbak/dbinfo.txt fi
③ 多分支if条件语句
语法格式如下:
if [ 条件判断式1 ] then 当条件判断式1成立时,执行程序1 elif [ 条件判断式2 ] then 当条件判断式2成立时,执行程序2 …省略更多条件… else 当所有条件都不成立时,最后执行此程序 fi
判断用户输入的名字是什么类型文件实例如下:
#/bin/bash read -p "Please input a filename: " file #判断file变量是否为空 if [ -z "$file" ] then echo "Error,please input a filename" #退出程序,并返回值为1(把返回值赋予变量$?) exit 1 #判断file的值是否存在 elif [ ! -e "$file" ] then echo "Your input is not a file!" exit 2 #判断file的值是否为普通文件 elif [ -f "$file" ] then echo "$file is a regulare file!" #判断file的值是否为目录文件 elif [ -d "$file" ] then echo "$file is a directory" #如果以上判断都不是,则执行程序5 else echo "$file is an other file!" fi [root@bogon shell]# ./if-elif.sh Please input a filename: test1.txt test1.txt is a regulare file!
完善版的四则运算计算器:
#!/bin/bash #字符界面加减乘除计算器 read -t 30 -p "Please input num1: " num1 read -t 30 -p "Please input num2: " num2 #通过read命令接收要计算的数值,并赋予变量num1和num2 read -t 30 -p "Please input a operator: " ope #通过read命令接收要计算的符号,并赋予变量ope if [ -n "$num1" -a -n "$num2" -a -n "$ope" ] #第一层判断,用来判断num1、num2和ope中都有值 then test1=$(echo $num1 | sed 's/[0-9]//g') test2=$(echo $num2 | sed 's/[0-9]//g') #定义变量test1和test2的值为$(命令)的结果 #后续命令作用是,把变量test1的值替换为空。如果能替换为空,证明num1的值为数字 #如果不能替换为空,证明num1的值为非数字。我们使用这种方法判断变量num1的值为数字 #用同样的方法测试test2变量 if [ -z "$test1" -a -z "$test2" ] #第二层判断,用来判断num1和num2为数值 #如果变量test1和test2的值为空,则证明num1和num2是数字 then #如果test1和test2是数字,则执行以下命令 if [ "$ope" == '+' ] #第三层判断用来确认运算符 #测试变量$ope中是什么运算符 then value=$(( $num1 + $num2 )) #如果是加号则执行加法运算 elif [ "$ope" == '-' ] then value=$(( $num1 - $num2 )) #如果是减号,则执行减法运算 elif [ "$ope" == '*' ] then value=$(( $num1 * $num2 )) elif [ "$ope" == '/' ] then value=$(( $num1 / $num2 )) else echo "Please enter a valid symbol" #如果运算符不匹配,提示输入有效的符号 exit 10 #并退出程序,返回错误代码10 fi else #如果test1和test2不为空,说明num1和num2 不是数字 echo "Please enter a valid value" #则提示输入有效的数值 exit 11 #并退出程序,返回错误代码11 fi else echo "qing shuru neirong" exit 12 fi echo " $num1 $ope $num2 : $value" #输出数值运算的结果
【3】流程控制之case条件判断
case语句和if…elif…else
语句一样都是多分支条件语句,不过和if多分支条件语句不同的是,case语句只能判断一种条件关系,而if语句可以判断多种条件关系。case语句语法如下:
case $变量名 in "值1") 如果变量的值等于值1,则执行程序1 ;; "值2") 如果变量的值等于值2,则执行程序2 ;; …省略其他分支… *) 如果变量的值都不是以上的值,则执行此程序 ;; esac
这个语句需要注意以下内容:
case语句,会取出变量中的值,然后与语句体中的值逐一比较。如果数值符合,则执行对应的程序,如果数值不符,则依次比较下一个值。如果所有的值都不符合,则执行“*)”(“*”代表所有其他值)中的程序。
case语句以“case”开头,以“esac”结尾(就是case倒转)。
每一个分支程序之后要通过“;;”双分号结尾,代表该程序段结束。
测试实例如下:
[root@localhost shell]# cat case.sh #!/bin/bash read -p "Please choose yes/no: " -t 30 cho case "$cho" in "yes") echo "your choose is yes" ;; "no") echo "your choose is no" ;; *) echo "your choose is error" ;; esac [root@localhost shell]# ./case.sh Please choose yes/no: yes your choose is yes
【4】流程控制之for循环
for循环是固定循环,也就是在循环时已经知道需要进行几次的循环,有时也把for循环称为计数循环。
for的语法有如下两种。语法一如下:
#语法一 for 变量 in 值1 值2 值3… do 程序 done
这种语法中for循环的次数,取决于in后面值的个数(空格分隔),有几个值就循环几次,并且每次循环都把值赋予变量。也就是说,假设in后面有三个值,for会循环三次,第一次循环会把值1赋予变量,第二次循环会把值2赋予变量,以此类推。
实例如下:
[root@bogon shell]# ./for.sh this time is morning this time is noon this time is afternoon this time is evening [root@bogon shell]# cat for.sh #!/bin/bash for time in morning noon afternoon evening do echo "this time is $time" done
语法二如下:
for (( 初始值;循环控制条件;变量变化 )) do 程序 done
语法二中需要注意:
- 初始值:在循环开始时,需要给某个变量赋予初始值,如i=1;
- 循环控制条件:用于指定变量循环的次数,如i<=100,则只要i的值小于等于100,循环就会继续;
- 变量变化:每次循环之后,变量该如何变化,如i=i+1。代表每次循环之后,变量i的值都加1。
如求和1-100:
[root@bogon shell]# vi for2.sh #!/bin/bash s=0 for (( i=1;i<=100;i++ )) do s=$(( $s+$i )) done echo "the sum of 1+2+...+100 is:$s" [root@bogon shell]# ./for2.sh the sum of 1+2+...+100 is:5050
如下批量添加指定数量的用户:
[root@localhost ~]# vi useradd.sh #!/bin/bash read -p "Please input user name: " -t 30 name #让用户输入用户名,把输入保存入变量name read -p "Please input the number of users: " -t 30 num #让用户输入添加用户的数量,把输入保存入变量num read -p "Please input the password of users: " -t 30 pass #让用户输入初始密码,把输入保存如变量pass if [ ! -z "$name" -a ! -z "$num" -a ! -z "$pass" ] #判断三个变量不为空 then y=$(echo $num | sed 's/[0-9]//g') #定义变量的值为后续命令的结果 #后续命令作用是,把变量num的值替换为空。如果能替换为空,证明num的值为数字 #如果不能替换为空,证明num的值为非数字。用这种方法判断变量num的值为数字 if [ -z "$y" ] #如果变量y的值为空,证明num变量是数字 then for (( i=1;i<=$num;i=i+1 )) #循环num变量指定的次数 do /usr/sbin/useradd $name$i &>/dev/null #添加用户,用户名为变量name的值加变量i的数字 echo $pass | /usr/bin/passwd --stdin $name$i &>/dev/null #给用户设定初始密码为变量pass的值 chage -d 0 $name$i &>/dev/null #强制用户登录后修改密码 done fi fi [root@bogon shell]# ./useradd.sh Please input user name: jane Please input the number of users: 1 Please input the password of users: 123456 [root@bogon shell]# cat /etc/passwd|grep "jane" jane:x:1000:1000:jane:/home/jane:/bin/bash jane1:x:1001:1001::/home/jane1:/bin/bash
如下批量删除用户:
#!/bin/bash #批量删除用户 user=$(cat /etc/passwd | grep "/bin/bash"|grep -v "root"|cut -d ":" -f 1) #读取用户信息文件,提取可以登录用户,取消root用户,截取第一列用户名 for i in $user #循环,有多少个普通用户,循环多少次 do userdel -r $i #每次循环,删除指定普通用户 -r表示家目录一同删除 done
【5】流程控制之while循环
语法格式如下:
#注意空格 while [ 条件判断式 ] do 程序 done
对while循环来讲,只要条件判断式成立,循环就会一直继续,直到条件判断式不成立,循环才会停止。
如下求和1-100:
[root@bogon shell]# vim while.sh #!/bin/bash s=0 i=1 while [ $i -le 100 ] do s=$(( $s+$i )) i=$(( $i+1 )) done echo "the sum 1+2+...+100 is :$s" [root@bogon shell]# ./while.sh the sum 1+2+...+100 is :5050
【6】流程控制之until循环
再来看看until循环,和while循环相反,until循环时只要条件判断式不成立则进行循环,并执行循环程序。一旦循环条件成立,则终止循环。
语法格式如下:
until [ 条件判断式 ] do 程序 done
求和1-100:
#!/bin/bash s=0 i=1; until [ $i -gt 100 ] do s=$(( $s+$i )) #加上这句将会变成求1-100内的偶数 # i=$(( $i+1 )) done echo "the sum 1+2+...+100 is :$s" [root@bogon shell]# ./until.sh the sum 1+2+...+100 is :5050
【7】特殊流程控制语句
① exit语句
系统是有exit命令的,用于退出当前用户的登录状态。可是在Shell脚本中,exit语句是用来退出当前脚本的。也就是说,在Shell脚本中,只要碰到了exit语句,后续的程序就不再执行,而直接退出脚本。
exit的语法如下:
exit [返回值]
如果exit命令之后定义了返回值,那么这个脚本执行之后的返回值就是我们自己定义的返回值。可以通过查询$?
这个变量,来查看返回值。如果exit之后没有定义返回值,脚本执行之后的返回值是执行exit语句之前,最后执行的一条命令的返回值。
测试实例如下:
[root@bogon shell]# vim exit.sh #!/bin/bash read -p "Please input a number:" -t 30 num #如果变量num的值是数字,则把num的值替换为空,否则不替换 #把替换之后的值赋予变量y y=$( echo $num|sed 's/[0-9]//g' ) #判断变量y的值如果不为空,输出报错信息,退出脚本,退出返回值为18 [ -n '$y' ] && echo "Error,please input a number !" && exit 18 echo "the number is :$num" [root@bogon shell]# ./exit.sh Please input a number:kk Error,please input a number ! [root@bogon shell]# echo $? 18
② break语句
当程序执行到break语句时,会结束整个当前循环。而continue语句也是结束循环的语句,不过continue语句单次当前循环,而下次循环会继续。
测试如下:
[root@localhost ~]# vi sh/break.sh #!/bin/bash #演示break跳出循环 for (( i=1;i<=10;i=i+1 )) #循环十次 do if [ "$i" -eq 4 ] #如果变量i的值等于4 then break #退出整个循环 fi echo $i #输出变量i的值 done
执行下这个脚本,因为一旦变量i的值等于4,整个循环都会跳出,所以只能循环三次:
[root@localhost ~]# chmod 755 break.sh [root@localhost ~]# sh/break.sh 1 2 3
③ continue语句
continue也是结束流程控制的语句。如果在循环中,continue语句只会结束单次当前循环,然后继续下次循环。
[root@localhost ~]# vi sh/continue.sh #!/bin/bash #演示continue语句 for (( i=1;i<=10;i=i+1 )) do if [ "$i" -eq 4 ] then continue #退出语句换成continue fi echo $i done [root@localhost ~]# chmod 755 continue.sh #赋予执行权限 [root@localhost ~]# ./continue.sh 1 2 3 #少了4这个输出 5 6 7 8 9 10
continue只会退出单次循环,所以并不影响后续的循环,所以只会少4的输出。这个例子和break的例子做个比较,应该可以更清楚的说明break和continue的区别。