一、测试
1.测试
在程序运行中经常需要根据实际情况来运行特定的命令或代码块。
比如判断某个文件或目录是否存在?如果不存在,则需要创建。
[root@localhost ~]# ls /var/log/messages
/var/log/messages
[root@localhost ~]# echo $?
0
[root@localhost ~]# ls /var/log/messages044
ls: /var/log/messages044: No such file or directory
[root@localhost ~]# echo $?
2
2.测试的结构主要有两种
(1)使用test命令
test expression
其中expression是一个表达式,可以是算术比较、字符串比较、文本和文件属性比较等。
(2)使用[]
[ expression ]
注意括号和表达式expression之间都有空格。推荐使用第二种方式。
例如:判断文件是否存在
[root@localhost ~]# test -e /var/log/messages
[root@localhost ~]# echo $?
0
[root@localhost ~]# [ -e /var/log/messages ]
[root@localhost ~]# echo $?
0
3.文件测试参数
参数 | 作用 |
---|---|
-e | 文件或目录是否存在 |
-f | 文件存在且为普通文件 |
-d | 目录是否存在 |
-w file | 当文件存在且为可写文件时返回真,否则为假 |
-r file | 当文件存在且为可读文件时返回真,否则为假 |
-x file | 当文件存在且为可执行文件时返回真,否则为假 |
-l file | 当文件存在且为链接文件时返回真,否则为假 |
-p file | 当文件存在且为管道文件时返回真,否则为假 |
-s file | 当文件存在且大小不为0时返回真,否则为假 |
-S file | 当文件存在且为socket文件时返回真,否则为假 |
-g file | 当文件存在且设置了SGID时返回真,否则为假 |
-u file | 当文件存在且设置了SUID时返回真,否则为假 |
-k file | 当文件存在且设置了sticky属性时返回真,否则为假 |
-G file | 当文件存在且属于有效的用户组时返回真,否则为假 |
-O file | 当文件存在且属于有效的用户时返回真,否则为假 |
file1 -nt file2 | 当file1比file2新时,返回为真,否则为假 |
file1 -ot file2 | 当file1比file2旧时,返回为真,否则为假 |
示例
[root@localhost ~]# vim rwx.sh
#!/bin/bash
read -p "what file do you want to test?:" filename
if [ ! -e "$filename" ];then
echo "the file does not exist."
exit 1
fi
if [ -r "$filename" ];then
echo "$filename is readable."
fi
if [ -w "$filename" ];then
echo "$filename is writeable."
fi
if [ -x "$filename" ];then
echo "$filename is executable."
fi
[root@localhost ~]# bash rwx.sh
what file do you want to test?:/etc
/etc is readable.
/etc is writeable.
/etc is executable.
二、条件判断
1.if判断结构
最简单的判断语句,可以针对测试结果做相应处理;如果测试为真则运行相关代码,其语法结构如下:
if expression;then
command
fi
如果expression测试返回真,则执行command。如果执行不止一条命令,则不同命令之间用换行符隔开,如下所示:
if expression;then
command1
command2
...
fi
2.常用参数
参数 | 作用 |
---|---|
-eq | 检测两个数是否相等,相等返回true,否则返回false |
-ne | 检测两个数是否不相等,不相等返回true,否则返回true |
-gt | 检测左边的数是否大于右边的,如果是,则返回true,否则返回false |
-lt | 检测左边的数是否小于右边的,如果是,则返回true,否则返回false |
-ge | 检测左边的数是否大于等于右边的,如果是,则返回true,否则返回false |
-le | 检测左边的数是否小于等于右边的,如果是,则返回 true,否则返回true |
示例
写一个脚本,判断用户得分情况。
如果小于30分,那么输出“太低了!”
如果大于等于30分且小于60分,则输出"加油!"
如果大于等于60分且小于85分,则输出“不错!”
如果大于等于85分且小于100分,则输出“优秀!”
如果等于100分,则输出“人才!”
[root@localhost ~]# vim score.sh
#!/bin/bash
echo -n "please input a score:"
read SCORE
if [ "$SCORE" -lt 30 ];then
echo "太低了!"
fi
if [ "$SCORE" -ge 30 -a "$SCORE" -lt 60 ];then
echo "加油!"
fi
if [ "$SCORE" -ge 60 -a "$SCORE" -lt 85 ];then
echo "不错!"
fi
if [ "$SCORE" -ge 85 -a "$SCORE" -lt 100 ];then
echo "优秀!"
fi
if [ "$SCORE" -eq 100 ];then
echo "人才!"
fi
2.if/else判断结构
如果if后的判断成立,则执行then后面的内容;否则执行else后面的内容。
语法结构如下:
if expression;then
command1
else
command2
fi
示例
[root@localhost ~]# vim check.sh
#!/bin/bash
read -p "请输入你要查询的目录或文件名:" FILE
if [ -e $FILE ];then
echo "$FILE 有!"
else
echo "$FILE 没有!"
fi
[root@localhost ~]# bash check.sh
请输入你要查询的目录或文件名:/etc
/etc 有!
[root@localhost ~]# bash check.sh
请输入你要查询的目录或文件名:cda
cda 没有!
3.if/elif/else判断结构
可以代替if嵌套。
语法结构如下:
if expression1;then
command1
elif expression2;then
command2
elif expression3;then
command3
...
fi
示例
写一个脚本,查询用户是否存在,如果存在,则输出“有此用户,它的UID为:”,如果没有则输出“没有此用户。”
(1)如果使用if判断语句,则可以这样编写:
[root@localhost ~]# vim testusr.sh
#!/bin/bash
read -p "请输入想要查询的用户名:" USER
id $USER &> /dev/null
if [ $? -ne 0 ]
then
useradd $USER
echo "没有此用户,并已经为您添加此用户。添加后此用户UID为 `id -u $USER`"
else
echo "此用户已经存在,UID为`id -u $USER`"
fi
[root@localhost ~]# bash testusr.sh
请输入想要查询的用户名:root
此用户已经存在,UID为0
[root@localhost ~]# bash testusr.sh
请输入想要查询的用户名:nihao
没有此用户,并已经为您添加此用户。添加后此用户UID为 2021
输出重定向
符号 | 意义 |
---|---|
> | 覆盖重定向 |
>> | 追加重定向 |
2> | 错误重定向 |
2>> | 错误追加重定向 |
&> | 同时重定向,不管正确与否 |
/dev/null | 数据黑洞 |
(2)上面的例子一般不会直接添加用户,所以可以利用if/elif/else语法修改一下。
#!/bin/bash
read -p "请输入想要查询的用户名:" USER
id $USER &> /dev/null
if [ $? -ne 0 ]
then
read -p "没有此用户,请问是否创建此用户?Y/N" YN
if [ $YN == Y ];then
useradd $USER
echo "用户添加成功,用户ID为`id -u $USER`"
elif [ $YN == N ];then
echo "好的,不进行任何操作,欢迎下次再来!"
else
echo "您的输入有误!"
fi
else
echo "此用户已经存在,UID为`id -u $USER`"
fi
[root@localhost ~]# bash testusr.sh
请输入想要查询的用户名:nihao
没有此用户,请问是否创建此用户?Y/NY
用户添加成功,用户ID为2021
[root@localhost ~]# bash testusr.sh
请输入想要查询的用户名:ni
没有此用户,请问是否创建此用户?Y/NN
好的,不进行任何操作,欢迎下次再来!
颜色方面的参数
参数 | 意义 |
---|---|
\e[1;m | 设置高亮加粗 |
\e[4;m | 添加下划线 |
\e[5;m | 闪烁 |
31m | 红色 |
32m | 绿色 |
33m | 黄色 |
34m | 蓝色 |
35m | 紫色 |
36m | 青色 |
37m | 白色 |
[root@localhost ~]# echo -e "\e[1;31m红色\e[0m"
红色
[root@localhost ~]# echo -e "\e[4;31m红色\e[0m"
红色
[root@localhost ~]# echo -e "\e[5;31m红色\e[0m"
红色
示例
写一个脚本,要求:用户输入七种颜色之一,根据用户输入的颜色打印出相应的颜色。
[root@localhost ~]# vim yanse.sh
#!/bin/bash
echo "您能输入的颜色有:红色、绿色、黄色、蓝色、紫色、青色、白色"
read -p "请输入你要选取的颜色:" COLOR
if [ $COLOR == "红色" ];then
echo -e "\e[1;31m红色\e[0m"
elif [ $COLOR == "绿色" ];then
echo -e "\e[1;32m绿色\e[0m"
elif [ $COLOR == "黄色" ];then
echo -e "\e[1;33m黄色\e[0m"
elif [ $COLOR == "蓝色" ];then
echo -e "\e[1;34m蓝色\e[0m"
elif [ $COLOR == "紫色" ];then
echo -e "\e[1;35m紫色\e[0m"
elif [ $COLOR == "青色" ];then
echo -e "\e[1;36m青色\e[0m"
elif [ $COLOR == "白色" ];then
echo -e "\e[1;37m白色\e[0m"
else
echo "您的输入有误!"
fi
[root@localhost ~]# bash yanse.sh
您能输入的颜色有:红色、绿色、黄色、蓝色、紫色、青色、白色
请输入你要选取的颜色:红色
红色
[root@localhost ~]# bash yanse.sh
您能输入的颜色有:红色、绿色、黄色、蓝色、紫色、青色、白色
请输入你要选取的颜色:蓝色
蓝色
[root@localhost ~]# bash yanse.sh
您能输入的颜色有:红色、绿色、黄色、蓝色、紫色、青色、白色
请输入你要选取的颜色:白色
白色
[root@localhost ~]# bash yanse.sh
您能输入的颜色有:红色、绿色、黄色、蓝色、紫色、青色、白色
请输入你要选取的颜色:你
您的输入有误!
4.case判断结构
用于多种可能情况下的分支选择。
语法结构如下:
case var in
var1)
command1;;
var2)
command2;;
var3)
command3;;
...
*)
command6;;
esac
其原理为从上而下依次比较var和var1、var2、var3的值是否相等,如果匹配则执行其后面的命令,都不匹配则执行最后的命令。
注意case判断结构中的var1、var2、var3等这些值只能是常量或正则表达式。
示例1
检测当前操作系统
[root@localhost ~]# vim os.sh
#!/bin/bash
OS=`uname -s`
case "$OS" in
FreeBSD)
echo "this is FreeBSD";;
SunOS)
echo "this is Solaris";;
Darwin)
echo "this is Mac OSX";;
Linux)
echo "this is Linux";;
*)
echo "Failed to identify this OS";;
esac
[root@localhost ~]# bash os.sh
this is Linux
示例2
上面颜色的例子用case改写
[root@localhost ~]# vim yanse.sh
#!/bin/bash
echo "您能输入的颜色有:红色、绿色、黄色、蓝色、紫色、青色、白色"
read -p "请输入你要选取的颜色:" COLOR
case "$COLOR" in
红色)
echo -e "\e[1;31m红色\e[0m";;
绿色)
echo -e "\e[1;32m绿色\e[0m";;
黄色)
echo -e "\e[1;33m黄色\e[0m";;
蓝色)
echo -e "\e[1;34m蓝色\e[0m";;
紫色)
echo -e "\e[1;35m紫色\e[0m";;
青色)
echo -e "\e[1;36m青色\e[0m";;
白色)
echo -e "\e[1;37m白色\e[0m";;
*)
echo "您的输入有误!";;
esac
[root@localhost ~]# bash yanse.sh
您能输入的颜色有:红色、绿色、黄色、蓝色、紫色、青色、白色
请输入你要选取的颜色:ni
您的输入有误!
[root@localhost ~]# bash yanse.sh
您能输入的颜色有:红色、绿色、黄色、蓝色、紫色、青色、白色
请输入你要选取的颜色:黄色
黄色
三、function功能
函数可以在shell script当中做出一个类似自动执行指令的东西,最大的功能是可以简化程序码。如果输出的内容都一样,那么就可以使用function来简化。
语法结构如下:
function fname () {
command
}
fname是需要自动执行的指令名称,而程序段就是要他执行的内容。
注意:因为shell script的执行方式是由上而下,由左而右,因此在shell script中function的设置一定要在程序的最前面,这样才能够在执行时被找到。
示例
使用function功能简化代码。
[root@localhost ~]# vim zhuangbei.sh
#!/bin/bash
read -p "请输入你要查询的装备类别:" INPUT
read -p "请输入装备的分数:" SCORE
function fenshu () {
if [ $SCORE -le 30 ];then
echo "品相极渣!"
elif [ $SCORE -gt 30 -a $SCORE -le 65 ];then
echo "渣渣!"
elif [ $SCORE -gt 65 -a $SCORE -le 95 ];then
echo "嗯,这才像个样!"
elif [ $SCORE -gt 95 ];then
echo "谁与争锋!"
else
echo "输入有误!"
fi
}
function chongzhu () {
read -p "请问是否选择重铸!Y/N" YN
if [ $YN == Y ];then
read -p "好的,用户选择重铸"
elif [ $YN == N ];then
echo "用户不重铸,886!"
else
echo "输入有误!"
fi
}
case $INPUT in
toukui)
fenshu;chongzhu;;
jianbang)
fenshu;chongzhu;;
xiongjia)
fenshu;chongzhu;;
*)
echo "没有这个装备";;
esac
[root@localhost ~]# bash zhuangbei.sh
请输入你要查询的装备类别:xiongjia
请输入装备的分数:90
嗯,这才像个样!
请问是否选择重铸!Y/NN
用户不重铸,886!
四、while循环、until do done(不定循环)
shell中的循环主要有for、while、until、select几种。
1.while循环
while [ condition ] #状态的判读
do #循环的开始
command
done #循环的结束
当condition条件成立时进行循环,直到condition的条件不成立才停止。
2.until循环
until [ condition ]
do
command
done
与while相反,当condition条件成立时,就终止循环,否则就持续进行循环的程序段。
示例1
[root@localhost ~]# vim while.sh
#!/bin/bash
while [ "${yn}" != "yes" ]
do
read -p "请输入'yes'退出: " yn
done
echo "退出成功!"
[root@localhost ~]# bash while.sh
请输入'yes'退出: no
请输入'yes'退出: no
请输入'yes'退出: yes
退出成功!
示例2
[root@localhost ~]# vim until.sh
#!/bin/bash
until [ "${yn}" == "yes" ]
do
read -p "请输入'yes'退出: " yn
done
echo "退出成功!"
[root@localhost ~]# bash until.sh
请输入'yes'退出: no
请输入'yes'退出: yes
退出成功!
3.关于变量取值
[root@localhost ~]# vim 1.sh
#!/bin/bash
i=0
let i=$i+1
echo $i
[root@localhost ~]# bash 1.sh
1
关于下面那个i的值已经是新的变量了,格式还可以这么写。
let i=$i+1 ----- let i+=1 ------ let i++
三者等价
示例1
求1+2+3+4…+100的值是多少?
[root@localhost ~]# vim qiuhe.sh
#/bin/bash
s=0 i=0
while [ $i != 100 ]
do
let i+=1
let s=$s+$i
done
echo "1+2+3...+100等于$s"
[root@localhost ~]# bash qiuhe.sh
1+2+3...+100等于5050
示例2
让用户输入密码,如果输入错误超过5次,就退出。
[root@localhost ~]# vim denglu.sh
#!/bin/bash
i=1
while [ "$MIMA" != "123.com" -a $i -le 5 ]
do
let i+=1
read -p "请输入密码:" MIMA
done
if [ $i -le 5 ];then
echo "登录成功!"
else
echo "已经超过5次,退出!"
fi
[root@localhost ~]# bash denglu.sh
请输入密码:123.com
登录成功!
[root@localhost ~]# bash denglu.sh
请输入密码:1
请输入密码:1
请输入密码:1
请输入密码:1
请输入密码:1
已经超过5次,退出!
五、for循环
最常见的循环结构。for循环是一种运行前测试语句,也就是在运行任何循环体之前先要判断循环条件是否成立,只有在条件成立的情况下才会运行循环体,否则将退出循环。每完成一次循环后,在进行下一次循环之前都会再次进行测试。
带列表的for循环用于执行一定次数的循环(循环次数等于列表元素个数),其语法结构如下:
for var in con1 con2 con3
do
command
done
第一次循环时,$var的内容为con1;
第二次循环时,$var的内容为con2;
第三次循环时,$var的内容为con3;
示例1
[root@localhost ~]# vim fruit.sh
#!/bin/bash
for FRUIT in apple orange banana pear
do
echo "$FRUIT is john's favorite!"
done
echo "no more fruits"
[root@localhost ~]# bash fruit.sh
apple is john's favorite!
orange is john's favorite!
banana is john's favorite!
pear is john's favorite!
no more fruits
示例2
为了便于修改,可以先定义变量,然后再用变量替代列表。
#!/bin/bash
fruits="apple orange banana pear"
for FRUIT in ${fruits}
do
echo "$FRUIT is john's favorite!"
done
echo "no more fruits"
[root@localhost ~]# bash fruit.sh
apple is john's favorite!
orange is john's favorite!
banana is john's favorite!
pear is john's favorite!
no more fruits
示例3
当然变量也可以是数字
[root@localhost ~]# vim list.sh
#!/bin/bash
for var in {1..10}
do
echo "loop $var times"
done
[root@localhost ~]# bash list.sh
loop 1 times
loop 2 times
loop 3 times
loop 4 times
loop 5 times
loop 6 times
loop 7 times
loop 8 times
loop 9 times
loop 10 times
示例4
也可以利用这个去求和
[root@localhost ~]# vim qiuhe1.sh
#!/bin/bash
sum=0
for i in `seq 1 100`
do
let sum+=${i}
done
echo "total:${sum}"
[root@localhost ~]# bash qiuhe1.sh
total:5050
示例5
还可以使用“步长”计算1到100的奇数和
[root@localhost ~]# vim jishu.sh
#!/bin/bash
sum=0
for VAR in `seq 1 2 100`
#for VAR in $(seq 1 2 100)
do
let "sum+=${VAR}"
done
echo "Total: ${sum}"
[root@localhost ~]# bash jishu.sh
Total: 2500
六、类C的for循环
格式如下:
for ((expression1;expression2;expression3))
do
command
done
相关解释
expression1:为初始化语句,一般用作变量定义和初始化;
expression2:为判断表达式,用于测试表达式返回值并以此控制循环,返回值为真则循环继续,返回值为假则退出循环;
expression3:用于变量值修改,从而影响expression2的返回值,并以此影响循环行为;
示例1
[root@localhost ~]# vim c.sh
#!/bin/bash
for ((i=1;i<=10;i++))
do
echo "$i"
done
[root@localhost ~]# bash c.sh
1
2
3
4
5
6
7
8
9
10
示例2
倒数5秒
[root@localhost ~]# vim daoshu.sh
#!/bin/bash
echo "准备倒数5秒:"
for i in `seq 5 -1 1`
do
echo -en "$i";sleep 1
done
echo -e "开始"
[root@localhost ~]# bash daoshu.sh
准备倒数5秒:
54321开始
示例3
批量添加用户
[root@localhost ~]# cat >> user.txt << EOF
> zhangsan
> lisi
> wangwu
> zhaoliu
> EOF
[root@localhost ~]# cat user.txt
zhangsan
lisi
wangwu
zhaoliu
[root@localhost ~]# vim user.sh
#!/bin/bash
for i in $(cat /root/user.txt)
do
useradd $i
echo "123.com" | passwd --stdin $i
done
[root@localhost ~]# bash user.sh
更改用户 zhangsan 的密码 。
passwd:所有的身份验证令牌已经成功更新。
更改用户 lisi 的密码 。
passwd:所有的身份验证令牌已经成功更新。
更改用户 wangwu 的密码 。
passwd:所有的身份验证令牌已经成功更新。
更改用户 zhaoliu 的密码 。
passwd:所有的身份验证令牌已经成功更新。
[root@localhost ~]# tail -4 /etc/passwd
zhangsan:x:2021:2021::/home/zhangsan:/bin/bash
lisi:x:2022:2022::/home/lisi:/bin/bash
wangwu:x:2023:2023::/home/wangwu:/bin/bash
zhaoliu:x:2024:2024::/home/zhaoliu:/bin/bash
总结
(1)while循环的特长是执行守护进程以及希望循环不退出持续执行的情况,用于频率小于一分钟循环处理。
其他的while循环几乎都可以被for循环替代。
(2)case语句可以替换if语句,一般在系统启动脚本传入少量固定规则字符串,用case语句。
其他普通判断多用if语句。
(3)if和for语句最常用,其次是while(守护进程),case(服务启动脚本)。
各个语句的应用场景:
条件表达式,简单的判断(文件是否存在,字符串是否为空等)。
if取值判断,不同值数量较少的情况。
for循环正常的循环处理,最常用。
while循环守护进程、无限循环(sleep)。
case服务启动脚本,菜单。
函数逻辑清晰,减少重复语句。