shell编程
概述
shell是什么
Shell是一个命令行解释器,它为用户提供了一个向Linux内核发送请求以便运行程序的界面系统级程序,用户可以用Shell来启动、挂起、停止甚至是编写一些程序。
Shell 是一个用C语言编写的程序,它是用户使用Linux的桥梁。Shell既是一种命令语言,又是一种程序设计语言。
每个人在成功登陆Linux后,系统会出现不同的提示符号,比如#,$等,之后用户就可以输入需要的命令,让linux系统执行一直到注销系统为止,在从登录到注销期间,输入的每个命令都会经过解释及执行,负责该用户和Linux系统对话的机制就是shell
Shell 脚本(shell script),是一种为shell编写的脚本程序。其实作为命令语言互动式的解释和执行用户的输入命令只是shell功能的一个方面。shell还能用来进行程序设计,它提供了定义变量和参数的手段以及丰富的程序控制结构。类似于Dos系统中的批处理文件,称为shell script。
为什么要学习shell
- Linux运维工程师在进行服务器集群管理时,需要编写Shell程序来进行服务器管理。
- 对于JavaEE和Python程序员来说,工作可能需要编写一些Shell脚本进行程序或者是服务器的维护,比如编写一个定时备份数据库的脚本。
- 对于大数据程序员来说,需要编写Shell程序来管理集群。
查看shell
当前使用shell
env | grep sh
当前有哪些shell
ls -l /bin/*sh*
Linux的Shell种类众多,常见的有:
- Bourne Shell(/usr/bin/sh或/bin/sh)
- Bourne Again Shell(/bin/bash)
- C Shell(/usr/bin/csh)
- K Shell(/usr/bin/ksh)
- Shell for Root(/sbin/sh)
- ……
我们关注的是 Bash,也就是 Bourne Again Shell,由于易用和免费,Bash在日常工作中被广泛使用。同时,Bash也是大多数Linux系统默认的Shell。
在一般情况下,人们并不区分 Bourne Shell 和 Bourne Again Shell,所以,像 #!/bin/sh
,它同样也可以改为#!/bin/bash
。#!
告诉系统其后路径所指定的程序即是解释此脚本文件的Shell程序。
修改shell
chsh -s /bin/bash
shell脚本的执行方式
脚本格式要求
- 脚本以
#!/bin/bash
开头 - 脚本需要有可执行权限
通过/usr/bin/env 运行程序,用户不需要去寻找程序在系统中的位置(因为在不同的系统,命令或程序存放的位置可能不同),只要程序在你的$PATH中;
通过/usr/bin/env 运行程序另一个好处是,它会根据你的环境寻找并运行默认的版本,提供灵活性。
不好的地方是,有可能在一个多用户的系统中,别人在你的$PATH中放置了一个bash,可能出现错误。
大部分情况下,/usr/bin/env是优先选择的,因为它提供了灵活性,特别是你想在不同的版本下运行这个脚本;而指定具体位置的方式#! /usr/bin/bash,在某些情况下更安全,因为它限制了代码注入的可能。
脚本的常用执行方式
-
输入脚本的绝对路径或相对路径
- 首先要赋予helloworld.sh 脚本的+x权限
- 执行脚本
-
sh+脚本
说明:不用赋予脚本+x权限,直接执行即可
注释
单行注释:#
多行注释::<<!
开头,!
结尾
在shell脚本中执行命令
先来说一下主要以下有几种方式:
- fork: 如果脚本有执行权限的话,path/to/foo.sh。如果没有,sh path/to/foo.sh。
- exec: exec path/to/foo.sh
- source: source path/to/foo.sh
fork
fork
是最普通的, 就是直接在脚本里面用 path/to/foo.sh
来调用 foo.sh
这个脚本,比如如果是 foo.sh 在当前目录下,就是 ./foo.sh
。运行的时候 terminal 会新开一个子 Shell 执行脚本 foo.sh,子 Shell 执行的时候, 父 Shell 还在。子 Shell 执行完毕后返回父 Shell。 子 Shell 从父 Shell 继承环境变量,但是子 Shell 中的环境变量不会带回父 Shell。
exec
exec
与 fork
不同,不需要新开一个子 Shell 来执行被调用的脚本. 被调用的脚本与父脚本在同一个 Shell 内执行。但是使用 exec 调用一个新脚本以后, 父脚本中 exec 行之后的内容就不会再执行了。这是 exec
和 source
的区别.
source
与 fork
的区别是不新开一个子 Shell 来执行被调用的脚本,而是在同一个 Shell 中执行. 所以被调用的脚本中声明的变量和环境变量, 都可以在主脚本中进行获取和使用。
shell变量
Shell的变量的介绍
- Linux Shell中的变量分为,系统变量和用户自定义变量。
- 系统变量:
$HOME
、$PWD
、$SHELL
、$USER
等等 - 显示当前shell中所有变量:set
用户自定义变量
基本语法
- 定义变量:变量=值
- 撤销变量:unset 变量
- 声明静态变量:readonly 变量,注意:不能 unset
- 可把变量提升为全局环境变量,可供其他 shell 程序使用(参考系统变量)
定义变量的规则
- 变量名称可以由字母、数字和下划线组成,但是不能以数字开头。
- 等号两侧不能有空格
- 变量名称一般习惯为大写
将命令的返回值赋给变量
- A=`ls -la` 反引号,运行里面的命令,并把结果返回给变量 A
- A=
$(ls -la)
等价于反引号 (推荐)
系统变量
基本语法
- 在配置文件(eg
/etc/profile
)中执行export 变量名=变量值
(功能描述:将 shell 变量输出为环境变量) - source 配置文件 (功能描述:让修改后的配置信息立即生效)
- echo $变量名 (功能描述:查询环境变量的值)
位置参数变量
当我们执行一个 shell 脚本时,如果希望获取到命令行的参数信息,就可以使用到位置参数变 量,比如 : ./myshell.sh 100 200
, 这个就是一个执行 shell 的命令行,可以在 myshell 脚本中获取到参数信息
基本语法
$n
(功能描述:n 为数字,$0
代表命令本身,$1-$9
代表第一到第九个参数,十以上的参数,十 以上的参数需要用大括号包含,如${10}
)$*
(功能描述:这个变量代表命令行中所有的参数,$*
把所有的参数看成一个整体)$@
(功能描述:这个变量也代表命令行中所有的参数,不过$@
把每个参数区分对待)$#
(功能描述:这个变量代表命令行中所有参数的个数)
预定义变量
就是 shell 设计者事先已经定义好的变量,可以直接在 shell 脚本中使用
基本语法
$$
(功能描述:当前进程的进程号(PID))$!
(功能描述:后台运行的最后一个进程的进程号(PID))$?
(功能描述:最后一次执行的命令的返回状态。如果这个变量的值为 0,证明上一个命令 正确执行;如果这个变量的值为非 0(具体是哪个数,由命令自己来决定),则证明上一个命令执行不正确了。)
应用实例
在一个 shell 脚本中简单使用一下预定义变量
|
|
运行结果:
|
|
运算符
基本语法
-
$((运算式))
-
$[运算式]
, 推荐写法 -
expr 运算时
注意 expr 运算符间要有空格,运算符:
\*
, /, % 乘,除,取余
应用案例
- 计算(2+3)X4 的值
- 请求出命令行的两个参数[整数]的和
编写脚本:
|
|
测试脚本:
|
|
条件判断
基本语法
[ condition ](注意condition前后要有空格)
非空返回true,可使用$?验证(0为true,>1为false)
-
[ “sss” ] 返回true
-
[] 返回false
-
[ condition ] && echo OK || echo notok 条件满足,执行后面的语句,否则执行或运算后面的语句
eg:
1 2 3 4 5
$ [ a = b ] && echo OK || echo notOK notOK $ [ a = a ] && echo OK || echo notOK OK
判断语句
字符串比较
= 字符串比较
两个整数比较
- -lt 小于
- -le 小于等于
- -eq 等于
- -gt 大于
- -ge 大于等于
- -ne 不等于
按照文件权限进行判断
- -r 有读的权限
- -w 有写的权限
- -x 有执行的权限
按照文件类型进行判断
- -f 文件存在并且是一个常规的文件
- -e 文件存在
- -d 文件存在并是一个目录
演示
|
|
运行结果
|
|
流程控制
if
基本语法
|
|
或者
|
|
推荐使用第二种
演示
编写一个 shell 程序,如果输入的参数,大于等于 60,则输出 “及格了”,如果小于 60, 则输出 “不及格”
|
|
运行结果:
|
|
case
基本语法
|
|
演示
当命令行参数是 1 时,输出 “周一”, 是 2 时,就输出"周二", 其它情况输出"other"
|
|
运行结果:
|
|
for
基本语法
|
|
或者
|
|
演示
案例 1 :打印命令行输入的参数【会使用到$*
$@
】
|
|
运行结果:
|
|
案例 2:从 1 加到 100 的值输出显示
|
|
运行结果:
|
|
while
基本语法
|
|
演示
|
|
运行结果
|
|
read读取控制台输入
基本语法
read (选项) (参数)
选项:
- -p:指定读取值时的提示符;
- -t:指定读取值时等待的时间(秒),如果没有在指定的时间内输入,就不再等待了。。
参数:指定读取值的变量名
演示
案例 1:读取控制台输入一个 num 值
案例 2:读取控制台输入一个 num 值,在 10 秒内输入。
|
|
运行结果:
|
|
函数
shell 编程和其它编程语言一样,有系统函数,也可以自定义函数。系统函数中,我们这里就介绍 两个。
系统函数
basename
基本语法:basename [pathname] [suffix]
功能:返回完整路径最后 / 的部分,常用于获取文件名
basename [string] [suffix]
功能描述:basename 命令会删掉所有的前缀包括最后一个(‘/’)字符,然后将字符串显示出来。
选项: suffix 为后缀,如果 suffix 被指定了,basename 会将 pathname 或 string 中的 suffix 去掉。
dirname
基本语法:dirname 文件绝对路径
功能:返回完整路径最后 / 的前面的部分,常用于返回路径部分
演示
|
|
自定义函数
基本语法
|
|
直接写函数名:funname [值]
演示
|
|
运行结果:
|
|
shell编程综合案例
需求分析
- 每天凌晨 2:10 备份 数据库 atguiguDB 到 /data/backup/db
- 备份开始和备份结束能够给出相应的提示信息
- 备份后的文件要求以备份时间为文件名,并打包成 .tar.gz 的形式,比如: 2018-03-12_230201.tar.gz
- 在备份的同时,检查是否有 10 天前备份的数据库文件,如果有就将其删除。
shell脚本如下:
|
|
在mysql容器里执行如下:
|
|
配置任务处理器
|
|