Shell 编程入门

Shell 简介

管理整个计算机硬件的其实就是操作系统的核心(kernel),用户一般是通过 Shell 来和 kernel 沟通,来达到我们想要的工作。

Shell 脚本就是包含一组可运行的特定 Shell 命令(在这里指 bash shell)的文本文件,命令的执行与其出现在脚本中的顺序一致。

Shell 提供了一种方式让人可以方便的调用操作系统命令库的接口,便于简化那些人们不愿意操作的重复而繁杂的工作,比如 web 应用程序的部署,特别是一套多服务系统,尤其是对于新手来说更是灾难。对于一些小公司来说,没能那么幸运拥有一位高级运维人员,这就对开发提出了更高的要求,需要熟练使用 shell 脚本实现自动化部署系统。拿我们公司举例来说,之前没有自动化部署,装完数据库后,部署应用得花半天时间,用上自动部署后可以在半小时内部署好,只需输入一些自定义信息就可以,比如端口。

除了这些还可以用来做比如:定时删除日志文件、Web 爬取、磁盘用量跟踪、天气数据下载、文件更名,等等。

常见的 shell 指令我们肯定经常会使用,比如:cd、ll、ls -la、vim。bash 的功能里面最棒的一个就是它能记住使用过的指令,你只要摁上下键,就可以找到前/后一个指令,非常方便,默认可以记住多达 1000 个的指令!

我们可以使用 alias 来帮助我们减少输入,比如下达命令设定别名:$ alias lm = ‘ls -la’,这样就可以使用 lm 代替 ls -la。

Shell 变量

自定义变量和环境变量
在 Shell 变量中包括自定义变量和环境变量:

自定义变量:脚本中自己命名定义的变量,通常为局部变量,其他 Shell 程序不能访问到;

环境变量,操作系统已定义的变量,如 PATH,所有 Shell 程序都能访问到,也可以通过 env 查看所有环境变量。 可以通过 echo $ORACLE_HOME 来查看所有环境变量。

常见的环境变量有:

变量名 作用
PATH 决定了 Shell 将从哪些目录下查找程序或命令
LANG 操作系统字符集
HOME 当前用户主目录,如 oracle 的主目录为:/home/oracle
HISTSIZE 历史记录数,可以记住的 shell 指令数
HOSTNAME 指主机的名称
SHELL 当前用户 Shell 类型,如:/bin/bash

命名

变量名由字母、数字、下划线组成,如:url_1。
只能以字母或者下划线开头,如:route_path、_pig。
不能使用 Shell 的保留字。
不能使用空格、不能使用标点符号。
赋值、调用、删除

  1. 新建 hello.sh 脚本,扩展名不影响执行:

  1. 给 hello.sh 脚本赋予执行权限:chmod +x hello.sh

  2. 调用脚本 ./hello.sh,hello.sh 的前面需要加上 ./,这是因为不加上的话会去 PATH 下查找是否有对应的命令可以执行,而 PATH 下只有 /bin、/sbin、/usr/bin、/usr/sbin,通常当前目录不在 PATH 下,就会提示 comman not found,所以要用 ./ 告诉系统在当前目录下查找。

. 使用 unset 命令可以删除变量:

unset variable_name
例如:

输出结果:

Shell 字符串

单引号、双引号
Shell 中最常用的数据类型就是字符串和数字,除此之外也没有数据类型了,在 Shell 中字符串可以用单引号或者双引号来包围,如:‘/opt/IBM’、"/opt/IBM"、/opt/IBM。也可以没有引号包围。

两者的区别在于:

  • 单引号包围的字符串会以原样输出,如:echo ‘hello ${name}’,会输出:hello ${name},且单引号包围的字符串中不能出现单引号,进行转义也不行。

  • 双引号包围的字符串会将变量进行替换,如:echo "hello ${name}",会输出:hello jack,且双引号包围的字符串中可以出现双引号,进行转义就行。
    不被引号包围的字符串,会对变量进行解析,这点跟双引号一样,但是字符串中不能出现空格,否则空格后面的字符串会被当作命令或者其他变量解析。
    综上,当有变量时最好是使用双引号包围字符串,且变量最好有 {} 包围,明确变量名,这也是最佳编程实践。

获取字符串长度

获取字符串长度的方式有两种:

举个例子:

输出:

截取字符串

使用 # 截取右边字符,方式为 ${hello#*chars},例如:

输出:

表明截取了从左到右第一个 o 右边的字符串,*chars 代表忽略 chars 左边任意长度的字符串(包括 chars)。如果不写星号,那么就不会忽略 chars 左边的字符串。

如果像直到最后一个 chars 再截取右边的字符串,那么可以用 ## 来截取,例如:

输出:

使用 % 截取左边字符串,方式为:${hello%chars}。与 # 不同的是,这里在右边,代表忽略 chars 右边的任意长度字符串,来截取 chars 左边的字符串,其用法跟 # 类似。

看个例子:

输出:

可以看到“%”截取时是从右边开始的,从右往左,也可使用“%%”直到最后一个 chars 再截取左边的字符串。

