测试选项 | 作 用 |
---|---|
-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
单分支条件语句最为简单,就是只有一个判断条件,如果符合条件则执行某个程序,否则什么事情都不做。语法如下:
if [ 条件判断式 ];then
程序
fi
单分支条件语句需要注意几个点:
[ 条件判断式 ]
就是使用test命令判断,所以中括号和条件判断式之间必须有空格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 [ 条件判断式 ]
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 [ 条件判断式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"
#输出数值运算的结果
case语句和if…elif…else
语句一样都是多分支条件语句,不过和if多分支条件语句不同的是,case语句只能判断一种条件关系,而if语句可以判断多种条件关系。case语句语法如下:
case $变量名 in
"值1")
如果变量的值等于值1,则执行程序1
;;
"值2")
如果变量的值等于值2,则执行程序2
;;
…省略其他分支…
*)
如果变量的值都不是以上的值,则执行此程序
;;
esac
这个语句需要注意以下内容:
“*)”(“*”
代表所有其他值)中的程序。“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
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
语法二中需要注意:
如求和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
语法格式如下:
#注意空格
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
再来看看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
系统是有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语句时,会结束整个当前循环。而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语句只会结束单次当前循环,然后继续下次循环。
[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的区别。