本博客内容来自《Linux命令行与shell脚本编程大全》第十二、十三章
目录
1、使用 if-then 语句
2、if-then-else语句
3、嵌套if
4、test命令
数值比较
字符串比较
字符串相等性
字符串顺序
字符串大小
文件比较
5、复合条件测试
6、高级特性
使用双括号
使用双方括号
7、case命令
8、for命令
读取列表中的值
读取列表中复杂的值
从变量读取列表
从命令中读取值
更改字段分隔符
用通配符读取目录
9、使用C语言风格的for命令
10、while命令
if-then语句格式如下:
if command
then
commands ##多个命令行可以依次执行
fi
或者有些人喜欢这么写:
if command; then
commands
fi
该命令会运行if后面的命令,如果该命令的退出状态码是0(成功运行),位于then部分的命令就会被执行,否则不执行。下面是一个简单的例子:
[root@izwz9194nuv8g0cwqfqsh3z 12]# ./test1.sh
/root/12
it workded!
[root@izwz9194nuv8g0cwqfqsh3z 12]# cat test1.sh
#!/bin/bash
# testing the if-then
if pwd
then
echo it workded!
fi
格式为:
if command
then
commands
else
commands
fi
这个就与我们比较熟悉的if-else语法有点相似了~
嵌套语句在判断多个逻辑时非常有效:
if command
then
commands
else
...
if command
then
commands
fi
fi
上述表达式虽然满足要求,但是不易阅读,可以用以下形式:
if command1
then
commands
elif command2 ##很像我们JAVA里面的 else if 形式
then
commands
fi
那么,也就不难可以知道还有如下形式:
if command1
then
commands
elif command2
then
commands
else
commands
fi
由于if-then语句只能测试命令退出状态码这一条件,无法对其他条件进行判定,所以功能有限。
test命令提供了在if-then语句中测试不同条件的途径。test命令的格式为:
test condition
与if-then语句结合起来,形式为:
if test condition
then
command
fi
test后面的condition部分一定要写,否则会返回非零的退出状态码
常见的test后面跟的condition举例如下:
test $variable #测试变量是否为空,非空时if test返回0
而另一种条件测试方法无需声明test命令:
if [ condition ] ##condition前后必须加上一个空格,否则报错
then
commands
fi
test命令可以判断三类条件
数值比较
字符串比较
文件比较
最常用的情形,对两个数值进行比较,但是要注意,必须得是整数:
n1 -eq n2 ##检查是否相等
n1 -ge n2 ##大于等于
n1 -gt n2 ##大于
n1 -le n2 ##小于等于
n1 -lt n2 ##小于
n1 -ne n2 ##不相等
举例如下:
[root@izwz9194nuv8g0cwqfqsh3z 12]# ./test2.sh
the test value 10 is greater than 5
[root@izwz9194nuv8g0cwqfqsh3z 12]# cat test2.sh
#!/bin/bash
value1=10
if [ $value1 -gt 5 ]
then
echo the test value $value1 is greater than 5
fi
比较字符串比较繁琐
格式
str1 = str2 ##检查str1是否和str2相同
str1 != str2
需要注意的地方:
1.大于号和小于号必须转义,否则shell会把他们当做重定向符号,把字符串值当做文件名
2.大于和小于顺序和sort命令所采用的不同
由于问题一,因此在比较字符串时需要使用:
[ $val1 \> $val2 ]
对于问题二,仅在比较大小写字母时会遇到,在比较测试中,大写字母被认为小于小写字母,但sort命令相反。
-n和-z参数可以检查一个变量是否含有数据
if [ -n $val ] ##判断变量val是否为非null(空)可以把-n中的-理解为取反的意思
if [ -z $val ] ##判断变量val是否长度为0
这类比较测试可能是shell中最为强大且用的最多的形式,允许用户测试Linux文件系统上文件和目录的状态。
-d file ##检查file是否存在并是一个目录 directory
-e file ##检查file是否存在
-f file ##检查file是否存在并是一个文件
-r file ##检查file是否存在且可读
-s file ##检查file是否存在且非空
-w file ##检查file是否存在并可写
-x file ##检查file是否存在且可执行
-O file ##检查file是否存在并属于当前用户所有
-G file ##检查file是否存在并且默认组与当前用户相同,注意这个默认组
file1 -nt file2 ##检查file1是否比file2新,通过检查文件日期实现
file1 -ot file2 ##检查file1是否比file2旧
例子如下:
[root@izwz9194nuv8g0cwqfqsh3z 12]# cat test3.sh
#!/bin/bash
##-d 检查目录
if [ -d /root/12 ]
then
echo "the directory /root/12 exists"
else
echo "the directory /root/12 dose not exist"
fi
##-e 检查目录
if [ -e /root/12 ]
then
echo "the directory /root/12 exists"
else
echo "the directory /root/12 dose not exist"
fi
##-e 检查文件
if [ -e /root/12/test4.sh ]
then
echo "the file /root/12/test4.sh exists"
else
echo "the file /root/12/test4.sh dose not exist"
fi##创建文件
touch /root/12/test4.sh
##-e 检查文件
if [ -e /root/12/test4.sh ]
then
echo "the file /root/12/test4.sh exists"
else
echo "the file /root/12/test4.sh dose not exist"
fi
[root@izwz9194nuv8g0cwqfqsh3z 12]# ./test3.sh
the directory /root/12 exists
the directory /root/12 exists
the file /root/12/test4.sh dose not exist
the file /root/12/test4.sh exists
-e参数可以用于文件和目录,但要确定指定对象为文件的话必须用-f参数
if-then语句允许你使用布尔逻辑来组合测试,有两种布尔运算符可用:
[ condition1 ] && [ condition2 ]
[ condition1 ] || [ condition2 ]
跟其他编程语言性质一致,不再赘述。
双括号命令可以在比较过程中使用高级数学表达式。命令格式如下:
(( expression ))
双括号命令中会用到的其他运算符,与C语言中的基本一致:
val++
val--
++val
--val
!
~
** ##幂运算
<< 左位移
>> 右位移
&
|
&&
||
例如:
[root@izwz9194nuv8g0cwqfqsh3z 12]# cat test4.sh
#!/bin/bash
val1=10
#
if (( $val1 ** 2 > 90 ))
then
(( val2 = $val1 ** 2 ))
echo the square of $val1 is $val2.
fi
[root@izwz9194nuv8g0cwqfqsh3z 12]# ./test4.sh
the square of 10 is 100.
双方括号命令提供了针对字符串比较的高级特性,命令格式如下:
[[ expression ]]
双方括号里面的expression使用了test命令中采用的标准字符串比较,但它提供了test命令未提供的特性——模式匹配
在模式匹配中,可以定义正则表达式来匹配字符串值,使用双等号==:
例如:
[root@izwz9194nuv8g0cwqfqsh3z 12]# cat test5.sh
#!/bin/bash
if [[ $USER == r*t ]]
then
echo hello $USER
else
echo "sorry, I don't know you."
fi
[root@izwz9194nuv8g0cwqfqsh3z 12]# ./test5.sh
hello root
与C语言中的case命令类似,shell中的case命令主要适用于一个变量存在多种可能值的情况
格式如下:
case variable in
pattern1) commands1;;
pattern2) commands2;;
pattern3 | pattern4) commands3;;
*) default commands;;
esac
例如:
[root@izwz9194nuv8g0cwqfqsh3z 12]# ./test6.sh
Welcome, root!
[root@izwz9194nuv8g0cwqfqsh3z 12]# cat test6.sh
#!/bin/bash
case $USER in
ZhangSan)
echo Welcome, ZhangSan
echo Nice to meet you.;;
LiSi)
echo Welcome, LiSi
echo Nice to meet you.;;
WangWu | ZhaoLiu)
echo Welcome, WangWu or Zhaoliu
echo Nice to meet you.;;
*)
echo Welcome, root!;;
esac
[root@izwz9194nuv8g0cwqfqsh3z 12]# ./test6.sh
Welcome, root!
for命令的基本格式:
for var in list
do
commands
done
在do和done之间,$var变量包含着这次迭代对应的当前列表中的值。
也可以用如下格式:
for var in list; do
commands
done
那么list如何指定呢?
第一种是直接在in后面列出多个值,空格隔开
for city in Hangzhou Shanghai Fuzhou Xiamen Beijing
do
the next most pupular city is $city
done
for循环假定每个值都是用空格分割,如果原始值中本来就带了空格,必须在这些词上增加双引号圈起来
for city in "Hang zhou" "Shang hai" "Fu zhou" "Xia men" "Bei jing"
do
the next most pupular city is $city
done
通常shell脚本中,我们会将多个值存储在一个变量中,然后遍历这个变量即可:
cities="Hangzhou Shanghai Fuzhou Xiamen Beijing"
cities=$cities " Chongqing"
for city in $cities
do
the next most pupular city is $city
done
生成列表所需值的另外一个途径就是使用命令的输出,可以用命令替换来执行任何能够产生输出的命令
file=cities ##cities是同一个目录下存储了城市名的文件
for city in $(cat $file)
do
the next most pupular city is $city
done
其中,cat $file将会输出:
Hangzhou
Shanghai
Fuzhou
Xiamen
Beijing
可以看到for循环支持变量中按行存储的值,但是如果这些值中间有空格。。。那for还是会识别这个空格并将值一分为二,怎么办?继续往下看。
造成以上问题的原因是特殊的环境变量IFS(internal field separator)内部字段分隔符,一般bash shell中,IFS主要包括以下三种:
空格
制表符
换行符
可以通过set查看变量IFS的值(\t前面是个空格):
IFS=$' \t\n'
补充一下基础知识:
\r:回车符,返回到这一行的开头,return的意思。
\n:换行符,到下一行的同一位置,纵坐标相同,new line的意思。
\t:制表符,为了在不使用表格的情况下,上下对齐,table的意思。
Enter 相当于\n\r,所以Enter的标识为 往下,再往前。当然,\n\r等价于\r\n。
我们可以在shell脚本中临时更改IFS这个环境变量的值来限制被bash shell当做字段分隔符的字符,可以在脚本中加入一句:
IFS=$'\n'
这样就能使用列表中包含空格的值了。需要注意,如果脚本量比较大,只在脚本中某个环节修改IFS的话,需要及时恢复默认值:
IFS.OLD=$IFS
IFS=$'\n'
<在代码中使用新的IFS>
IFS=$IFS.OLD
IFS还有多种用途,如果你想遍历一个文件中用冒号分割的值(如/etc/passwd)要做的就是将IFS的值设为冒号:
IFS=:
如果要指定多个IFS字段,只要将他们在赋值行串起来就行:
IFS=$'\n':;"
可以通过for命令来自动遍历目录中的文件:
[root@izwz9194nuv8g0cwqfqsh3z ~]# cat test12
#!/bin/bashfor file in /root/*
do
if [ -d "$file" ]
then
echo $file is a directory.
elif [ -f "$file" ]
then
echo $file is a file.
fi
done
[root@izwz9194nuv8g0cwqfqsh3z ~]# ./test12
/root/12 is a directory.
/root/123 is a file.
/root/file1 is a file.
/root/final is a directory.
/root/FS is a directory.
在Linux中目录和文件可能包含空格,为了适应这种情况需要将遍历的file遍历用双引号圈起来。
[root@izwz9194nuv8g0cwqfqsh3z ~]# cat test11
#!/bin/bash
for (( i = 1; i <= 10; i++ ))
do
echo the nest number is $i.
done
[root@izwz9194nuv8g0cwqfqsh3z ~]# ./test11
the nest number is 1.
the nest number is 2.
the nest number is 3.
the nest number is 4.
the nest number is 5.
the nest number is 6.
the nest number is 7.
the nest number is 8.
the nest number is 9.
the nest number is 10.
原则就是,加双括号,语法与C语言基本一致,当然,这个表达式的存在违背了shell风格的(1)变量赋值不能有空格;(2)条件的变量要以$开头。C语言风格的代码还可以有多个变量。
while命令的基本格式为:
while test command
do
other commands
done
只要test command成立,即执行other commands
while命令的关键在于test command中的退出状态码必须随着循环不断改变,否则将成为死循环。
test command最常用的方法就是用方括号来检查循环命令中用到的shell变量的值
while [ $var -gt 0]
......
until命令格式如下所示:
until test commands
do
other commands
done
与while命令相反