六、使用结构化命令
使用if-then语句
语法格式
if command
then
commands
fi
注意:if是根据命令退出码来判断(echo $?=0),如果是0,则表示为真,执行后面的命令
举例
[root@tzPC ~]# cat if-1.sh #!/bin/bash if ls /mnt then echo "It worked" fi
if-then-else语句
语法格式
if command ; then commands else commands fi
举例
[root@tzPC if]# cat if_2.sh #!/bin/bash testuser=tz if grep $testuser /etc/passwd >/dev/null then echo "The bash files for user $testuser are:" ls -a /home/$testuser/.b* echo else echo "The user $testuser does not exist on this system." echo fi
嵌套if
语法结构
if command1;then commands elif command2;then commands elif command3;then commands ... else more commands fi
举例
查看tz用户是否存在
[root@tzPC ~]# ls -d /home/tz /home/tz [root@tzPC ~]# echo $? 0
脚本
[root@tzPC ~]# cat if-3.sh #!/bin/bash read -p "input a username:" name if grep $name /etc/passwd ;then echo "the user $name exists on this system!" elif ls -d /home/$name;then echo "the user $name not exists on this system!" echo "$name has a home directory" else echo "the user $name not exists on this system" echo "$name not has a direcotry" fi
test命令
test命令用于检查某个条件是否成立,如果成立就会退出并返回状态码0。不成立就会返回非0退出状态码。
test命令可以判断三类条件
- 数值比较
- 字符串比较
- 文件比较
语法格式
if test condition
then
commands
fi
语法格式2
注意方括号之间的空格
if [ condition ]
then
commands
fi
如果不写condition会以非0的退出状态码退出
[root@tzPC test]# bash test6.sh No expression returns a False
#脚本如下 [root@tzPC test]# cat test6.sh #!/bin/bash if test then echo "No expression returns a True" else echo "No expression returns a False" fi
如果condition有内容,返回的退出码就为0,如果没有则不为0
[root@tzPC test]# bash test6.sh No expression returns a True
#脚本如下
[root@tzPC test]# cat test6.sh #!/bin/bash my_variable="Full"
#my_variable="" 则会返回非0 if test $my_variable then echo "No expression returns a True" else echo "No expression returns a False" fi
数值比较
参数 |
说明 |
示例 |
-eq |
等于则为真 |
n1 -eq n2 |
-ne |
不等于则为真 |
n1 -ne n2 |
-gt |
大于则为真 |
n1 -gt n2 |
-ge |
大于等于则为真 |
n1 -ge n2 |
-lt |
小于则为真 |
n1 -lt n2 |
-le |
小于等于则为真 |
n1 -le n2 |
举例
[root@tzPC ~]# cat test-1.sh
#!/bin/bash
if test 2 -eq 1 ; then
echo ok
else
echo err
fi
或者
[root@tzPC ~]# cat test-2.sh
#!/bin/bash
if [ 2 -eq 2 ] ;then
echo ok
else
echo err
fi
举例
[root@tzPC test]# bash numeric_test.sh
The test value 10 is greater than 5
The values are different
#脚本如下 [root@tzPC test]# cat numeric_test.sh #!/bin/bash value1=10 value2=11 if [ $value1 -gt 5 ] then echo "The test value $value1 is greater than 5" fi # if [ $value1 -eq $value2 ] then echo "The values are equal" else echo "The values are different" fi
数值比大小
[root@tzPC ~]# cat test2.sh
#!/bin/bash
read -p "input var1 var2:" var1 var2
if [ $var1 -gt $var2 ] ;then
echo "$var1 > $var2"
elif [ $var1 -lt $var2 ] ;then
echo "$var1 < $var2"
else
echo "$var1=$var2"
fi
注意,bash shell只能处理整数,在condition 中写浮点数比较会报错。
字符串比较
参数. |
说明 |
str1 == str2 或者 str1 = str2 |
检查str1 是否跟 str2相同 |
str1 != str2 |
检查str1 是否跟 str2不同 |
-z str1 |
检查str1 长度是否为0 |
-n str1 |
检查str1长度是否非0 |
str1 > str2 |
检查str1是否比str2大 |
str1 < str2 |
检查str1是否比str2小 |
举例
[root@tzPC ~]# cat test3.sh
#!/bin/bash
read -p "input your name :" name
if [ $name == "root" ] ;then
echo "you are super administrator"
else
echo "you are a general user"
fi
字符串比较需要注意
- 大于号和小于号必须转义,要不然SHELL会把它当成重定向符号
- 大于和小于它们的顺序和sort排序是不一样的
- 在test比较测试中,它使用的是ASCII顺序,大写字母是小于小写字母的;sort命令使用的是系统的本地化语言设置中定义的排序顺序,对于英语,本地化设置制定了在排序中小写字母会出现在大写字母前。
举例
[root@tzPC test]# bash test4.sh test > Test #在比较测试中大写字母是小于小写字母的 [root@tzPC test]# sort testfile test Test #在sort中大写字母是大于小写字母的,sort默认从小到大排序
#脚本如下 [root@tzPC test]# cat test4.sh #!/bin/bash var1=test var2=Test if [ $var1 \> $var2 ] ;then echo "$var1 > $var2" else echo "$var1 < $var2" fi
-z跟-n判断未被定义的变量长度会被判为0
文件比较
参数 |
.说明 |
-e file |
检查文件或目录是否存在 |
-r file |
检查文件存在且可读 |
-w file |
检查文件存在且可写 |
-x file |
检查文件存在且可执行 |
-s file |
检查文件存在且至少有一个字符 |
-d file |
检查文件存在且为目录 |
-f file |
检查文件存在且为普通文件 |
-c file |
检查文件存在且为字符型文件 |
-b file |
检查文件存在且为块特殊文件 |
file1 -nt fle2 |
检查file1是否比file2新 |
file1 -ot file2 |
检查file1是否比file2旧 |
检查目录是否存在
-d会检查指定的目录是否存在于系统中
[root@tzPC script]# bash test11.sh The /home/tz directory exists /home/tz
[root@tzPC script]# cat test11.sh #!/bin/bash jump_directory=/home/tz if [ -d $jump_directory ];then echo "The $jump_directory directory exists" cd $jump_directory pwd else echo "The $jump_directory direcotry does not exist" fi
检查文件或目录是否存在
#!/bin/bash
if [ -e /etc/passwd ] ; then
echo ok
else
echo err
fi
举例
[root@tzPC ~]# test -e /etc/aaa.txt && echo ok || echo err
检查文件是否存在
[root@tzPC script]# bash test13.sh The item being checked: /root The item,/root,does exits. But is it a file? No,/root is not a file.
#脚本如下 [root@tzPC script]# cat test13.sh #!/bin/bash item_name=$HOME echo echo "The item being checked: $item_name" echo if [ -e $item_name ]; then echo "The item,$item_name,does exits." echo "But is it a file?" echo if [ -f $item_name ];then ehco "Yes,$item_name is a file." else echo "No,$item_name is not a file." fi else echo "The item,$item_name,does not exist." echo "Nothing to update" fi
检查所属关系
-O可以测试你是否是文件的属主
root@tzPC script]# bash test18.sh You are the owner of the /etc/passwd file [root@tzPC script]# cat test18.sh #!/bin/bash if [ -O /etc/passwd ];then echo "You are the owner of the /etc/passwd file" else echo "Sorry,you are not the owner of the /etc/passwd file" fi
检查默认属主关系
-G只会检查文件的默认组,是否为用户的默认组,并不会检查用户所属的所有组。
检查文件日期
对两个文件的创建日期进行比较
-nt比较一个文件是否比另一个文件新
-ot比较一个文件是否比另一个文件旧
注意:使用前须先确认文件是否存在
[root@tzPC script]# bash test20.sh The test18.sh file is newer than test11.sh the test11.sh file is older than the test18.sh [root@tzPC script]# ll 总用量 16 -rw-r--r--. 1 root root 199 8月 16 22:31 test11.sh -rw-r--r--. 1 root root 158 8月 16 23:13 test18.sh
#脚本如下 [root@tzPC script]# cat test20.sh #!/bin/bash if [ test11.sh -nt test18.sh ];then echo "The test11.sh file is newer than test18.sh" else echo "The test18.sh file is newer than test11.sh" fi if [ test11.sh -ot test18.sh ];then echo "the test11.sh file is older than the test18.sh" fi
清空日志目录
#!/bin/bash
# clear /var/log/messages
#确定当前是root用户
if [ $USER != "root" ];then
echo "你必须使用root用户才能执行脚本"
exit 10 #直接退出,并返回10
fi
#判断文件是否存在
if [ ! -f /var/log/messages ];then
echo "文件不存在"
exit 12
fi
#保留最近100行的日志内容
tail -100 /var/log/messages > /var/log/mesg.tmp
#日志清理
>/var/log/messages
#cat /dev/null > /var/log/messages
mv /var/log/mesg.tmp /var/log/messages
echo "Logs clean up"
注:退出码 exit ,取值范围是0-255
退出码可以使用$?得到
复合条件测试
判断第一种:两个条件都为真或有一个为真就执行
注意&&在[]外
if [ command1 ] && (||) [ command2 ]; then commands elif [ command3 ] && (||) [ command4 ]; then commands else commands fi
判断第二种
注意-a在[]内
if [ command1 -a (-o) command2 -a (-o) command3 ]; then elif [command3 -a (-o) command4 ]; then else commands fi
判断第三种
[[...]]支持*,<,>等符号且不需要转义
if [[ command1 && (||) command2 ]]; then
commands elif [[ command3 && (||) command4 ]]; then else commands fi
使用双括号(())
- 双括号可以在比较过程中使用高级数学表达式。
- 双括号中可以赋值,且不用转义。
符号 | 描述 |
val++ | 后增 |
val-- | 后减 |
++val | 先增 |
--val | 先减 |
! | 求反 |
- | 位求反 |
** | 幂运算 |
<< | 左位移 |
>> | 右位移 |
& | 位布尔和 |
| | 位布尔或 |
&& | 逻辑和 |
|| | 逻辑或 |
注意括号左右要有空格。
[root@tzPC script]# bash test23.sh The square of 10 is 100 [root@tzPC script]# cat test23.sh #!/bin/bash val1=10 if (( $val1 ** 2 > 90 ));then ((val2 =$val1 ** 2 )) echo "The square of $val1 is $val2" fi
使用双方括号
- 双方括号支持模式匹配
- [[...]]支持*,<,>等符号且不需要转义
举例
[root@tzPC ~]# if [[ $USER == ro* ]] ;then echo "hello,$USER" ;else echo "$USER is not root"; fi hello,root
当只有一个[],r*表示字符串r*,而不是r通配符*
[root@tzPC ~]# if [ $USER == ro* ] ;then echo "hello,$USER" ;else echo "$USER is not root"; fi root is not root
这时候需要这样写
[root@tzPC ~]# if [[ $USER == [a-z]oot ]] ; then echo "hello,$USER" ; else echo $USER not ; fi hello,root
[[ 。。。 ]]和[ 。。。]的区别汇总:
1、所有的字符与逻辑运算符直接用“空格”分开,不能连到一起。
2、在[… ]表达式中,常见的> 、<需要加转义符\,大小比较
3、进行逻辑运算符&& 、||比较时;如果用的[ ]符号,则用在外面,如[… ] && [… ] || [ …]如果在[…]里面进行逻辑与或的比较,则用-a、-o进行表示,如[ x = y –a x < z –o x > m ]
4、[[… ]] 运算符只是[… ]运算符的扩充;能够支持< 、>符号运算不需要转义符;它还是以字符串比较大小。里面支持逻辑运算符 || 、 && , 不再使用-a 、-o
5、[[…]] 用 && 而不是 -a 表示逻辑“与”;用 || 而不是 -o表示逻辑“或”
6、[[… ]]可以进行算术扩展,而[ ... ]不可以
7、[[...]]能用正则,而[...]不行
8、双括号(( ))用于数学表达式
9、双方括号号[[ ]]用于高级字符串处理,比如“模糊匹配”
shell常见通配符:
字符 |
含义 |
实例 |
* |
匹配 0 或多个字符 |
a*b a与b之间可以有任意长度的任意字符, 也可以一个也没有, 如aabcb, axyzb, a012b, ab。 |
? |
匹配任意一个字符 |
a?b a与b之间必须也只能有一个字符, 可以是任意字符, 如aab, abb, acb, a0b。 |
[list] |
匹配 list 中的任意单一字符 |
a[xyz]b a与b之间必须也只能有一个字符, 但只能是 x 或 y 或 z, 如: axb, ayb, azb。 |
[!list] |
匹配 除list 中的任意单一字符 |
a[!0-9]b a与b之间必须也只能有一个字符, 但不能是阿拉伯数字, 如axb, aab, a-b。 |
[c1-c2] |
匹配 c1-c2 中的任意单一字符 如:[0-9] [a-z] |
a[0-9]b 0与9之间必须也只能有一个字符 如a0b, a1b... a9b。 |
{string1,string2,...} |
匹配 sring1 或 string2 (或更多)其一字符串 |
a{abc,xyz,123}b a与b之间只能是abc或xyz或123这三个字符串之一。 |
举例
[root@tzPC ~]# ls /etc/*.conf
/etc/asound.conf /etc/host.conf /etc/libaudit.conf /etc/man_db.conf /etc/rsyslog.conf /etc/sudo-ldap.conf
/etc/dracut.conf /etc/kdump.conf /etc/libuser.conf /etc/mke2fs.conf /etc/sestatus.conf /etc/sysctl.conf
/etc/e2fsck.conf /etc/krb5.conf /etc/locale.conf /etc/nsswitch.conf /etc/sos.conf /etc/vconsole.conf
/etc/fuse.conf /etc/ld.so.conf /etc/logrotate.conf /etc/resolv.conf /etc/sudo.conf /etc/yum.conf
[root@tzPC ~]# ls /etc/???.conf
/etc/sos.conf /etc/yum.conf
[root@tzPC ~]# touch /home/tz/a{1,2,3}.txt
[root@tzPC ~]# ls /home/tz/
a1.txt a2.txt a3.txt root
[root@tzPC ~]# ls /home/tz/a[123].txt
/home/tz/a1.txt /home/tz/a2.txt /home/tz/a3.txt
[root@tzPC ~]# ls /home/tz/a[1,2,3].txt
/home/tz/a1.txt /home/tz/a2.txt /home/tz/a3.txt
case命令
case命令会将指定的变量与不同模式进行比较。
根据变量的不同取值进行比较从而分别执行不同命令操作
适用于多分支,是一个多选择语句
case 变量或表达式 in
变量或表达式1)
命令序列1
;;
变量或表达式2)
命令序列2
;;
……
*)
默认命令序列
esac
举例
[root@tzPC script]# cat test26.sh #!/bin/bash case $USER in tz | root) echo "Welcome,$USER" echo "Please enjoy your visit" ;; testing) echo "Special testing account" ;; rich) echo "Do not forget to log off when you're done" ;; *) echo "Sorry,you are not allowed here" ;; esac
举例2
[root@tzPC ~]# cat case1.sh
#!/bin/bash
cat <<eof
***************
* 1. backup *
* 2. copy *
* 3. quit *
***************
eof
read -p "Input a choose:" OP
case $OP in
1|backup)
echo "BACKUP..."
;;
2|copy)
echo "COPY..."
;;
3|quit)
exit
;;
*)
echo "error"
esac
exit 后边写返回值,默认是0,可以通过$?取得。
举例2:编写一个启动apache服务脚本
安装httpd服务
yum -y install httpd
脚本
[root@tzPC ~]# cat case2.sh
#!/bin/bash
case $1 in
start)
systemctl $1 httpd
ps aux|grep httpd
;;
stop)
systemctl $1 httpd
ps aux|grep httpd
;;
status)
systemctl $1 httpd
ps aux|grep httpd
;;
restart)
systemctl $1 httpd
ps aux|grep httpd
;;
*)
echo "USAGE: $0 start|stop|restart"
esac
学习来自:《Linux命令行与Shell脚本大全 第3版》第12章