# 数学运算
在脚本中进行数学运算有很多种方式,你可以从下面选几种喜欢的
exper
命令,支持基本的(逻辑、比较)运算符,对于有歧义的符号 (如*
),需要用\*
,传送门。
# expr 表达式 | |
expr length “this is a test” #计算字串长度 | |
expr 14 % 9 #整数运算 | |
expr 2 \* 10 #注意。参数和符号之间必须要有空格 |
$[表达式]
,更加方便,符号不会出现歧义,但是只能整数运算。
var1=$[1+5] |
bc
计算器,实际上是一种编程语言,-q
可以不显示bash
计算器冗长的欢迎信息。浮点运算是由内建变量scale
控制的,必须将这个值设置为计算结果希望保留的小数位数scale
默认是 0。
cyan@cyan-virtual-machine:~$ bc | |
# 欢迎信息 | |
bc 1.07.1 | |
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006, 2008, 2012-2017 Free Software Foundation, Inc. | |
This is free software with ABSOLUTELY NO WARRANTY. | |
For details type `warranty'. | |
1+3 | |
4 | |
319+42 | |
361 | |
cyan@cyan-virtual-machine:~$ bc -q | |
21/3 | |
7 | |
#内建变量不能在外面修改 | |
cyan@cyan-virtual-machine:~$ echo $scale | |
cyan@cyan-virtual-machine:~$ bc -q | |
scale=3 #进入bc修改内建变量 | |
21/3 | |
7.000 | |
# 还有一种修改内建变量的方法,常用于脚本中,格式为echo "options;expression" | bc | |
cyan@cyan-virtual-machine:~$ echo '21/4' | bc | |
5 | |
cyan@cyan-virtual-machine:~$ echo 'scale=4;21/4' | bc | |
5.2500 |
可见,通过管道, bc
计算器还是挺好用的。再看一个输入重定向的例子
cyan@cyan-virtual-machine:~$ cat math.dat | |
scale=4 | |
var1=1 | |
var2=29 | |
var3=5 | |
var1/var3+var2 | |
cyan@cyan-virtual-machine:~$ result=$(bc < math.dat) | |
cyan@cyan-virtual-machine:~$ echo $result | |
29.2000 |
有一点你可以看到,我们在 bc
中使用变量没有加 $
符号。最后,你也可以试试内联输入重定向,我想,应该没什么问题吧?
# 结构化语句
该部分我就直接给格式了,你记住了就会使用。
# 选择语句
我们如何对 if
中的条件进行判断?
if condition1 #(退出状态码是 0) | |
then | |
commands_1 | |
elif condition2 | |
then | |
commands_2 | |
else | |
commands_3 | |
fi |
condition
可以是一个命令的正确执行,也可以是字符串比较,数值比较,文件比较。
判断 condition
的命令为 test condtion
或者 [ condition ](必须有空格)
。同样的,如果有多个 condition
可以使用 && , ||
。
举个例子
cyan@cyan-virtual-machine:~/Templates$ cat tmp.txt | |
var=100 | |
if [ $var -ge 10 ] && [ $var -le 190 ] | |
then | |
echo '执行if语句块' | |
else | |
echo '执行else语句块' | |
fi | |
cyan@cyan-virtual-machine:~/Templates$ ./tmp.txt | |
执行if语句块 |
再次声明,使用 []
要加空格。
# 比较方式
数值比较: n1 -eq n2
符号选项 | 含义 |
---|---|
-eq | equals(==) |
-gt | greater than(>) |
-ge | greater equals(>=) |
-lt | less than(<) |
-le | less equals(<=) |
-ne | not equals(!=) |
if [ $val -gt 5]
,注意,bash shell 只能使用整数。
字符串比较:
直接使用 =,!=,\>,\<
(大于小于,必须使用转义,否则就会被认为是重定向)。 在比较测试中,大写字母 < 小写字母,如 a>z>A
。而 sort
命令恰好相反, sort
使用的是系统本地化语言设置中定义的排序顺序。对于英语,本地化设置指定在排序顺序中,小写字母出现在大写字母前。
-n
和 -z
可以检查一个变量是否含有数据 (未被定义的变量默认长度为 0)
if[ -n $val ] #如果 val 长度不为 0,就执行 then | |
if[ -z $val ] #如果 val 长度为 0,就执行 then,z--zero |
文件比较:
符号选项 | 含义 |
---|---|
-d file | 检查 file 是否存在并是一个目录 (directory) |
-e file | 检查 file 是否存在 (exits) |
-f file | 检查 file 是否存在并是否是一个文件 |
-r file | 检查 file 是否存在并是否可读 |
-s file | 检查 file 是否存在并是否非空 |
-w file | 检查 file 是否存在并是否可写 |
-x file | 检查 file 是否存在并是否可执行 |
-G file | 检查 file 是否存在并且默认组与当前用户相同 |
-O file | 检查 file 是否存在并是否并属当前用户所有 |
file1 -nt file2 | 检查 file1 是否比 file2 新 |
file1 -ot file2 | 检查 file1 是否比 file2 旧 |
# case 语句
case variable in | |
pattern1 | pattern2) commands1;; | |
pattern3) commands2;; | |
*) defalut commands3;; | |
esac | |
# 例子 | |
case $USER in | |
Bob | Mike) | |
echo "Number one";; | |
Cyan) | |
echo "Cyan";; | |
*) | |
echo "Have not found";; | |
esac |
# 循环语句
# for 循环
for var in list | |
do | |
commands | |
done | |
#例子 | |
for test in Alabama Alaska Arizona Arkansas California | |
do | |
echo The state is $test | |
done |
$test
变量在剩余的shell
脚本一直有效并且保持着最后一个变量的值 (当然是可以修改的)list
中单个元素出现了单引号,空格等,要么在这个单独变量外部直接再使用一对引号,要么直接使用\
转义字符list
的获取,也可以用命令的输出 + 命令替换:for var in $(cat file)
,甚至是/home/cyan/test/*
路径。当然,如果变量是文件名,要考虑文件名可能出现空格,那么在使用时就要使用引号:"$file"
。
# 模拟 ls 指令,打印指定目录下的所有文件(当然这里目录固定为 home/cyan) | |
# 如果想像 ls 路径那样传参数,需要用到之后的知识 | |
cyan@cyan-virtual-machine:~/Templates$ cat tmp.txt | |
#/bin/bash | |
for file_name in /home/cyan/* | |
do | |
echo $file_name | |
done | |
cyan@cyan-virtual-machine:~/Templates$ ./tmp.txt | |
/home/cyan/Desktop | |
/home/cyan/Documents | |
/home/cyan/Downloads | |
/home/cyan/Files | |
/home/cyan/Music | |
/home/cyan/OSIntroduction | |
/home/cyan/Pictures | |
/home/cyan/Public | |
/home/cyan/shtool-2.0.8 | |
/home/cyan/shtool-2.0.8.tar.gz | |
/home/cyan/snap | |
/home/cyan/Templates | |
/home/cyan/Videos | |
/home/cyan/vmware-tools-distrib |
- 在
list
中,各个元素之间的分隔符是由IFS
-- 内部字段分隔符决定的,一般会将空格,制表符,换行符作为默认字段分隔符如果想要更改分隔符,就必须在shell
脚本for
循环前面更改IFS
。
cyan@cyan-virtual-machine:~/Templates$ cat data | |
jack bob cyan mike | |
mary smith | |
cyan@cyan-virtual-machine:~/Templates$ cat tmp.txt | |
#/bin/bash | |
for name in `cat data` | |
do | |
echo $name | |
done | |
#得到的结果 | |
cyan@cyan-virtual-machine:~/Templates$ ./tmp.txt | |
jack | |
bob | |
cyan | |
mike | |
mary | |
smith |
这是因为 IFS
默认的是空格,制表符,换行符。在遇到第一个空格时,就已经分隔了。如果想要只以换行符为分隔符
cyan@cyan-virtual-machine:~/Templates$ cat tmp.txt | |
#/bin/bash | |
oldIFS=$IFS | |
IFS=$'\n' | |
for file_name in `cat data` | |
do | |
echo $file_name | |
done | |
IFS=$oldIFS | |
cyan@cyan-virtual-machine:~/Templates$ ./tmp.txt | |
jack bob cyan mike | |
mary smith |
C 语言风格的 for 循环
for (( i=1;i <= 20;i++ )) # i=$(expr $i+1) i=$[$i + 1] i=$(echo "scale=0;$i + 1" | bc) | |
do | |
commands | |
done |
# while 循环
while test conitions | |
do | |
commands | |
done | |
# test 的替代物 [] 需要两边空格,而 expr 的替代物 $[] 不需要两边空格 | |
# while 命令允许执行多个测试命令,但是只有最后一个测试命令的退出状态码会被用于决定什么时候结束循环 | |
# 比如:while [$var1 -ge 0] | |
# echo $var1 | |
# 就是一个死循环 | |
#注意,每个测试命令单独一行 |
# until 命令
until test commands | |
do | |
commands | |
done | |
# until 语句,只有测试条件的退出码非 0,才会执行循环中列出的命令。 |