作者:二青
个人站点:zhangerqing.cn 邮箱:[email protected] 微博:http://weibo.com/xtfggef
Shell脚本就是将很多条命令结合起来写在一起,通过运算以及判断来实现很多功能的文本。为什么学习shell,首先一些常规的系统管理操作,并且需要自动化地执行,如果用shell脚本把这些操作集中在一起,只需要定期的执行这个shell脚本就可以了,其次,对于一些复杂的文本处理,比如日志分析等等,可能需求比较多,单条执行命令不是很方便,因此也需要使用shell实现,所以,如果想学通linux系统,shell是必备的一课。本章我们主要以bash shell为主,不涉及其它shell。
HelloWorld
第一个shell脚本,输出Hello World。
第一行必须是#!/bin/bash(声明我们用的是bash shell,否则系统不知道需要调用那个shell去执行脚本)。由#开始的表示注释,后面的字符在执行的时候全部被忽略。主体就是第4行的echo -e “Hello World \a \n”,-e表示启用反斜线转义, \a表示输出“咚”的声音,\n表示换行。写完脚本后,为脚本添加可执行权限:chmod +x sh01.sh,然后用./sh01.sh执行就好了。
交互式脚本
最简单的情况就是获取用户输入,然后输出。
这个例子也比较简单,实用read进行输入的获取,并将值赋于紧跟着的变量上,执行效果:
数值计算
bash shell仅支持整数的简单加减乘除,需要用到$((express)),两层小括号内的express则为计算的表达式。
第七行采用declare的方式声明一个变量sum,使用$(( ))的方式计算结果。
判断式
1. test命令
检查文件是否存在:test -e filename && echo "Exist" || "Not exist",如果存在,会输出Exist,否则Not exist. test命令有很多参数.
命令 | 参数 | 解释 | 备注 |
关于文件类型的判断, test -e filename | |||
test | -e | 文件名是否存在 | 常用 |
-f | 文件名是否存在且为文件 | 常用 | |
-d | 目录名是否存在且为目录 | 常用 | |
-b | 文件名是否存在且为一个block device设备 | ||
-c | 文件名是否存在且为一个character device设备 | ||
-S | 文件名是否存在且为一个Socket设备 | ||
-p | 文件名是否存在且为一个FIFO文件 | ||
-L | 文件名是否存在且为一个连接文件 | ||
关于文件的权限检测,如test -r filename | |||
-r | 文件名是否存在且具有可读权限 | ||
-w | 文件名是否存在且具有可写权限 | ||
-x | 文件名是否存在且具有可执行权限 | ||
-u | 文件名是否存在且具有SUID属性 | ||
-g | 文件名是否存在且具有SGID属性 | ||
-k | 文件名是否存在且具有Sticky bit属性 | ||
-s | 文件名是否存在且为非空白文件 | ||
关于两个文件之间的比较,test file1 -nt file2 | |||
-nt | newer than,判断file1是否比file2新 | 常用 | |
-ot | older than,判断file1是否比file2旧 | ||
-ef | 判断file1与file2是否为同一文件 | ||
关于两个整数之间的比较,test n1 -eq n2 | |||
-eq | 两数值相等 | ||
-ne | 两数值不等 | ||
-gt | greater than,n1 大于n2 | ||
-lt | less than,n1小于n2 | ||
-ge | greater than or equal,n1 大于等于n2 | ||
-le | less than or equal,n1小于等于n2 | ||
判断字符串 | |||
test -z string | 判断字符串是否为0 | ||
test -n string | 判断字符串是否不为0 | ||
test str1 = str2 | 判断字符串是否相等 | ||
test str1 != str2 | 判断字符串是否不等 | ||
多重条件判定,test -r filename -a -x filename | |||
-a | 两个条件同时成立时返回true | ||
-O | 任何一个条件成立时返回true | ||
! | 反向状态,当条件不成立时返回true |
2. []判断符
除了使用test外,我们还可以使用[](中括号)来进行一些判断,如判断HOME环境变量是否为空:
[ -z $HOME ] ; echo $?
注意命令中的空格,[之后]之前都要跟一个空格,如果用到==,则==两侧也都需要有一个空格(要么都有,要么都没有)。比如,[ "aaa" == "bbb" ],这是合理的方式,如果写成[ "aaa" =="bbb" ]或者[ "aaa"== "bbb" ]就不合理了,会报错。使用[]进行判断时,应该注意如下几点:
a. 在括号[]内的组件都需要空格来分隔。
b. 括号内的变量最好要用双引号括起来。
c. 括号内的常量最好也要用单引号或者双引号括起来。
3. shell script的默认变量$0, $1, $2...
当我们给一个脚本带参数运行时,我们可以在脚本里获取到该命令的一些信息,比如:sh01.sh aaa bbb,在脚本里,$0就可以拿到脚本名,$1,$2分别为第一、第二个参数,以此类推,我们可以总结一下:
$0, 脚本名
$1, $2,脚本的参数
$#, 参数个数
[email protected], 所有参数,每个参数用双引号括起来
$*, 所有参数,用空格隔开
做个例子:
运行结果:
条件判断式
这个好理解,就是我们常见的if else语句,在shell脚本里用if then表示if语句,if then else表示if else语句,if出现时要用fi来结尾,else if用elif代替。看个例子:
1. 判断输入的第一个参数是不是hello
2. 如果无任何参数,则提示用户输入一个参数
3. 如果输入的参数不是hello,则提示用户只能输入hello作为参数
查看效果:
case判断
我们用过程序语言里的switch case语句,在某些情况下比if else方便很多,在shell脚本里也有类似的语句块叫:case in esac,还是上面的例子,我们换种写法:
看看效果:
循环
1. while do ... done
这个就是我们常见的while循环,当满足条件时,已知执行循环体里的语句,直到条件不满足时推出循环,done为循环结束标志。
2. until do ... done
该语句和while do ... done正好相反,当条件不满足时进行循环,满足时结束循环。
3. for do ... done
常见的for循环,一般就是对一个已知的数组或者结构进行循环遍历。
for do ... done还有一种用法就是对数值的处理,可以使用我们传统for循环的方式: for (( ;;))
shell 脚本的追踪与调试
在执行一个shell脚本之前,我们可以先进行一系列的语法检查,这样可以初步检测出一些明显的问题。
sh [-nvx] script.sh
-n, 不执行script,仅检查语法问题
-v, 在执行script前,先输出脚本到屏幕上
-x, 将使用到的script显示到屏幕上,列出所有的执行过程
这一章基本就要结束了,主要是一些基本的编写shell script的语法,我们可以先把这些掌握熟了,多加练习,然后多看一些复杂的文本处理的例子,多学习,多模仿复杂脚本的写法,然后写出复杂的脚本就不再是什么难事。