Shell 数组
Shell 数组只能是一维的,不支持多维数组,并且 Shell 是弱类型的,数组中的类型不一定只有一种,且不限制数组的长度大小,理论上可以是无限大小。

输出:

Shell 基本运算符

算数运算符

包括:+、-、*、/、%、=、==、!=

这些跟我们其他编程语言遇到的是一样的,就不详细说明,举个简单例子。

输出:

关系运算符

包括:-eq、-nq、-gt、-lt、-ge、-le

运算符 说明
-eq 判断两个数据是否相等
-nq 判断两个数据是否不相等
-gt 判断左边的数据是否大于右边的数据
-lt 判断左边的数据是否小于右边的数据
-ge 判断左边的数据是否大于等于右边的数据
-le 判断左边的数据是否小于等于右边的数据

接下来看下程序怎么写:

输出:

其他关系运算符相信大家都应该知道怎么使用了。

逻辑运算符

包括:&&、||

运算符 说明
&& 逻辑与,左右两边的表达式都为 true 才 true,有一个为 false 则为 false
\ \
接下来看下程序

输出:

布尔运算符

包括:!、-o、-a

运算符 说明
! 非运算,对表达式取反,如:[ !false ] 返回 false
-o 或运算,左右两边的表达式存在 true 则为 true,都为 false 则为 false
-a 与运算,左右两边的表达式存在 false 则为 false,都为 true 则为 true
接下来看下程序

输出:

a 与 b 不相等
A
-a 与 -o 用法相同。

字符串运算符

包括:=、!=、-z、-n、str

运算符 说明
= 检测两个字符串是否相等,相等返回 true
!= 检测两个字符串是否不相等,不相等则返回 true
-z 检测字符串长度是否为 0,为 0 则返回 true
-n 检测字符串长度是否为 0,不为 0 则返回 true
str 检测字符串是否为空,不为空则返回 true
接下来一起看下程序:

输出:

Shell 流程控制

if 条件语句

前面我们也看到了 if 条件语句的使用,基本语法就是:

这就是 if-elif-else,最后别忘了 fi 作为结尾。跟 Java 不同的是,Shell 的 if 不能有空语句,即什么都不做的条件表达式。还有一点是 condition 一般用中括号[],Java 都是用小括号 ()。

for 循环语句

for 循环语句的基本语法是:

其中,for loop in 1 2 3 4 5 可被替换成 for loop in {1..5}。以及 类似于 java 中的 for 条件语句写法:for((i=0;i<=5;i++))。

举个例子:

输出:

while 循环语句

有了上面的 if 和 for 之后,相信可以实现很多的逻辑控制了,接下来再看看 while 循环语句怎么写。

基本语法是:

看个例子:

输出:

while 语句还可以用来接收用户输入,用法是:

while read choose
无限循环是经常会用到的一个语法,下面列举了无限循环的三种实现方式:

Shell 函数

了解完了上面的流程控制语句,下面我们来看看 Shell 是怎么定义函数,以及调用函数的,我们先来看个简单的例子。

这个是不带参数没有返回值的例子,接下来我们来看看不带参数没有返回值的例子:

输出:

a+b=4
从上面我们可以看出,在调用函数 plusnum 后,通过$?可以拿到返回结果。而调用方式是直接用函数名即可,不需要加上括号,这点跟 Java 和其他面向对象的编程语言都有所不同。

下面再看一个有参数的函数:

从上面我们可以看到函数 plusnum 中通过 $1 和 $2 获取传入的参数,在相加后返回结果,调用时直接跟在函数后面,并不像 Java 的函数传参。

理解一个 Shell 脚本
其实前面举得例子都比较简单,可以认为前面的语法是 Shell 程序的一个骨架,而众多的 Shell 命令以及业务内容将是填充进去的血肉,下面我们利用前面学过的知识来理解下下面的这个 Shell 程序。

file

首先他先定义了一个 DIR_HOME 数组
然后定义变量 FLAG、OFFICE_HOME,值为空
$(cd "$(dirname "$0")";pwd) 意为取当前目录
输出环境变量 KKFILEVIEW_BIN_FOLDER
进入目录
输出目录
查询 application.properties 中不以 # 开头的 office.home 的数量
如果上面的值为 0,那么就认为用了自定义的 office.home
否则循环最开始定义的 DIR_HOME 数组,看看其中是否有 soffice.bin 文件,若有则修改 FLAG 的值为 true,OFFICE_HOME 赋值为当前 DIR_HOME 数组的值,并且跳出循环
接下来判断 FLAG 是否为空,如果为空说明系统中从未安装过 OpenOffice,则调用 install.sh 进行安装,否则将认为已安装 OpenOffice,并输出安装路径
下面开始正式启动应用程序

总结

通过 Shell 脚本可以大大简化我们的工作,使我们从日复一日的重复劳动中解放出来,有时间去尝试更有趣的事物。学了技术之后就赶紧动手尝试起来吧,有些东西看看都会,一写起来就不会了,所以玩过之后印象才会更加深刻。

Views: 22