从理论到实战,一份详实的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. 条件测试语句,不会直接提示对错,通过返回值提示.