从理论到实战,一份详实的Shell脚本教程,值得收藏!
Shell是一个命令解释器,它在操作系统的最外层,负责直接与用户对话,把用户的输入解释给操作系统,并处理各种各样的操作系统的输出结果,输出屏幕返回给用户。
Shell脚本语言是实现Linux/UNIX系统管理及自动化运维所必备的重要工具 ,Linux/UNIX系统的底层及基础应用软件的核心大都涉及Shell脚本的内容。
每一个合格的Linux系统管理员或运维工程师,都需要能够熟练地编写Shell脚本语言, 并能够阅读系统及各类软件附带的Shell脚本内容。
只有这样才能提升运维人员的工作效率,适应曰益复杂的工作环境,减少不必要的重复工作,从而为个人的职场发展奠定较好的基础。
下面是常见命令解释器:
命令解释器 | 说明 |
---|---|
bash | 目前应用最广泛一款命令解释器红帽系列(默认),Debian,Ubuntu,BASH全称:Bourne-Again Shell |
dash | 一般debian/ubuntu系统默认的, 运行脚本推荐使用bash lidao.sh |
csh,tcsh | 一些unix系统使用 |
zsh | 功能更多,支持更多的插件,可以更好看。 |
shell脚本(.bash .sh),运行在ubuntu中的时候,不推荐使用sh运行,推荐使用bash运行
编程语言分类(执行方式)
编程语言分类 | 说明 |
---|---|
解析型:直接解析类 | shell,python,php,书写成文件后,可以通过对应的解释器直接运行 |
编译型:需要编译后运行 | C,C++,Java(maven),Golang下载好源代码,必须要进行译生成可以运行的命令 |
解释型
[root@m01 ~]# cat /server/scripts/show.py
print("hello world hello oldboy")
[root@m01 ~]# python /server/scripts/show.py
hello world hello oldboy
编译型
[root@m01 ~]# cat /server/scripts/show.c
#include "stdio.h"
void main() {
printf( "hello world c lang hell oldboy lidao" );
编译代码:
[root@m01 ~]# gcc /server/scripts/show.c -o
/server/scripts/show.bin
生成命令:
/server/scripts/show.bin
hello world c lang hell oldboy lidao
编程环境准备
环境 | 说明 |
---|---|
主机 | m01 oldboy-devops-shell;10.0.0.61/172.16.1.61 |
代码目录 | /server/scripts/devops-shell/ |
编程环境 | vim/sublime...../编程环境IDE,这里选择VIM或sublime即可 |
vim配置 | 自动添加说明信息,创建.sh或.bash,自动添加信息 |
修改vimrc文件,达到控制vim创建,编辑文件的动作
set ignorecase
autocmd BufNewFile *.py,*.cc,*.sh,*.java exec ":call
SetTitle()"
func SetTitle()
if expand("%:e") 'sh'
call setline(1, "/bin/bash")
setline(
2,"###############################################
###############")
call setline(3, "# File Name:".expand("%"))
call setline(4, "# Version:V1.0")
call setline(5, "# Author:oldboy lidao996")
call setline(6, "# Organization:www.oldboyedu.com")
call setline(7, "# Desc:")
setline(8,"###############################################
###############")
endif
endfunc
set ignorecase 搜索的时候忽略大小写
设置条件创建.py .sh 文件的时候 使用SetTitle函数
autocmd BufNewFile *.py,*.cc,*.sh,*.java exec ":call
SetTitle()"
func SetTitle()
if expand("%:e") 'sh' 判断结尾是.sh
setline写入行 1表示行号.
call setline(1, "/bin/bash")
setline(2,"###############################################
###############")
call setline(3, "# File Name:".expand("%"))
call setline(4, "# Version:V1.0")
call setline(5, "# Author:oldboy")
call setline(6, "# Organization:www.oldboyedu.com")
call setline(7, "# Desc:输入脚本作用")
setline(8,"###############################################
###############")
endif 判断结束
endfunc 函数结束
shell脚本执行方式
1.概述
应用及场景 | 说明 |
---|---|
通过sh或bash | 书写脚本后,最常用的方式,在其他非红帽系统中,建议使用bash运行脚本 |
通过.(点)或source | 加载/生效配置文件(环境变量,别名) /etc/profile 常用:可以用来实现include功能,把其他脚本引入到当天脚本中 |
通过相对或绝对路径 | 我们一般不推荐使用这种,一般都是系统脚本/服调用的脚本,脚本需要加上执行权限才能用 |
输入重定向符号 | 不推荐使用 |
2.详解
1)sh或bash
[root@oldboy-devops-shell ~]# cat
/server/scripts/01.show-v3.sh
/bin/bash
##########################################################
# File Name:/server/scripts/01.show-v3.sh
# Version:V1.0
# Author:oldboy lidao996
# Organization:www.oldboyedu.com
# Desc: show hostname
##########################################################
hostname
whoami
[root@oldboy-devops-shell ~]# sh /server/scripts/01.showv3.sh
oldboy-devops-shell
/root
[root@oldboy-devops-shell ~]# bash
/server/scripts/01.show-v3.sh
oldboy-devops-shell
/root
2).或source
[root@oldboy-devops-shell ~]# . /server/scripts/01.showv3.sh
oldboy-devops-shell
/root
[root@oldboy-devops-shell ~]# source
/server/scripts/01.show-v3.sh
oldboy-devops-shell
/root
3)相对或绝对路径
给脚本加上执行权限,系统/服务调用某个脚本的时候这样用的
chmod +x 01.show-v3.sh
./01.show-v3.sh
oldboy-devops-shell
/server/scripts/devops-shell
/server/scripts/devops-shell/01.show-v3.sh
oldboy-devops-shell
/server/scripts/devops-shell
4)使用重定向符号执行脚本
sh <01.show-v3.sh
oldboy-devops-shell
/server/scripts/devops-shell
3.#!符号含义
并非注释的意思,写在脚本开头,用于指定脚本默认的命令解释器
命令解释器 | 写法 |
---|---|
bash | #!/bin/bash |
python | #!/usr/bin/python2或/usr/bin/env python2 |
从变量开始
变量即variable,顾名思义为变化的值
#变量定义(创建)
oldboy=lidao996
#变量取值
echo $oldboy
lidao996
1.变量命名
变量命名要求:
- 不能以数字开头
- 不能以特殊符号开头,可以以"_"开头
- 推荐字母开头
变量的命名方式:
- 驼峰方式: personOfName personOfAge
- 现代式: 单词(小写)+"_下划线"连接person_of_name
- 不要写不能直接表示含义的变量 ,如:a1=lidao a2=oldboy a3=996
2.变量分类
分类 | 说明 | 要求 |
---|---|---|
普通变量(局部变量) | 我们在脚本中通过 oldboy=形式创建就是普通变量 | 常用,必会 |
环境变量(全局变量) | 一般都是系统创建,PATH,PS1 | 掌握几个常用的环境变量及含义 |
特殊变量 | shell脚本,命令,各种方面 | shell编程核心 |
1)普通变量
day=6
echo $day
因为shell认为dayhao是一个变量,取值为空.
echo $dayhao
echo ${金庸}新作
-bash: ${金庸}新作: bad substitution
echo ${day}hao
6hao
与{}一致,可以用于取值;${变量} 指定变量名字
2)环境变量
全局变量: 1处定义,处处使用 大部分都是系统定义的,我们一般就是修改
env
export
declare
环境变量名字 | 重要程度 | 含义 | 应用场景 |
---|---|---|---|
PATH | ☆☆☆☆☆ | 记录命令位置的环境变量,运行命令的时候bash会在PATH的路径中查找 | 通过二进制包或编译安装软件,增加新的命令路径 |
LANG | ☆☆☆☆☆ | 系统语言与字符集Language 中文 LANG=zh_CN.UTF8 LANG=en_S.UTF8 | 修改语言字符集 |
PS1 | ☆☆ | 命令行格式 | 修改命令行格式,生产环境不推荐修改 |
UID或EUID | 用户的uid,用于判断当前用户是否为root | 用于脚本判断用户是否root | |
HOSTNAME | 主机名 | ||
HIST四人组 | history命令 历史命令相关 | ||
HISTSIZE | ☆☆ | history命令记录多多条指令, 生产环境尽量少 | 未来安全优化配置 |
HISTFILESIZE | ☆☆ | history 历史记录文件的大小 ~/.bash_history生产环境尽量少 | 未来安全优化配置 |
HISTCONTROL | ☆☆ | 控制历史命令记录或不记录哪些内容 生产环境ignorespace以空格开头的命令 不记录 | 未来安全优化配置 |
HISTFILE | ☆☆ | 指定历史命令的记录文件的名字和位置.默认当前用户家目录.bash_history | 未来安全优化配置或手写跳板机/行为审计 |
PROMPT_COMMAND | ☆☆ | 存放命令,命令行执行命令后会运行这个变量的内容,用于实现行为审计(记录用户操作) | 手写跳板机/行为审计 |
IFS | 类似于awk -F指定分隔符(指定每一列的分隔符) | 一般与循环配合读取文件内容 | |
TMOUT | ☆☆ | 超时自动退出时间 | 未来安全优化配置 |
修改环境变量
export 创建或修改全局变量(环境变量)
案例01 把当前系统语言改为中文,字符集改为UTF-8
export LANG=zh_CN.UTF-8
永久的就是写入到 /etc/profile最后即可.
source /etc/profile
env |grep LANG
LANG=zh_CN.UTF-8
3)环境变量相关文件
文件或目录 | 说明 | 应用场景 |
---|---|---|
/etc/profile | 全局生效(国法) 存放函数,环境变量 存放别名 | |
/etc/bashrc | 全局生效(国法) 存放别名 | |
~/.bashrc | 家规(局部生效) | |
~/.bash_profile | 家规(局部生效) | |
/etc/profile.d/ | 目录,每个用户登录的时候(远程连接与su切换),加载目录下面.sh结尾的文件. | 设置一些登录后提示,变化 |
案例01: 书写脚本每次用户登录后显示系统的基本信息
堆命令
要求显示的内容与格式:
主机名:m01-shell
ip地址:10.0.0.61 172.16.1.61
总计内存:1.9G
可用内存:1.5G
系统负载:0.32, 0.23, 0.25
分析
第1步骤:获取指标的命令。
主机名: hostname
ip地址: hostname -I
内存总数:free -h |awk 'NR2{print $2}'
可用内存: free -h |awk 'NR2{print $NF}'
系统负载:uptime |sed 's#^.*age: g'
系统负载:uptime |awk '{print $(NF-2),$(NF-1),$NF}'
书写脚本与调试
[root@oldboy-devops-shell /server/scripts/devops-shell]#
cat 02.sys_login_info.sh
/bin/bash
##########################################################
# File Name:02.sys_login_info.sh
# Version:V1.0
# Author:oldboy lidao996
# Organization:www.oldboyedu.com
# Desc: 用户登录系统后显示系统的基本信息
##########################################################
#########
#1.赋值
#########
sys_hostname=`hostname`
sys_ip_addrs=`hostname -I
sys_mem_total=`free -h |awk 'NR2{print $2}'`
sys_mem_free=`free -h |awk 'NR2{print $NF}'`
sys_load=`uptime |awk '{print $(NF-2),$(NF-1),$NF}'`
#########
#2.输出
#########
cat EOF
主机名: ${sys_hostname}
ip地址: ${sys_ip_addrs}
总内存: ${sys_mem_total}
可用内存: ${sys_mem_free}
系统负载: ${sys_load}
EOF


实现目标 软连接过去即可
ln -s /server/scripts/devops-shell/02.sys_login_info.sh
/etc/profile.d/sys_login_info.sh
[root@oldboy-devops-shell /server/scripts/devops-shell]# ll
/etc/profile.d/sys_login_info.sh
lrwxrwxrwx 1 root root 49 6月 16 17:35
/etc/profile.d/sys_login_info.sh -> /server/scripts/devopsshell/02.sys_login_info.sh
重新登陆并测试


4)特殊变量
linux、shell编程中有各种各样的特殊变量,方便对参数,命令结果,进行判断与对比
特殊变量分类 | 核心 |
---|---|
位置相关的特殊变量 | ☆☆☆☆☆ |
状态相关的特殊变量 | ☆☆☆☆☆ |
变量子串 | |
变量扩展 |
案例02: 执行脚本的时候输入用户名,判断用户名是否存在
注意:这里的判断可以不用,直接使用id用户名即可
效果
sh /server/scripts/devops-shell/03.check_user.sh oldboy
相当于执行id oldboy
sh /server/scripts/devops-shell/03.check_user.sh root
id root
核心问题:如何把命令行中脚本的参数,传递到参数内部
[root@m01-oldboy-auto-shell /server/scripts/devops-shell]#
cat 03.check_user.sh
/bin/bash
##########################################################
# File Name:03.check_user.sh
# Version:V1.0
# Author:oldboy lidao996
# Organization:www.oldboyedu.com
# Desc: 检查指定用户是否存在(无判断)
##########################################################
#1.vars
username=$1
#2.处理
echo "正在检查$username是否存在...."
echo "请稍后......."
echo "有点卡多等等."
sleep 5
id $username
echo "是否存在这个用户,请自己看...."
echo "看啥呢: 提示no such user就是不存在"
echo "提示:用户信息就是存在"
echo "恭喜你都会自己检查了....."
echo "脚本执行完毕,点个赞吧"

案例03: 如果脚本执行出错了,需要我们输出脚本的使用帮助
温馨提示:先略过如何检查是否出错
echo "xxx.sh {start|stop|restart}"

[root@m01-oldboy-auto-shell /server/scripts/devops-shell]#
sh 04.show-usage.sh
使用方法: 04.show-usage.sh {start|stop|restart}
[root@m01-oldboy-auto-shell /server/scripts/devops-shell]#
sh /server/scripts/devops-shell/04.show-usage.sh
[root@m01-oldboy-auto-shell /server/scripts/devops-shell]#
sh /server/scripts/devops-shell/04.show-usage.sh
使用方法: /server/scripts/devops-shell/04.show-usage.sh
{start|stop|restart}
[root@m01-oldboy-auto-shell /server/scripts/devops-shell]#
cat /server/scripts/devops-shell/04.show-usage.sh
/bin/bash
##########################################################
# File Name:04.show-usage.sh
# Version:V1.0
# Author:oldboy lidao996
# Organization:www.oldboyedu.com
# Desc: 脚本执行的时候 用户输入的参数不对,提示个错误信息
##########################################################
echo "使用方法: $0 {start|stop|restart}"
案例04: 判断脚本参数的格式,如果不等于1,则输出使用提示参考03案例
[root@m01-oldboy-auto-shell /server/scripts/devops-shell]#
sh 05.check_parm_num.sh
帮助: 05.check_parm_num.sh {start|stop|restart}
[root@m01-oldboy-auto-shell /server/scripts/devops-shell]#
sh 05.check_parm_num.sh start
[root@m01-oldboy-auto-shell /server/scripts/devops-shell]#
cat 05.check_parm_num.sh
/bin/bash
##########################################################
# File Name:05.check_parm_num.sh
# Version:V1.0
# Author:oldboy lidao996
# Organization:www.oldboyedu.com
# Desc:
##########################################################
#-eq equal
#-ne not equal
if [ $# -ne 1 ];then
echo "帮助: $0 {start|stop|restart}"
fi
Shell编程运算
1.运算符
shell-运算符 | 含义 |
---|---|
+ | 加法符号 |
- | 减法符号 |
* | 乘法符号 |
/ | 除法符号 |
% | 取余 |
^或** 幂、指数 | 2^10=1024 10个2相乘 |
i=i+1 i++ | 计数,计算次数 |
j=j+ j+= | 求和,累加 |
&& | 并且,前一个命令执行成功,再执行后面的命令(判断) |
2.运算方法
运算的命令/符号 | 说明 | 应用场景 |
---|---|---|
awk | 可以进行计算,带小数,可以与shell脚本进行变量传递 | 一般计算都可以用awk |
bc | 带小数 | 一般计算都可以用bc.需要安装 |
expr | 进行计算,整数 | 一般用于检查输入内容是否为数字(方法之一) |
let | 进行计算,整数,变量直接使用即可 | 用于计算i++ |
$(()) | 进行计算,整数,变量直接使用即可 | |
$[] | 进行计算,整数,变量直接使用即可 |
1)awk进行计算
基础用法
awk 'BEGIN{print 1/3}'
awk 'BEGIN{print 1/3*100}'
在awk中使用shell变量
awk -vn1=1 -vn2=3 'BEGIN{print n1/n2}'
0.333333

在awk中各种变量直接使用即可,不要加上$n1,如果加上了会被awk识别为取列

2)bc
基本用法即可,-l显示小数
echo 1/3 |bc -l
echo 2^10 |bc -l
3)expr
使用注意事项:使用空格,对*号转义
[root@oldboy-devops-shell ~]# expr 1+1
1+1
[root@oldboy-devops-shell ~]# expr 1 + 1
[root@oldboy-devops-shell ~]# expr 2 * 2
expr: 语法错误
[root@oldboy-devops-shell ~]# expr 2 \* 2
[root@oldboy-devops-shell ~]# expr 2 / 2
1
Shell编程-加点逻辑-判断
1.条件表达式
条件表达式属于判断中的核心,if后面都在使用它
1)格式
条件表达式也可以叫条件测试语句
含义与特点 | test 或 [ ] | [[ ]] 或 (( )) (小括号) |
---|---|---|
共同点 | 都可以用于判断 | 都可以用于判断 |
区别1 | 仅支持普通判断,不支持正则 | [[]]普通判断,支持正则 |
区别2 | 表示逻辑关系(与或非)符号不同 -a -o ! -gt | [[ ]] ! > < <= >= |
应用场景 | 大部分情况下使用 [] 进行常见判断 | [[ ]] 使用正则的时候使用2对中括号,(())可以用于运算 |
2)判断文件
条件表达式-文件 | 说明 |
---|---|
-f | file判断是否存在,判断这个是否为文件,如果是则为真(成立) |
-d | dir判断是否存在,判断这个是否为目录,如果是则为真(成立) |
-x | executable判断是否存在,是否有执行权限 |
-s | size 判断是否存在,文件大小是否大于0 (是否为空) 非空为真 |
-r | 是否有读权限 |
-w | 是否有读权限 |
-nt | newer than |
-ot | older than 两个文件修改时间 是否更加老 |
-L | 软连接 |
-e | 是否存在(任何类型文件) |
检查指定的文件是否存在
1. 条件测试语句,不会直接提示对错,通过返回值提示.