这里写目录标题
- 测试
- 条件判断
- function功能
- while循环、until do done(不定循环)
- for循环
- 类C的for循环
测试
1.测试
在程序运行中经常需要根据实际情况来运行特定的命令或代码块。比如判断某个文件或目录是否存在?如果不存在,则需要创建。
例如:
[root@localhost ~]# ls /var/log/messages/var/log/messages[root@localhost ~]# echo $?0[root@localhost ~]# ls /var/log/messages044ls: 无法访问/var/log/messages044: 没有那个文件或目录[root@localhost ~]# echo $?2
测试的结构主要有两种:
第一种:使用test命令
test expression
其中expression是一个表达式,可以是算术比较、字符串比较、文本和文件属性比较等。
第二种:使用[]
[ expression ]
需要注意的是括号和表达式expression之间都有空格。推荐使用第二种方式。
例如:判断文件是否存在
[root@localhost ~]# test -e /var/log/messages[root@localhost ~]# echo $?0[root@localhost ~]# [ -e /var/log/messages ][root@localhost ~]# echo $?0
其他的文件测试参数:
-w file:当文件存在且为可写文件时返回真,否则为假;-r 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旧时,返回为真,否则为假;常用的参数:-e:文件或目录是否存在;-f:文件存在且为普通文件;-d:目录是否存在。
关于权限方面:
-w:当文件存在且为可写;-r:当文件存在且为可读;-x:当文件存在且为可执行;
[root@localhost ~]# vim rwx.sh#!/bin/bashread -p \"what file do you want to test?:\" filenameif [ ! -e \"$filename\" ];thenecho \"the file does not exist.\"exit 1fiif [ -r \"$filename\" ];thenecho \"$filename is readable.\"fiif [ -w \"$filename\" ];thenecho \"$filename is writeable.\"fiif [ -x \"$filename\" ];thenecho \"$filename is executable.\"fi[root@localhost ~]# bash rwx.shwhat file do you want to test?:/etc/etc is readable./etc is writeable./etc is executable.
条件判断
if判断结构
if是最简单的判断语句,可以针对测试结果做相应处理;如果测试为真则运行相关代码,其语法结构如下:
if expression;thencommandfi
如果expression测试返回真,则执行command。如果执行的不止一条命令,则不同命令之间用换行符隔开,如下所示:
if expression;thencommand1command2...fi
常用参数
eq:equql平等的,相等的.gt:greater较大的,大于.lt:less then小于.-eq:检测两个数是否相等,相等返回true。否则返回false;-ne:检测两个数是否不相等,不相等返回true。否则返回true;-gt:检测左边的数是否大于右边的,如果是,则返回true。否则返回false;-lt:检测左边的数是否小于右边的,如果是,则返回true。否则返回true;-ge:检测左边的数是否大于等于右边的,如果是,则返回true。否则返回false。-le:检测左边的数是否小于等于右边的,如果是,则返回 true。否则返回true。
例子:写一个脚本,判断用户得分情况。
如果小于30分,那么输出“有点太低了吧!”
如果大于等于30分且小于60分,则输出\”加油!\”
如果大于等于60分且小于85分,则输出“不错,继续努力!”
如果大于等于85分且小于100分,则输出“优秀!”
如果等于100分,则输出“人才啊!”
1.利用if…then
[root@localhost ~]# vim score.sh#!/bin/bashecho -n \"please input a score:\"read SCOREif [ \"$SCORE\" -lt 30 ];thenecho \"有点太低了吧!\"fiif [ \"$SCORE\" -ge 30 -a \"$SCORE\" -lt 60 ];thenecho \"加油!\"fiif [ \"$SCORE\" -ge 60 -a \"$SCORE\" -lt 85 ];thenecho \"不错,继续努力!\"fiif [ \"$SCORE\" -ge 85 -a \"$SCORE\" -lt 100 ];thenecho \"优秀!\"fiif [ \"$SCORE\" -eq 100 ];thenecho \"人才啊!\"fi
2.if/else
如果if后的判断成立,则执行then后面的内容;否则执行else后面的内容。语法结构如下:
if expression;thencommandelsecommandfi
[root@localhost ~]# vim check.sh#!/bin/bashread -p \"请输入你要查询的目录或文件名:\" FILEif [ -e $FILE ];thenecho \"$FILE 有有有!\"elseecho \"$FILE 没这玩意!\"fi[root@localhost ~]# bash check.sh请输入你要查询的目录或文件名:/etc/etc 有有有![root@localhost ~]# bash check.sh请输入你要查询的目录或文件名:cdacda 没这玩意!
3.if/elif/else判断结构
可以代替if嵌套,语法结构如下:
if expression1;thencommand1elif expression2;thencommand2elif expression3;thencommand3...fi
练习:写一个脚本,查询用户是否存在,如果存在,则输出“有此用户,它的UID为:”,如果没有则输出“没有此用户。”
1.如果使用if判断语句,则可以这样编写:
[root@localhost ~]# vim testusr.sh#!/bin/bashread -p \"请输入想要查询的用户名:\" USERid $USER &> /dev/nullif [ $? -ne 0 ]thenuseradd $USERecho \"没有此用户,并已经为您添加此用户。添加后此用户UID为 `id -u $USER`\"elseecho \"此用户已经存在,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/bashread -p \"请输入想要查询的用户名:\" USERid $USER &> /dev/nullif [ $? -ne 0 ]thenread -p \"没有此用户,请问是否创建此用户?Y/N\" YNif [ $YN == Y ];thenuseradd $USERecho \"用户添加成功,用户ID为`id -u $USER`\"elif [ $YN == N ];thenecho \"好的,不进行任何操作,欢迎下次再 来!\"elseecho \"您的输入有误!\"fielseecho \"此用户已经存在,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 ~]#[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/bashecho \"您能输入的颜色有:红色、绿色、黄色、蓝色、紫色、青色、白色\"read -p \"请输入你要选取的颜色:\" COLORif [ $COLOR == \"红色\" ];thenecho -e \"\\e[1;31m红色\\e[0m\"elif [ $COLOR == \"绿色\" ];thenecho -e \"\\e[1;32m绿色\\e[0m\"elif [ $COLOR == \"黄色\" ];thenecho -e \"\\e[1;33m黄色\\e[0m\"elif [ $COLOR == \"蓝色\" ];thenecho -e \"\\e[1;34m蓝色\\e[0m\"elif [ $COLOR == \"紫色\" ];thenecho -e \"\\e[1;35m紫色\\e[0m\"elif [ $COLOR == \"青色\" ];thenecho -e \"\\e[1;36m青色\\e[0m\"elif [ $COLOR == \"白色\" ];thenecho -e \"\\e[1;37m白色\\e[0m\"elseecho \"您的输入有误!\"fi[root@localhost ~]# bash yanse.sh您能输入的颜色有:红色、绿色、黄色、蓝色、紫色、青色、白色请输入你要选取的颜色:红色红色[root@localhost ~]# bash yanse.sh您能输入的颜色有:红色、绿色、黄色、蓝色、紫色、青色、白色请输入你要选取的颜色:蓝色蓝色[root@localhost ~]# bash yanse.sh您能输入的颜色有:红色、绿色、黄色、蓝色、紫色、青色、白色请输入你要选取的颜色:白色白色[root@localhost ~]# bash yanse.sh您能输入的颜色有:红色、绿色、黄色、蓝色、紫色、青色、白色请输入你要选取的颜色:你您的输入有误!
4.case判断结构
case判断结构多用于多种可能情况下的分支选择。语法结构如下:
case var invar1)command;;var2)command;;var3)command;;...*)command6;;esac
其原理为从上而下依次比较var和var1、var2、var3的值是否相等,如果匹配则执行其后面的命令,都不匹配则执行最后的命令。需要注意的是case判断结构中的var1、var2、var3等这些值只能是常量或正则表达式。
例子:检测当前操作系统
[root@localhost ~]# vim os.sh#!/bin/bashOS=`uname -s`case \"$OS\" inFreeBSD)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.shthis is Linux
例子:把颜色的例子用case改写
[root@localhost ~]# vim yanse.sh#!/bin/bashecho \"您能输入的颜色有:红色、绿色、黄色、蓝色、紫色、青色、白色\"read -p \"请输入你要选取的颜色:\" COLORcase \"$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的语法
结构如下:
function fname () {command}
fname就是需要自动执行的指令名称,而程序段就是我们要他执行的内容了。要注意的是,因为shell script的执行方式是由上而下,由左而右,因此在shell script当中function 的设置一定要在程序的最前面,这样才能够在执行时被找到。
例子:使用function功能简化代码。
[root@localhost ~]# vim zhuangbei.sh#!/bin/bashread -p \"请输入你要查询的装备类别:\" INPUTread -p \"请输入装备的分数:\" SCOREfunction fenshu () {if [ $SCORE -le 30 ];thenecho \"品相极品渣!\"elif [ $SCORE -gt 30 -a $SCORE -le 65 ];thenecho \"渣渣!\"elif [ $SCORE -gt 65 -a $SCORE -le 95 ];thenecho \"嗯,这才像个样!\"elif [ $SCORE -gt 95 ];thenecho \"谁与争锋!\"elseecho \"输入有误!\"fi}function chongzhu () {read -p \"请问是否选择重铸!Y/N\" YNif [ $YN == Y ];thenread -p \"好的,用户选择重铸\"elif [ $YN == N ];thenecho \"用户不重铸,886!\"elseecho \"输入有误!\"fi}case $INPUT intoukui)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几种。
while循环
while [ condition ] 状态的判读do 循环的开始commanddone 循环的结束
while的中文是“当…时”,所以这种方式说的是“当condition条件成立时进行循环,直到condition的条件不成立才停止”。
untile循环
until [ condition ]docommanddone
这种方式恰恰与while相反,它说的是“当condition条件成立时,就终止循环,否则就持续进行循环的程序段。
1.用while举个例子:
[root@localhost ~]# vim while.sh#!/bin/bashwhile [ \"${yn}\" != \"yes\" ]doread -p \"请输入\'yes\'退出: \" yndoneecho \"退出成功!.\"[root@localhost ~]# bash while.sh请输入\'yes\'退出: no请输入\'yes\'退出: no请输入\'yes\'退出: yes退出成功!.
2.如果是until的话,那么判断条件相反。
[root@localhost ~]# vim until.sh#!/bin/bashuntil [ \"${yn}\" == \"yes\" ]doread -p \"请输入\'yes\'退出: \" yndoneecho \"退出成功!.\"[root@localhost ~]# bash until.sh请输入\'yes\'退出: no请输入\'yes\'退出: yes退出成功!.
现在我们来看另外一个脚本,关于变量取值
[root@localhost ~]# vim 1.sh#!/bin/bashi=0let i=$i+1echo $i[root@localhost ~]# bash 1.sh1
关于下面那个i的值已经是新的变量了,格式还可以这么写
let i=$i+1 ----- let i+=1 ------ let i++三者等价
我们知道那个之后,就可以求和。比如1+2+3+4…+100的值是多少?我们就可以用到。
[root@localhost ~]# vim qiuhe.sh#/bin/bashs=0 i=0while [ $i != 100 ]dolet i+=1let s=$s+$idoneecho \"1+2+3...+100等于$s\"[root@localhost ~]# bash qiuhe.sh1+2+3...+100等于5050
这个时候,我们再看一个例子,编写一个脚本:让用户输入密码,如果输入错误超过5
次,就退出。这个时候有条件,当用户输入超过5次,就提示用户已经错误了5次,密码已经被锁,并退出。
[root@localhost ~]# vim denglu.sh#!/bin/bashi=1while [ \"$MIMA\" != \"123.com\" -a $i -le 5 ]dolet i+=1read -p \"请输入密码:\" MIMAdoneif [ $i -le 5 ];thenecho \"登录成功!\"elseecho \"已经超过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 con3docommanddone\\1.第一次循环时,$var的内容为con1;\\2.第二次循环时,$var的内容为con2;\\3.第三次循环时,$var的内容为con3;
[root@localhost ~]# vim fruit.sh#!/bin/bashfor FRUIT in apple orange banana peardoecho \"$FRUIT is john\'s favorite!\"doneecho \"no more fruits\"[root@localhost ~]# bash fruit.shapple is john\'s favorite!orange is john\'s favorite!banana is john\'s favorite!pear is john\'s favorite!no more fruits
为了便于修改,可以先定义变量,然后再用变量替代列表
#!/bin/bashfruits=\"apple orange banana pear\"for FRUIT in ${fruits}doecho \"$FRUIT is john\'s favorite!\"doneecho \"no more fruits\"[root@localhost ~]# bash fruit.shapple is john\'s favorite!orange is john\'s favorite!banana is john\'s favorite!pear is john\'s favorite!no more fruits
当然变量也可以是数字
[root@localhost ~]# vim list.sh#!/bin/bashfor var in {1..10}doecho \"loop $var times\"done[root@localhost ~]# bash list.shloop 1 timesloop 2 timesloop 3 timesloop 4 timesloop 5 timesloop 6 timesloop 7 timesloop 8 timesloop 9 timesloop 10 times
所以我们也可以利用这个去求和
[root@localhost ~]# vim qiuhe1.sh#!/bin/bashsum=0for i in `seq 1 100`dolet sum+=${i}doneecho \"total:${sum}\"[root@localhost ~]# bash qiuhe1.shtotal:5050
还可以使用“步长”计算1到100的奇数和
[root@localhost ~]# vim jishu.sh#!/bin/bashsum=0for VAR in `seq 1 2 100`#for VAR in $(seq 1 2 100)dolet \"sum+=${VAR}\"doneecho \"Total: ${sum}\"[root@localhost ~]# bash jishu.shTotal: 2500
类C的for循环
格式如下:
for ((expression1; expression2; expression3))docommanddone
expression1:为初始化语句,一般用作变量定义和初始化;
expression2:为判断表达式,用于测试表达式返回值并以此控制循环,返回值为真则循环继续,返回值为假则退出循环;
expression3:用于变量值修改,从而影响expression2的返回值,并以此影响循环行为。
[root@localhost ~]# vim c.sh#!/bin/bashfor ((i=1;i<=10;i++))doecho \"$i\"done[root@localhost ~]# bash c.sh12345678910
例子1:倒数5秒
[root@localhost ~]# vim daoshu.sh#!/bin/bashecho \"准备倒数5秒:\"for i in `seq 5 -1 1`doecho -en \"$i\";sleep 1doneecho -e \"开始\"[root@localhost ~]# bash daoshu.sh准备倒数5秒:54321开始
例子2:批量添加用户
[root@localhost ~]# cat >> user.txt << EOF> zhangsan> lisi> wangwu> zhaoliu> EOF[root@localhost ~]# cat user.txtzhangsanlisiwangwuzhaoliu[root@localhost ~]# vim user.sh#!/bin/bashfor i in $(cat /root/user.txt)douseradd $iecho \"123.com\" | passwd --stdin $idone[root@localhost ~]# bash user.sh更改用户 zhangsan 的密码 。passwd:所有的身份验证令牌已经成功更新。更改用户 lisi 的密码 。passwd:所有的身份验证令牌已经成功更新。更改用户 wangwu 的密码 。passwd:所有的身份验证令牌已经成功更新。更改用户 zhaoliu 的密码 。passwd:所有的身份验证令牌已经成功更新。[root@localhost ~]# tail -4 /etc/passwdzhangsan:x:2021:2021::/home/zhangsan:/bin/bashlisi:x:2022:2022::/home/lisi:/bin/bashwangwu:x:2023:2023::/home/wangwu:/bin/bashzhaoliu: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服务启动脚本,菜单。
函数逻辑清晰,减少重复语句。