shell script编程
[TOC]
shell script (纯文本文件) 在系统管理上是一个好工具, 但是用在处理大量数值运算上就不好了, 因其速度较慢, 且使用CPU资源较多, 容易造成主机资源分配不良.
shell script的执行至少需要 r 权限, 若需要命令执行, 至少需要 rx权限.
&& 代表and, || 代表or.
var=$( 命令 ) 引用命令结果
var=$((整数的运算))
var=${命令或参数或值}, 变量引用
与一般编程语言不同, 等号左右两边不可分.
0. 判断式
特别要注意一种简单的判断式写法: [ -e $var ] && echo "$var is existing."
0.1 文件类型
test -e filename 或 [ -e "filename" ]
测试标志 | 代表意义 |
---|---|
-e | 文件名是否存在 |
-f | 文件名是否存在且为文件 (file) |
-d | 文件名是否存在且为目录 (directory) |
-b | 文件名是否存在且为 bolck device 设备 |
-c | 文件名是否存在且为 character device 设备 |
-S | 文件名是否存在且为 Socket device 设备 |
-p | 文件名是否存在且为 FIFO (pipe) 文件 |
-L | 文件名是否存在且为一个连接文件 |
0.2 文件权限
test -r filename 或 [ -r "filename" ]
测试标志 | 代表意义 |
---|---|
-r | 检测该文件名是否存在且具有"可读"的权限 |
-w | 检测该文件名是否存在且具有"可写"的权限 |
-x | 检测该文件名是否存在且具有"可执行"的权限 |
-u | 检测该文件名是否存在且具有"SUID"的权限 |
-g | 检测该文件名是否存在且具有"SGID"的权限 |
-k | 检测该文件名是否存在且具有"SBIT"的权限 |
-s | 检测该文件名是否存在且为"非空白文件" |
0.3 文件比较
test file1 -nt file2 或 [ "file1" -nt "file2" ]
测试标志 | 代表意义 |
---|---|
-nt | (newer than) 判断file1是否比file2新 |
-ot | (older than) 判断file1是否比file2旧 |
-et | 判断file1于file2是否为同一文件, 可用在hard link的判定上. <br />主要意义在于判定两个文件是否均指向同一个inode |
0.4 整数判定
test n1 -eq n2 或 [ "n1" -eq "n2" ]
测试标志 | 代表意义 |
---|---|
-eq | equal |
-ne | not equal |
-gt | greater than |
-lt | less than |
-ge | greater than or equal |
-le | less than or equal |
0.5 字符串
test -z str1 或 [ -z "str1" ]
test str1 == str2 或 [ "str1" != "str2" ]
测试标志 | 代表意义 |
---|---|
-z | 判断str1是否为0, 若为空字符串, 则为true |
-n | 判断str1是否为非0, 若为空字符串, 则为false<br />注: -n可省略 |
== | 判断str1和str2是否相等, 若相等, 则回传true |
!= | 判断str1和str2是否不相等, 若相等, 则回传false |
0.6 多重条件
test -r filename -o -w filename 或 [ -r "filename" -o -w "filename" ] 或 [ -r "filename" ] -o [ -w "filename" ]
测试标志 | 代表意义 |
---|---|
-a | 且 |
-o | 或 |
! | 非 |
1. 条件判断
1.1 if...then...
if [ condition ]; then
程序段
elif [ condition ]; then
程序段
else
程序段
if
1.2 case...esac
只针对某几种特殊情况进行设置.
系统很多服务的启动script都是用这种写法的.
case ${变量名称} in
"第一个变量内容") #每个变量内容双引号括起来, 关键字则为小括号
程序段
;; #每个类型结尾使用两个连续的分号来处理
"第二个变量内容")
程序段
;;
*) #最后一个变量内容都会用*来代表其他所有值
程序段
exit 1 #此处千万不要忘记!
;;
esac
case支持glob风格的通配符:
- * : 任意长度任意字符
- ? : 任意单个字符
- [ ] : 指定范围内的任意单个字符
- a|b : a或b
2. 函数
实现功能, 减少重复.
注意shell script的执行方式从上到下, 从左到右, 因此shell script中function的设置一定要写在最前面.
function也是有内置变量的.
# 语法一:
function fname() {
...函数体... #函数的内置变量在函数定义的代码块中有$, 在程序块中引用函数时, 无$
}
# 语法二:
f_name () {
...函数体...
}
调用: 函数只有被调用才会执行
调用: 给定函数名 (函数名出现的地方, 会被自动替换为函数代码)
函数的生命周期: 被调用时创建, 返回时终止
return命令返回自定义的状态结果:
0: 成功
1 - 255: 失败
函数可以接受参数:
传递参数给函数: 调用函数时, 在函数名后面以空白分隔参数列表即可, 例如: testfunc arg1 arg2
在函数体中, 可使用$1, $2, ...调用这些参数, 还可使用$@, $*, $#等特殊变量
变量作用域:
本地变量: 当前shell进程(当前shell脚本程序文件)
局部变量: 函数的生命周期, 函数结束时被自动销毁
如果函数中有变量与本地变量名称相同, 若不用local声明该变量为局部变量, 则在函数操作时会修改本地变量的值
在函数中定义局部变量的方法:
local NAME=VALUE
函数递归:
函数直接或间接调用自身:
n!=n(n-1)(n-2)...1
斐波那契数组: 1 1 2 3 5 8 13 ...
foo () {
if [ $1 = 0 -o $1 = 1 ]; then
echo 1
else
echo $[$1*$(foo $[$1-1])]
fi
}
foo 6
febo () {
if [ $1 = 1 -o $1 = 2 ]; then
echo 1
else
echo $[$(febo $[$1-1])+$(febo [$1-2])]
fi
}
febo 10
3. 循环
3.1 不定循环
3.1.1 while do done
当条件成立, 执行循环, 否则停止.
while [ condition ]
do # do是循环的开始
程序段
done # done是循环的结束
3.1.2 until do done
直到条件成立, 终止循环, 否则循环执行程序段.
until [ condition ]
do # do是循环的开始
程序段
done # done是循环的结束
3.2 固定循环
3.2.1 for do done
for var in con1 con2 con3 ... # 注: 用空格隔开, 中间不需要加逗号!!!
do
程序段
done
3.2.2 for do done的数值处理
for (( 初始值; 限制值; 执行步长 ))
do
程序段
done
# 实例
# 计算1加到100的值
sum=0
for ((i=1; i<=100; i=i+1))
do
sum=$(( sum+i )) # shell脚本中计算时要用$(( ))
done
4. shell script的追踪与调试
# 用法
sh [-nvx] script.sh
# -n 不执行脚本, 仅查询语法问题
# -v 在执行脚本前, 先将script的内容输出到屏幕上
# -x 将命令的执行过程显示在屏幕上, 如此用户便可以判断程序代码执行到哪一段出了问题, 很有用!