一、认识shell
操作系统最外层的程序,shell通过提示符让用户输入,向操作系统解释该输入,然后处理来自操作系统的任何结果输出来,管理用户与操作系统之间的交互。
二、shell脚本编程
这里我们直接上手编程,再根据遇到的问题逐个讲解。
shell脚本编写流程:
1)创建shell脚本文件
2)编写shell脚本
3)给脚本文件添加执行权限
4)执行shell脚本文件
2.1 创建shell脚本文件
这里我们可以用gedit、kedit、vim、vi等等编辑软件创建shell脚本文件,注意文件后缀名为“ .sh ”。
2.2 编写shell脚本
以下面程序为例:
#!/bin/bash
#程序作用,定义变量,给变量赋值,键盘输入变量的值,并且在屏幕中打印变量的值
VAR1=0 #定义变量VAR1 并赋初值0
VAR2=0 #定义变量VAR2 并赋初值0
echo "请输入VAR1的值:" #在屏幕上打印 请输入VAR1的值:
read VAR1 #从键盘获取VAR1的值
echo "VAR1 = ${VAR1}"
VAR2=${VAR1} #取VAR1的值,并且赋给VAR2
echo "VAR2 = ${VAR2}"
我们以C语言程序来进行对比讲解,shell脚本的特点。
首先第一行的 #!/bin/bash 就相当于C语言中的添加头文件#include <stdio.h>,常见的shell类型有/bin/sh,/bin/csh,/bin/ksh以及我们这里选择的:/bin/bash,其中bash是大多数linux默认的shell程序。
这里我们也看到了注释文字之前都是以#开头的,没错,在shell脚本中,我们是以#为注释标号。
在紧接着我们定义了VAR1和VAR2两个变量,并且赋了初值0,这里我们需要注意,变量赋值的时候,“ = ”两边不能有空格。
变量赋值的格式为: 变量名=值 (等号两端不能有空格)
echo是一个打印指令,将数据打印到指定的输出流当中,默认是屏幕。
read则是键盘输入数据传送给变量,想当于C语言中的scanf()函数。
VAR2=${VAR1},这行代码执行了两件事,先取了VAR1的值,然后再将VAR1的值赋给了VAR2,这里我们需要注意关于变量的取值,虽然在变量名前加一个" $ "就可以取得变量的值,但是这样的取值方法很容易出现错误,例如:
SCORE=80
echo "your score is $SCOREcredits"
这里的打印结果将是:your score is 而不是我们预料的:your score is 80credits 因为shell并不会自己去搜索变量,所以shell自动的将SCOREcredits当成了一个变量并且去取了他的值取显示。所以我们要对取值命令写得更谨慎一些:
SCORE=80
echo "your score is ${SCORE}credits"
2.3 给shell脚本文件添加执行权限
在上面我们已经编写并保存了一个极简单的shell脚本文件,但是此时的shell脚本文件是没有执行权限的,我们需要手动给shell脚本文件添加执行权限指令如下:
chmod +x 文件名.sh
2.4 执行shell脚本文件
执行完上面3个步骤以后,我们就可以在Ubuntu终端上直接只执行shell脚本文件了,执行结果如下:
三、shell脚本的基本语法
3.1 变量
在shell编程中,shell的变量都是字符串组成,无具体类型,其中/bin/bash中有以下具体四种变量。
1)用户自定义变量
2)位置变量
3)预定义变量
4)环境变量
3.1.1 用户自定义变量
用户自定义的变量由字母或下划线开头,由字母,数字或下划线序列组成,并且大小写字母意义不同,变量名长度没有限制。习惯上用大写字母来命名变量。变量名以字母表示的字符开头,不能用数字。
3.1.2 位置变量
位置变量指的是命令行参数,例如C语言中的main()函数传参,传入的参数即为位置变量(./a.out 参数1 参数2....),这里我们在shell脚本中调用位置变量的时候,只需使用" $n "即可,其中n代表的是第几个参数,$1 是传入的参数1,$2是传入的参数2,以此类推使用。
3.1.3 预定义变量
$0 与键入的命令行一样,包含脚本文件名
$1,$2,……$9 分别包含第一个到第九个命令行参数
$# 包含命令行参数的个数
$@ 包含所有命令行参数:“$1,$2,……$9”
$? 包含前一个命令的退出状态
$* 包含所有命令行参数:“$1,$2,……$9”
$$ 包含正在执行进程的ID号
3.1.4 环境变量
环境变量即是linux系统中的环境变量,该处变量在$HOME/.profile文件中有定义。
3.2 功能性语句
3.2.1 算术运算
在shell脚本编程中能使用的算术运算符(+),(-),(\*),(/),(%),(=),(**)等等,并且我们在使用算术运算的时候要先写算术命令expr并且整个语句要使用命令置换,就是键盘左上角的数字1旁边的那个按键,反引号。
+:VAR=`expr 10 + 2` #加 结果为12
-:VAR=`expr 10 - 2` #减 结果为8
\*:VAR=`expr 10 \* 2` #乘 结果为20
/:VAR=`expr 10 / 2` #除 结果为5
%:VAR=`expr 10 % 2` #取余 结果为0
**:VAR=`expr 10 ** 2` #乘方 结果为100
3.2.2 关系运算
这里有一个细节需要我们注意一下,在shell脚本编程中,关系运算结果0为真,结果1为假
#字符串相关
s1 = s2 测试两个字符串的内容是否完全一样
s1 != s2 测试两个字符串的内容是否有差异
-z s1 测试s1 字符串的长度是否为0
-n s1 测试s1 字符串的长度是否不为0
#整数相关
a -eq b 测试a 与b 是否相等
a -ne b 测试a 与b 是否不相等
a -gt b 测试a 是否大于b
a -ge b 测试a 是否大于等于b
a -lt b 测试a 是否小于b
a -le b 测试a 是否小于等于b
#文件相关
-d name 测试name 是否为一个目录
-f name 测试name 是否为普通文件
-L name 测试name 是否为符号链接
-r name 测试name 文件是否存在且为可读
-w name 测试name 文件是否存在且为可写
-x name 测试name 文件是否存在且为可执行
-s name 测试name 文件是否存在且其长度不为0
f1 -nt f2 测试文件f1 是否比文件f2 更新
f1 -ot f2 测试文件f1 是否比文件f2 更旧
在进行关系运算的时候,我们需要调用test命令,调用格式为:test 表达式1 运算符 表达式2
#调用格式: test 表达式1 运算符 表达式2
VAR1=10
VAR2=20
test ${VAR1} -gt ${VAR2} #判断VAR1是否大于VAR2 结果为1
# test命令可以使用 [] 进行替代,上式可以写为
[ ${VAR1} -gt ${VAR2} ]
3.3 结构性语句
3.3.1 选择结构
1.
if 表达式
then
... ... #条件满足执行的任务
fi
例:
if [ ${VAR1} -gt ${VAR2} ]
then
echo "VAR1 > VAR2"
fi
2.
if 表达式
then
... ... #条件满足执行的任务
else
... ... #条件满足执行的任务
fi
例:
if [ ${VAR1} -gt ${VAR2} ]
then
echo "VAR1 > VAR2"
else
echo "VAR1 < VAR2"
fi
3.
if 表达式1
then
... ... #条件满足执行的任务
elif 表达式2
then
... ... #条件满足执行的任务
else
... ... #条件满足执行的任务
fi
例:
if [ ${VAR1} -gt ${VAR2} ]
then
echo "VAR1 > VAR2"
elif [ ${VAR1} -eq ${VAR2} ]
then
echo "VAR1 = VAR2"
else
echo "VAR1 < VAR2"
fi
4.
case 字符串变量 in
模式1)
... ... #条件满足执行的任务
;;
模式2)
... ... #条件满足执行的任务
;;
.
.
.
模式n)
... ... #条件满足执行的任务
;;
esac
3.3.1 循环结构
#循环结构
1.
for var in item1 item2 ... itemN
do
... ... #条件满足执行任务
done
例.
for i in 1 2 3 4 5 6 7 8
do
echo ${i}
done
2.
for (( i = 1; i < 101; i++ ))
do
... ... #条件满足执行任务
done
例.。
for ((i = 1; i < 101; i++))
do
echo ${i}
done
3.
for var //这里的var的值是位置变量
do
... ... #条件满足执行任务
done
4.
while 判断命令或表达式
do
... ... #条件满足执行任务
done
例:
while [ $i -lt 100 ]
do
echo ${i}
done
5. 死循环
while true
do
... ... #条件满足执行任务
done
for ((; ;))
do
... ... #条件满足执行任务
done
6. break 和 continue
continue #跳过该次循序
break #跳出该循环体
continue n #跳出最近n层循环语句
break n #跳出最近n层循环体
3.4 shell函数
在shell编程中,函数在调用前必须先定义,即在顺序上函数说明必须放在调用程序的前面。调用程序可以传递参数给函数,函数可用return语句把运行结果返回给调用函数,函数只能在当前shell中起作用,不能输出到子shell中。
函数定义格式如下:
#方式一:
function func_name()
{
commond1
... ...
commond2
}
#方式二:
func_name()
{
commond1
... ...
commond2
}
函数调用的时候直接写函数名即可,函数中写的return返回值只能通过 " $? " 获取,若是调用函数将函数赋值给变量如:
(var = `func_name`),var得到的结果将是func_name函数中echo命令打印的内容。
func_name()
{
echo "RESULT = $1 + $2"
return `expr $1 + $2`
}
VAR1=10
VAR2=20
func_name ${VAR1} ${VAR2} #${VAR1} ${VAR2} 就是函数参数$1 和 $2
RESULT=`func_name ${VAR1} ${VAR2}`
echo $?
echo $RESULT
程序运行结果如下:程序return的返回值是通过 " $? " 得到,而赋给变量的值确实函数中echo输出的结果,在这里变量RESULT起到的是一个缓冲区的作用。
3.5 在shell脚本中调用其他shell脚本
这个只需要将被调用的shell脚本放到一个路径下,并且在程序中需要调用的地方书写source filename.sh 即可。
仓促成文,不当之处,尚祈方家和读者批评指正。联系邮箱1772348223@qq.com