教程一共8章:
01_SHELL编程前奏_小工具
02_SHELL编程之变量定义
03_SHELL编程之条件判断和流程控制
04_SHELL编程之循环语句_2
05_SHELL编程之嵌套循环+随机数及综合案例
06_SHELL编程之CASE语句+函数+正则
07_SHELL编程之文本处理工具sed
08_SHELL编程之文本处理工具awk
01_SHELL编程前奏_小工具
本节课程目标
- 了解shell中的通配符
- 熟悉grep、cut、sort等小工具和shell中的通配符的使用
一、文本处理工具
1. ==grep工具==
grep是==行==过滤工具;用于根据关键字进行行过滤
语法和选项
语法:
1 | # grep [选项] '关键字' 文件名 |
常见选项:
1 | OPTIONS: |
颜色显示(别名设置):
1 | 临时设置: |
举例说明:
==说明:不要直接使用/etc/passwd文件,将其拷贝到/tmp下做实验!==
1 | # grep -i root passwd 忽略大小写匹配包含root的行 |
2. ==cut工具==
cut是==列==截取工具,用于列的截取
语法和选项
语法:
1 | # cut 选项 文件名 |
常见选项:
1 | -c: 以字符为单位进行分割,截取 |
举例说明:
1 | # cut -d: -f1 1.txt 以:冒号分割,截取第1列内容 |
课堂练习:
用小工具列出你当系统的运行级别。5/3
- 如何查看系统运行级别
- 命令
runlevel - 文件
/etc/inittab
- 命令
- 如何过滤运行级别
1 | runlevel |cut -c3 |
find
Linux find 命令用来在指定目录下查找文件。任何位于参数之前的字符串都将被视为欲查找的目录名。如果使用该命令时,不设置任何参数,则 find 命令将在当前目录下查找子目录与文件。并且将查找到的子目录和文件全部进行显示。
语法
1 | find path -option [ -print ] [ -exec -ok command ] {} \; |
参数说明 :
find 根据下列规则判断 path 和 expression,在命令列上第一个 - ( ) , ! 之前的部份为 path,之后的是 expression。如果 path 是空字串则使用目前路径,如果 expression 是空字串则使用 -print 为预设 expression。
expression 中可使用的选项有二三十个之多,在此只介绍最常用的部份。
-mount, -xdev : 只检查和指定目录在同一个文件系统下的文件,避免列出其它文件系统中的文件
-amin n : 在过去 n 分钟内被读取过
-anewer file : 比文件 file 更晚被读取过的文件
-atime n : 在过去 n 天内被读取过的文件
-cmin n : 在过去 n 分钟内被修改过
-cnewer file :比文件 file 更新的文件
-ctime n : 在过去 n 天内创建的文件
-mtime n : 在过去 n 天内修改过的文件
-empty : 空的文件-gid n or -group name : gid 是 n 或是 group 名称是 name
-ipath p, -path p : 路径名称符合 p 的文件,ipath 会忽略大小写
-name name, -iname name : 文件名称符合 name 的文件。iname 会忽略大小写
-size n : 文件大小 是 n 单位,b 代表 512 位元组的区块,c 表示字元数,k 表示 kilo bytes,w 是二个位元组。
-type c : 文件类型是 c 的文件。
d: 目录
c: 字型装置文件
b: 区块装置文件
p: 具名贮列
f: 一般文件
l: 符号连结
s: socket
-pid n : process id 是 n 的文件
你可以使用 ( ) 将运算式分隔,并使用下列运算。
exp1 -and exp2
! expr
-not expr
exp1 -or exp2
exp1, exp2
1 | 实例 |
3. sort工具
sort工具用于排序;它将文件的每一行作为一个单位,从首字符向后,依次按ASCII码值进行比较,最后将他们按升序输出。
语法和选项
1 | -u :去除重复行 |
举例说明
1 | # sort -n -t: -k3 1.txt 按照用户的uid进行升序排列 |
4.uniq工具
uniq用于去除==连续==的==重复==行
1 | 常见选项: |
5.tee工具
tee工具是从标准输入读取并写入到标准输出和文件,即:双向覆盖重定向(屏幕输出|文本输入)
1 | 选项: |
6.diff工具
diff工具用于逐行比较文件的不同
注意:diff描述两个文件不同的方式是告诉我们==怎样改变第一个==文件之后==与第二个文件匹配==。
语法和选项
语法:
1 | diff [选项] 文件1 文件2 |
常用选项:
| 选项 | 含义 | 备注 |
|---|---|---|
| -b | 不检查空格 | |
| -B | 不检查空白行 | |
| -i | 不检查大小写 | |
| -w | 忽略所有的空格 | |
| –normal | 正常格式显示(默认) | |
| -c | 上下文格式显示 | |
| -u | 合并格式显示 |
举例说明:
- 比较两个==普通文件==异同,文件准备:
1 | [root@MissHou ~]# cat file1 |
1)正常显示
1 | diff目的:file1如何改变才能和file2匹配 |
2)上下文格式显示
1 | [root@MissHou ~]# diff -c file1 file2 |
3)合并格式显示
1 | [root@MissHou ~]# diff -u file1 file2 |
- 比较两个==目录不同==
1 | 默认情况下也会比较两个目录里相同文件的内容 |
其他小技巧:
有时候我们需要以一个文件为标准,去修改其他文件,并且修改的地方较多时,我们可以通过打补丁的方式完成。
1 | 1)先找出文件不同,然后输出到一个文件 |
7. paste工具
paste工具用于合并文件行
1 | 常用选项: |
8. tr工具
tr用于字符转换,替换和删除;主要用于==删除文件中控制字符==或进行==字符转换==
语法和选项
语法:
1 | 用法1:命令的执行结果交给tr处理,其中string1用于查询,string2用于转换处理 |
常用选项:
1 | -d 删除字符串1中所有输入字符。 |
常匹配字符串:
| 字符串 | 含义 | 备注 |
|---|---|---|
| ==a-z==或[:lower:] | 匹配所有小写字母 | 所有大小写和数字[a-zA-Z0-9] |
| ==A-Z==或[:upper:] | 匹配所有大写字母 | |
| ==0-9==或[:digit:] | 匹配所有数字 | |
| [:alnum:] | 匹配所有字母和数字 | |
| [:alpha:] | 匹配所有字母 | |
| [:blank:] | 所有水平空白 | |
| [:punct:] | 匹配所有标点符号 | |
| [:space:] | 所有水平或垂直的空格 | |
| [:cntrl:] | 所有控制字符 | \f Ctrl-L 走行换页 \n Ctrl-J 换行 |
| \r Ctrl-M 回车 | ||
| \t Ctrl-I tab键 |
举例说明:
1 | [root@MissHou shell01]# cat 3.txt 自己创建该文件用于测试 |
小试牛刀
- 使用小工具分别截取当前主机IP;截取NETMASK;截取广播地址;截取MAC地址
1 | # ifconfig eth0|grep 'Bcast'|tr -d '[a-zA-Z ]'|cut -d: -f2,3,4 |
- 将系统中所有普通用户的用户名、密码和默认shell保存到一个文件中,要求用户名密码和默认shell之间用tab键分割
1 | # grep 'bash$' passwd |grep -v 'root'|cut -d: -f1,2,7|tr ':' '\t' |tee abc.txt |
二、bash的特性
##1、命令和文件自动补全
Tab只能补全==命令和文件== (RHEL6/Centos6)
##2、常见的快捷键
1 | ^c 终止前台运行的程序 |
##3 、==常用的通配符(重点)==
1 | *: 匹配0或多个任意字符 |
##4、==bash中的引号(重点)==
- 双引号”” :会把引号的内容当成整体来看待,允许通过$符号引用其他变量值
- 单引号’’ :会把引号的内容当成整体来看待,禁止引用其他变量值,shell中特殊符号都被视为普通字符
- 反撇号`` :反撇号和$()一样,引号或括号里的命令会优先执行,如果存在嵌套,反撇号不能用
1 | [root@MissHou dir1]# echo "$(hostname)" |
02_SHELL编程之变量定义
SHELL编程模块课程目标
① Shell的基本语法结构
如:变量定义、条件判断、循环语句(for、until、while)、分支语句、函数和数组等;
② 基本正则表达式的运用;
③ 文件处理三剑客:grep、sed、awk工具的使用;
④ 使用shell脚本完成一些较复杂的任务,如:服务搭建、批量处理等。
说明:以上内容仅仅是基本要求,还有很多更深更难的语法需要扩充学习。
本节目标
- ==熟练掌握shell变量的定义和获取(重点)==
- ==能够进行shell简单的四则运算==
一、SHELL介绍
前言:
计算机只能认识(识别)机器语言(0和1),如(11000000 这种)。但是,我们的程序猿们不能直接去写01这样的代码,所以,要想将程序猿所开发的代码在计算机上运行,就必须找”人”(工具)来==翻译成机器语言==,这个”人”(工具)就是我们常常所说的==编译器==或者==解释器==。
编译和解释型语言区别
##1. 编程语言分类
- 编译型语言:
==程序在执行之前需要一个专门的编译过程==,把程序编译成为机器语言文件,运行时不需要重新翻译,直接使用编译的结果就行了。程序执行效率高,依赖编译器,跨平台性差些。如C、C++
- 解释型语言:
程序不需要编译,程序在运行时由==解释器==翻译成机器语言,每执行一次都要翻译一次。因此效率比较低。比如Python/JavaScript/ Perl /ruby/==Shell==等都是解释型语言。
语言分类
- 总结
编译型语言比解释型语言==速度较快==,但是不如解释型语言==跨平台性好==。如果做底层开发或者大型应用程序或者操作系开发一==般都用编译型语言==;如果是一些服务器脚本及一些辅助的接口,对速度要求不高、对各个平台的==兼容性有要求==的话则一般都用==解释型语言==。
##2. shell简介
00_shell介绍
总结:
- ==shell就是人机交互的一个桥梁==
- shell的种类
1 | [root@MissHou ~]# cat /etc/shells |
思考:终端和shell有什么关系?
01_shell介绍
##3. shell脚本
㈠ 什么是shell脚本?
- 一句话概括
简单来说就是将==需要执行的命令==保存到文本中,==按照顺序执行==。它是解释型的,意味着不需要编译。
- 准确叙述
若干命令 + 脚本的基本格式 + 脚本特定语法 + 思想= shell脚本
㈡ 什么时候用到脚本?
重复化、复杂化的工作,通过把工作的命令写成脚本,以后仅仅需要执行脚本就能完成这些工作。
㈢ shell脚本能干啥?
①自动化软件部署 LAMP/LNMP/Tomcat…
②自动化管理 系统初始化脚本、批量更改主机密码、推送公钥…
③==自动化分析处理== 统计网站访问量
④==自动化备份== 数据库备份、日志转储…
⑤自动化监控脚本
㈣ 如何学习shell脚本?
- 尽可能记忆更多的命令(记忆命令使用功能和场景)
- 掌握脚本的标准的格式(指定魔法字节、使用标准的执行方式运行脚本)
- 必须==熟悉掌握==脚本的基本语法(重点)
㈤ 学习shell脚本的秘诀
多看(看懂)——>模仿(多练)——>多思考(多写)
㈥ shell脚本的基本写法
1)脚本第一行,魔法字符==#!==指定解释器【==必写==】
#!/bin/bash 表示以下内容使用bash解释器解析
==注意:==
如果直接将解释器路径写死在脚本里,可能在某些系统就会存在找不到解释器的兼容性问题,所以可以使用:==#!/bin/env 解释器== ==#!/bin/env bash==
2)脚本第二部分,注释(#号)说明,对脚本的基本信息进行描述【可选】
1 | #!/bin/env bash |
3)脚本第三部分,脚本要实现的具体代码内容
㈦ shell脚本的执行方法
- 标准脚本执行方法(建议)
1 | 1) 编写人生第一个shell脚本 |
- 非标准的执行方法(不建议)
- 直接在命令行指定解释器执行
1 | [root@MissHou shell01]# bash first_shell.sh |
- 使用
source命令读取脚本文件,执行文件里的代码
1 | [root@MissHou shell01]# source first_shell.sh |
小试牛刀:写一个木有灵魂的脚本,要求如下:
删除/tmp/目录下的所有文件
然后在/tmp目录里创建3个目录,分别是dir1~dir3
拷贝/etc/hosts文件到刚创建的dir1目录里
最后打印”==报告首长,任务已于2019-05-05 10:10:10时间完成==”内容
echo "报告首长,任务已于$(date +'%F %T')"
==二、变量的定义==
1. 变量是什么?
一句话概括:变量是用来临时保存数据的,该数据是可以变化的数据。
2. 什么时候需要定义变量?
- 如果某个内容需要多次使用,并且在代码中重复出现,那么可以用变量代表该内容。这样在修改内容的时候,仅仅需要修改变量的值。
- 在代码运作的过程中,可能会把某些命令的执行结果保存起来,后续代码需要使用这些结果,就可以直接使用这个变量。
3.变量如何定义?
变量名=====变量值
变量名:用来临时保存数据的
变量值:就是临时的可变化的数据
1 | [root@MissHou ~]# A=hello 定义变量A |
4. 变量的定义规则
虽然可以给变量(变量名)赋予任何值;但是,对于==变量名==也是要求的!:unamused:
㈠ 变量名区分大小写
1 | [root@MissHou ~]# A=hello |
㈡ 变量名不能有特殊符号
1 | [root@MissHou ~]# *A=hello |
㈢ 变量名不能以数字开头
1 | [root@MissHou ~]# 1A=hello |
㈣ 等号两边不能有任何空格
1 | [root@MissHou ~]# A =123 |
㈤ 变量名尽量做到见名知意
1 | NTP_IP=10.1.1.1 |
5. 变量的定义方式有哪些?
㈠ 基本方式
直接赋值给一个变量
1 | [root@MissHou ~]# A=1234567 |
㈡ 命令执行结果赋值给变量
1 | [root@MissHou ~]# B=`date +%F` |
㈢ ==交互式定义变量(read)==
目的:让==用户自己==给变量赋值,比较灵活。
语法:read [选项] 变量名
常见选项:
| 选项 | 释义 |
|---|---|
| -p | 定义提示用户的信息 |
| -n | 定义字符数(限制变量值的长度) |
| -s | 不显示(不显示用户输入的内容) |
| -t | 定义超时时间,默认单位为秒(限制用户输入变量值的超时时间) |
举例说明:
1 | 用法1:用户自己定义变量值 |
用法2:变量值来自文件
1 | [root@MissHou ~]# cat 1.txt |
㈣ 定义有类型的变量(==declare==)
目的: 给变量做一些限制,固定变量的类型,比如:整型、只读
用法:declare 选项 变量名=变量值
常用选项:
| 选项 | 释义 | 举例 |
|---|---|---|
| ==-i== | 将变量看成整数 | declare -i A=123 |
| ==-r== | 定义只读变量 | declare -r B=hello |
| -a | 定义普通数组;查看普通数组 | |
| -A | 定义关联数组;查看关联数组 | |
| -x | 将变量通过环境导出 | declare -x AAA=123456 等于 export AAA=123456 |
举例说明:
1 | [root@MissHou ~]# declare -i A=123 |
6. 变量的分类
㈠ 本地变量
- ==本地变量==:当前用户自定义的变量。当前进程中有效,其他进程及当前进程的子进程无效。
㈡ 环境变量
- 环境变量:当前进程有效,并且能够被子进程调用。
env查看当前用户的环境变量set==查询当前用户的所有变量(临时变量与环境变量)==export 变量名=变量值或者变量名=变量值;export 变量名
1 | [root@MissHou ~]# export A=hello 临时将一个本地变量(临时变量)变成环境变量 |
㈢ 全局变量
全局变量:全局所有的用户和程序都能调用,且继承,新建的用户也默认能调用.
解读相关配置文件
| 文件名 | 说明 | 备注 |
|---|---|---|
| $HOME/.bashrc | 当前用户的bash信息,用户==登录==时读取 | 定义别名、umask、函数等 |
| $HOME/.bash_profile | 当前用户的环境变量,用户==登录==时读取 | |
| $HOME/.bash_logout | 当前用户==退出==当前shell时最后读取 | 定义用户退出时执行的程序等 |
| /etc/bashrc | 全局的bash信息,所有用户都生效 | |
| /etc/profile | 全局环境变量信息 | 系统和所有用户都生效 |
| $HOME/.bash_history | 用户的历史命令 | history -w 保存历史记录 history -c 清空历史记录 |
说明:以上文件修改后,都需要重新==source==让其生效或者退出重新登录。
- 用户登录系统读取相关==文件的顺序==
/etc/profile$HOME/.bash_profile$HOME/.bashrc/etc/bashrc$HOME/.bash_logout
㈣ ==系统变量==
- 系统变量(内置bash中变量) : shell本身已经固定好了它的名字和作用.
| 内置变量 | 含义 |
|---|---|
| ==$?== | 上一条命令执行后返回的状态;状态值为0表示执行正常,==非0==表示执行异常或错误 |
| $0 | 当前执行的程序或脚本名 |
| ==$#== | 脚本后面接的参数的==个数== |
| ==$*== | 脚本后面==所有参数==,参数当成一个整体输出,每一个变量参数之间以空格隔开 |
| ==$@== | 脚本后面==所有参数==,参数是独立的,也是全部输出 |
| ==$1~$9== | 脚本后面的==位置参数==,$1表示第1个位置参数,依次类推 |
| ${10}~${n} | 扩展位置参数,第10个位置变量必须用{}大括号括起来(2位数字以上扩起来) |
| ==$$== | 当前所在进程的进程号,如echo $$ |
| $! | 后台运行的最后一个进程号 (当前终端) |
| !$ | 调用最后一条命令历史中的==参数== |
- 进一步了解位置参数
$1~${n}
1 | #!/bin/bash |
- 进一步了解$*和$@的区别
$*:表示将变量看成一个整体$@:表示变量是独立的
1 | #!/bin/bash |
三、简单四则运算
算术运算:默认情况下,shell就只能支持简单的==整数==运算
运算内容:加(+)、减(-)、乘(*)、除(/)、求余数(%)
1. 四则运算符号
| 表达式 | 举例 |
|---|---|
| $(( )) | echo $((1+1)) |
| $[ ] | echo $[10-5] |
| expr | expr 10 / 5 |
| let | n=1;let n+=1 等价于 let n=n+1 |
2.了解i++和++i
- 对变量的值的影响
1 | [root@MissHou ~]# i=1 |
- 对==表达式==的值的影响
1 | [root@MissHou ~]# unset i j |
四、扩展补充
1. 数组定义
㈠ 数组分类
- 普通数组:只能使用整数作为数组索引(元素的下标)
- 关联数组:可以使用字符串作为数组索引(元素的下标)
㈡ 普通数组定义
- 一次赋予一个值
1 | 数组名[索引下标]=值 |
- 一次赋予多个值
1 | 数组名=(值1 值2 值3 ...) |
㈢ 数组的读取
1 | ${数组名[元素下标]} |
㈣ 关联数组定义
①首先声明关联数组
==declare -A asso_array1==
1 | declare -A asso_array1 |
② 数组赋值
- 一次赋一个值
1 | 数组名[索引or下标]=变量值 |
- 一次赋多个值
1 | # asso_array2=([name1]=harry [name2]=jack [name3]=amy [name4]="Miss Hou") |
- 查看关联数组
1 | # declare -A |
- 获取关联数组值
1 | # echo ${asso_array1[linux]} |
- 其他定义方式
1 | [root@MissHou shell05]# declare -A books |
2. 其他变量定义
- 取出一个目录下的目录和文件:
dirname和basename
1 | # A=/root/Desktop/shell/mem.txt |
- -==变量”内容”的删除和替换==
1 | 一个“%”代表从右往左删除 |
- 以下了解,自己完成
1 | 替换:/ 和 // |
03_SHELL编程之条件判断和流程控制
本节课程目标
- 熟悉条件判断语句,如判断整数、判断字符串等
- 熟悉流程控制语句基本语法,如if…else…
一、条件判断语法结构
思考:何为真(==true==)?何为假(==false==)?
##1. ==条件判断语法格式==
- 格式1: ==test== 条件表达式
- 格式2: [ 条件表达式 ]
- 格式3: [[ 条件表达式 ]] 支持正则 =~
特别说明:
1)==[== 亲亲,我两边都有空格,不空打死你呦 ==]== :imp:
2)==[[== 亲亲,我两边都有空格,不空打死你呦 ==]]==:imp:
3) 更多判断,man test去查看,很多的参数都用来进行条件判断
2. 条件判断相关参数
问:你要判断什么?
答:我要判断文件类型,判断文件新旧,判断字符串是否相等,判断权限等等…
㈠ ==判断文件类型==
| 判断参数 | 含义 |
|---|---|
| ==-e== | 判断文件是否存在(任何类型文件) |
| -f | 判断文件是否存在==并且==是一个普通文件 |
| -d | 判断文件是否存在并且是一个目录 |
| -L | 判断文件是否存在并且是一个软连接文件 |
| -b | 判断文件是否存在并且是一个块设备文件 |
| -S | 判断文件是否存在并且是一个套接字文件 |
| -c | 判断文件是否存在并且是一个字符设备文件 |
| -p | 判断文件是否存在并且是一个命名管道文件 |
| ==-s== | 判断文件是否存在并且是一个非空文件(有内容) |
举例说明:
1 | test -e file 只要文件存在条件为真 |
㈡ 判断文件权限
| 判断参数 | 含义 |
|---|---|
| -r | 当前用户对其是否可读 |
| -w | 当前用户对其是否可写 |
| -x | 当前用户对其是否可执行 |
| -u | 是否有suid,高级权限冒险位 |
| -g | 是否sgid,高级权限强制位 |
| -k | 是否有t位,高级权限粘滞位 |
㈢ 判断文件新旧
说明:这里的新旧指的是==文件的修改时间==。
| 判断参数 | 含义 |
|---|---|
| file1 -nt file2 | 比较file1是否比file2新 |
| file1 -ot file2 | 比较file1是否比file2旧 |
| file1 -ef file2 | 比较是否为同一个文件,或者用于判断硬连接,是否指向同一个inode |
㈣ 判断整数
| 判断参数 | 含义 |
|---|---|
| -eq | 相等 |
| -ne | 不等 |
| -gt | 大于 |
| -lt | 小于 |
| -ge | 大于等于 |
| -le | 小于等于 |
㈤ ==判断字符串==
| 判断参数 | 含义 |
|---|---|
| -z | 判断是否为==空==字符串,字符串长度为0则成立 |
| -n | 判断是否为==非空==字符串,字符串长度不为0则成立 |
| string1 = string2 | 判断字符串是否相等 |
| string1 != string2 | 判断字符串是否相不等 |
㈥ ==多重条件判断==
| 判断符号 | 含义 | 举例 |
|---|---|---|
| -a 和 && | 逻辑与 | [ 1 -eq 1 -a 1 -ne 0 ] [ 1 -eq 1 ] && [ 1 -ne 0 ] |
| -o 和 || | 逻辑或 | [ 1 -eq 1 -o 1 -ne 1 ] |
==特别说明:==
&& 前面的表达式==为真==,才会执行后面的代码
|| 前面的表达式==为假==,才会执行后面的代码
; ==只==用于==分割==命令或表达式
① 举例说明
- 数值比较
1 | [root@server ~]# [ $(id -u) -eq 0 ] && echo "the user is admin" |
- 类C风格的数值比较
1 | 注意:在(( ))中,=表示赋值;==表示判断 |
- 字符串比较
1 | 注意:双引号引起来,看作一个整体;= 和 == 在 [ 字符串 ] 比较中都表示判断 |
② 逻辑运算符总结
- 符号;和&&和||都可以用来分割命令或者表达式
- 分号(;)完全不考虑前面的语句是否正确执行,都会执行;号后面的内容
&&符号,需要考虑&&前面的语句的正确性,前面语句正确执行才会执行&&后的内容;反之亦然||符号,需要考虑||前面的语句的非正确性,前面语句执行错误才会执行||后内容;反之亦然- 如果&&和||一起出现,从左往右依次看,按照以上原则
二、流程控制语句
关键词:==选择==(人生漫漫长路,我该何去何从:vertical_traffic_light:)
1. 基本语法结构
㈠ ==if结构==
箴言1:只要正确,就要一直向前冲:v:
==F==:表示false,为假
==T==:表示true,为真
1 | if [ condition ];then |

㈡ ==if…else结构==
箴言2:分叉路口,二选一
1 | if [ condition ];then |

小试牛刀:
==让用户自己输入==字符串,==如果==用户输入的是hello,请打印world,==否则==打印“请输入hello”
read定义变量- if….else…
1 | #!/bin/env bash |
㈢ ==if…elif…else结构==
箴言3:选择很多,能走的只有一条
1 | if [ condition1 ];then |

㈣ 层层嵌套结构
箴言4:多次判断,带你走出人生迷雾。
1 | if [ condition1 ];then |

2. 应用案例
㈠ 判断两台主机是否ping通
需求:判断==当前主机==是否和==远程主机==是否ping通
① 思路
- 使用哪个命令实现
ping -c次数 - 根据命令的==执行结果状态==来判断是否通
$? - 根据逻辑和语法结构来编写脚本(条件判断或者流程控制)
② 落地实现
1 | #!/bin/env bash |
㈡ 判断一个进程是否存在
需求:判断web服务器中httpd进程是否存在
① 思路
- 查看进程的相关命令 ps pgrep
- 根据命令的返回状态值来判断进程是否存在
- 根据逻辑用脚本语言实现
② 落地实现
1 | #!/bin/env bash |
③ 补充命令
1 | pgrep命令:以名称为依据从运行进程队列中查找进程,并显示查找到的进程id |
㈢ 判断一个服务是否正常
需求:判断门户网站是否能够正常访问
① 思路
- 可以判断进程是否存在,用/etc/init.d/httpd status判断状态等方法
- 最好的方法是==直接去访问==一下,通过访问成功和失败的返回值来判断
- Linux环境,==wget== curl elinks -dump
② 落地实现
1 | #!/bin/env bash |
##3. 课堂练习
㈠ 判断用户是否存在
需求1:输入一个用户,用脚本判断该用户是否存在
1 | #!/bin/env bash |
㈡ 判断软件包是否安装
需求2:用脚本判断一个软件包是否安装,如果没安装则安装它(假设本地yum已配合)
1 |
㈢ 判断当前主机的内核版本
需求3:判断当前内核主版本是否为2,且次版本是否大于等于6;如果都满足则输出当前内核版本
1 | 思路: |
04_SHELL编程之循环语句_2
#本机课程目标
- 掌握for循环语句的基本语法结构
- 掌握while和until循环语句的基本语法结构
一、==for循环语句==
关键词:爱的魔力转圈圈:innocent:
1. for循环语法结构
㈠ ==列表==循环
列表for循环:用于将一组命令执行==已知的次数==
- 基本语法格式
1 | for variable in {list} |
- 举例说明
1 | # for var in {1..10};do echo $var;done |
㈡ 不带列表循环
不带列表的for循环执行时由用户指定参数和参数的个数
- 基本语法格式
1 | for variable |
- 举例说明
1 | #!/bin/bash |
㈢ 类C风格的for循环
- 基本语法结构
1 | for(( expr1;expr2;expr3 )) |
- 举例说明
1 | # for ((i=1;i<=5;i++));do echo $i;done |
2. 应用案例
㈠ 脚本==计算==1-100奇数和
① 思路
- 定义一个变量来保存奇数的和 ==sum===0
- 找出1-100的奇数,保存到另一个变量里 ==i===遍历出来的奇数
- 从1-100中找出奇数后,再相加,然后将和赋值给变量 循环变量 for
- 遍历完毕后,将sum的值打印出来
② 落地实现(条条大路通罗马)
1 | #!/bin/env bash |
③ 循环控制语句
循环体: ==do….done==之间的内容
- continue:继续;表示==循环体==内下面的代码不执行,重新开始下一次循环
- break:打断;马上停止执行本次循环,执行==循环体==后面的代码
- exit:表示直接跳出程序
1 | [root@server ~]# cat for5.sh |
㈡ 判断所输整数是否为质数
质数(素数):==只能==被1和它本身==整除==的数叫质数。
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97
① 思路
- 让用户输入一个数,保存到一个变量里
read -p "请输入一个正整数:" num - 如果能被其他数整除就不是质数——>
$num%$i是否等于0$i=2到$num-1 - 如果输入的数是1或者2取模根据上面判断又不符合,所以先排除1和2
- 测试序列从2开始,输入的数是4——>得出结果
$num不能和$i相等,并且$num不能小于$i
② 落地实现
1 | #!/bin/env bash |
㈢ 批量创建用户
需求:批量加5个新用户,以u1到u5命名,并统一加一个新组,组名为class,统一改密码为123
① 思路
- 添加用户的命令
useradd -G class - 判断class组是否存在
grep -w ^class /etc/group或者groupadd class - 根据题意,判断该脚本循环5次来添加用户
for - 给用户设置密码,应该放到循环体里面
② 落地实现
1 | #!/bin/env bash |
3. 课堂练习
㈠ 批量创建用户
需求1:批量新建5个用户stu1~stu5,要求这几个用户的家目录都在/rhome.
1 | #!/bin/bash |
㈡ 局域网内脚本检查主机网络通讯
需求2:
写一个脚本,局域网内,把能ping通的IP和不能ping通的IP分类,并保存到两个文本文件里
以10.1.1.1~10.1.1.10为例
1 | 10.1.1.1~10.1.1.254 |
延伸扩展:shell脚本并发
1 | 并行执行: |
㈢ 判断闰年
需求3:
输入一个年份,判断是否是润年(能被4整除但不能被100整除,或能被400整除的年份即为闰年)
1 | #!/bin/bash |
##4. 总结
- FOR循环语法结构
- FOR循环可以结合==条件判断和流程控制语句==
- do ……done 循环体
- 循环体里可以是命令集合,再加上条件判断以及流程控制
- 控制循环语句
- continue 继续,跳过本次循环,继续下一次循环
- break 打断,跳出循环,==执行==循环体外的代码
- exit 退出,直接退出程序
#二、==while循环语句==
特点:==条件为真就进入循环;条件为假就退出循环==
##1. while循环语法结构
1 | while 表达式 |
循环打印1-5数字
1 | FOR循环打印: |
2. 应用案例
㈠ 脚本计算1-50偶数和
1 | #!/bin/env bash |
㈡ 脚本同步系统时间
① 具体需求
- 写一个脚本,==30秒==同步一次系统时间,时间同步服务器10.1.1.1
- 如果同步失败,则进行邮件报警,每次失败都报警
- 如果同步成功,也进行邮件通知,但是==成功100次==才通知一次
② 思路
每隔30s同步一次时间,该脚本是一个死循环 while 循环
同步失败发送邮件 1) ntpdate 10.1.1.1 2) rdate -s 10.1.1.1
同步成功100次发送邮件 定义变量保存成功次数
③ 落地实现
1 | #!/bin/env bash |
#三、until循环
特点:==条件为假就进入循环;条件为真就退出循环==
1. until语法结构
1 | until expression [ 1 -eq 1 ] (( 1 >= 1 )) |
打印1-5数字
1 | i=1 |
2. 应用案例
###㈠ 具体需求
- 使用until语句批量创建10个用户,要求stu1—stu5用户的UID分别为1001—1005;
- stu6~stu10用户的家目录分别在/rhome/stu6—/rhome/stu10
㈡ 思路
- 创建用户语句
useradd -u|useradd -d - 使用循环语句(until)批量创建用户
until循环语句结构 - 判断用户前5个和后5个
条件判断语句
㈢ 落地实现
1 | #!/bin/env bash |
四、课后作业
- 判断/tmp/run目录是否存在,如果不存在就建立,如果存在就删除目录里所有文件
- 输入一个路径,判断路径是否存在,而且输出是文件还是目录,如果是链接文件,还得输出是 有效的连接还是无效的连接
- 交互模式要求输入一个ip,然后脚本判断这个IP 对应的主机是否 能ping 通,输出结果类似于:
Server 10.1.1.20 is Down! 最后要求把结果邮件到本地管理员root@localhost mail01@localhost - 写一个脚本/home/program,要求当给脚本输入参数hello时,脚本返回world,给脚本输入参数world时,脚本返回hello。而脚本没有参数或者参数错误时,屏幕上输出“usage:/home/program hello or world”
- 写一个脚本自动搭建nfs服务
05_SHELL编程之嵌套循环+随机数及综合案例
#课程目标
- ==掌握for循环语句的基本语法结构==
- ==掌握while和until循环语句的基本语法结构==
- 能会使用RANDOM产生随机数
- 理解嵌套循环
一、随机数
关键词:一切都是未知数,永远不知道明天会抽什么风:wind_chime::sweat_smile:
1. 如何生成随机数?
系统变量:==RANDOM==,默认会产生0~32767的随机整数
前言:要想调用变量,不管你是什么变量都要给钱,而且是美元:heavy_dollar_sign:
1 | 打印一个随机数 |
2. 实战案例
㈠ 随机产生以139开头的电话号码
具体需求1:
写一个脚本,产生一个phonenum.txt文件,随机产生以139开头的手机号1000个,每个一行。
① 思路
- 产生1000个电话号码,脚本需要循环1000次
FOR WHILE UNTIL - 139+8位,后8位随机产生,可以让每一位数字都随机产生
echo $[$RANDOM%10] - 将随机产生的数字分别保存到变量里,然后加上139保存到文件里
② 落地实现
1 |
|
㈡ 随机抽出5位幸运观众
具体需求:
- 在上面的1000个手机号里抽奖==5个==幸运观众,显示出这5个幸运观众。
- 但只显示头3个数和尾号的4个数,中间的都用*代替
① 思路
- 确定幸运观众所在的行
0-1000 随机找出一个数字 $[$RANDOM%1000+1] - 将电话号码提取出来
head -随机产生行号 phonenum.txt |tail -1 - ==显示==前3个和后4个数到屏幕
echo 139****
② 落地实现
1 | #!/bin/bash |
㈢ 批量创建用户(密码随机产生)
需求:批量创建5个用户,每个用户的密码为一个随机数
① 思路
- 循环5次创建用户
- 产生一个密码文件来保存用户的随机密码
- 从密码文件中取出随机密码赋值给用户
② 落地实现
1 | #!/bin/bash |
二、嵌套循环
关键字:大圈套小圈
:clock3:时钟:分针与秒针,秒针转⼀圈(60格),分针转1格。循环嵌套就是外层循环⼀次,内层循环⼀轮。
- 一个==循环体==内又包含另一个完整的循环结构,称为循环的嵌套。
- 每次外部循环都会==触发==内部循环,直至内部循环完成,才接着执行下一次的外部循环。
- for循环、while循环和until循环可以相互嵌套。
##1. 应用案例
㈠ 打印指定图案
1 | 1 |
㈡ 落地实现1
1 | X轴: |
㈢ 落地实现2
1 | Y轴:打印换行 |
##2. 课堂练习
打印九九乘法表(三种方法)
1 | 1*1=1 |
三、阶段性补充总结
1、变量定义
1 |
2. 流程控制语句
1 |
3. 循环语句
1 |
4. 影响shell程序的内置命令
1 | exit 退出整个程序 |
举例说明:
1 | 以下脚本都能够实现用户自定义输入数字,然后脚本计算和: |
##4. 补充扩展expect
expect 自动应答 tcl语言
需求1:A远程登录到server上什么都不做
1 | #!/usr/bin/expect |
需求2:A远程登录到server上操作
1 | #!/usr/bin/expect |
需求3:shell脚本和expect结合使用,在多台服务器上创建1个用户
1 | [root@server shell04]# cat ip.txt |
#四、综合案例
##1. 实战案例1
㈠ 具体需求
写一个脚本,将跳板机上yunwei用户的公钥推送到局域网内可以ping通的所有机器上
说明:主机和密码文件已经提供
10.1.1.1:123456
10.1.1.2:123456
###㈡ 案例分析
- 关闭防火墙和selinux
- 判断ssh服务是否开启(默认ok)
- ==循环判断给定密码文件里的哪些IP是可以ping通==
- ==判断IP是否可以ping通——>$?—>流程控制语句==
- ==密码文件里获取主机的IP和密码保存变量==
- ==判断公钥是否存在—>不存在创建它==
- ==ssh-copy-id 将跳板机上的yunwei用户的公钥推送到远程主机—>expect解决交互==
- ==将ping通的主机IP单独保存到一个文件==
- ==测试验证==
㈢ 落地实现
####① 代码拆分
1 | 1.判断yunwei用户的公钥是否存在 |
② 最终实现
- 环境准备
1 | jumper-server 有yunwei用户 |
- 脚本实现
1 | #!/bin/bash |
##2. 实战案例2
写一个脚本,统计web服务的不同==连接状态==个数
1 | #!/bin/bash |
#五、课后实战
1、将/etc/passwd里的用户名分类,分为管理员用户,系统用户,普通用户。
2、写一个倒计时脚本,要求显示离2019年1月1日(元旦)的凌晨0点,还有多少天,多少时,多少分,多少秒。
3、写一个脚本把一个目录内的所有==空文件==都删除,最后输出删除的文件的个数。
06_SHELL编程之CASE语句+函数+正则
#课程目标
- 掌握case语句的基本语法结构
- 掌握函数的定义及调用
- 掌握常用的正则表达式元字符含义
一、case语句
关键词:确认过眼神,你是对的人:couple_with_heart:
- case语句为多重匹配语句
- 如果匹配成功,执行相匹配的命令
1. 语法结构
1 | 说明:pattern表示需要匹配的模式 |
2. 应用案例
㈠ 脚本传不同值做不同事
具体需求:当给程序传入start、stop、restart三个不同参数时分别执行相应命令
1 | #!/bin/env bash |
㈡ 根据用户需求选择做事
具体需求:
脚本提示让用户输入需要管理的服务名,然后提示用户需要对服务做什么操作,如启动,关闭等操作
1 | #!/bin/env bash |
###㈢ 菜单提示让用户选择需要做的事
具体需求:
模拟一个多任务维护界面;当执行程序时先显示总菜单,然后进行选择后做相应维护监控操作
1 | **********请选择********* |
思路:
- 菜单打印出来
- 交互式让用户输入操作编号,然后做出相应处理
落地实现:
- 菜单打印(分解动作)
1 | #!/bin/env bash |
- 最终实现
1 | #!/bin/bash |
课堂练习:
- 输入一个等级(A-E),查看每个等级的成绩;如:输入A,则显示“90分~100分”,依次类推
- 判断用户输入的字符串,如果是”hello”,则显示”world”;如果是”world”,则显示”hello”,否则提示”请输入hello或者world,谢谢!”
二、==函数==
1. 什么是函数?
- shell中允许将一组命令集合或语句形成一段可用代码,这些代码块称为shell函数
- 给这段代码起个名字称为函数名,后续可以直接调用该段代码的功能
2. 如何定义函数?
方法1:
1 | 函数名() |
方法2:
1 | function 函数名() |
函数中==return==说明:
- return可以==结束一个函数==。类似于循环控制语句break(结束当前循环,执行循环体后面的代码)。
- return默认返回函数中最后一个命令状态值,也可以给定参数值,范围是0-256之间。
- 如果没有return命令,函数将返回最后一个指令的退出状态值。
##3. 函数如何调用?
㈠ 当前命令行调用
1 | [root@MissHou shell04]# cat fun1.sh |
㈡ 定义到用户的环境变量中
1 | [root@MissHou shell05]# vim ~/.bashrc |
㈢ 脚本中调用
1 | #!/bin/bash |
##4. 应用案例
具体需求:
- 写一个脚本==收集用户输入==的基本信息(姓名,性别,年龄),如不输入==一直提示输入==
- 最后根据用户的信息输出相对应的内容
思路:
==交互式==定义多个变量来保存用户信息 姓名、性别、年龄
如果不输一直提示输入
- ==循环==直到输入字符串不为空 while 判断输入字符串是否为空
- 每个信息都必须不能为空,该功能可以定义为一个函数,方便下面脚本调用
根据用户输入信息做出匹配判断
代码实现:
1 | #!/bin/bash |
扩展延伸:
1 | 描述以下代码含义: |
#三、综合案例
1. 任务背景
现有的跳板机虽然实现了统一入口来访问生产服务器,yunwei用户权限太大可以操作跳板机上的所有目录文件,存在数据被误删的安全隐患,所以希望你做一些安全策略来保证跳板机的正常使用。
2. 具体要求
- 只允许yunwei用户通过跳板机远程连接后台的应用服务器做一些维护操作
- 公司运维人员远程通过yunwei用户连接跳板机时,跳出以下菜单供选择:
1 | 欢迎使用Jumper-server,请选择你要操作的主机: |
- 当用户选择相应主机后,直接免密码登录成功
- 如果用户不输入一直提示用户输入,直到用户选择退出
3. 综合分析
- 将脚本放到yunwei用户家目录里的.bashrc文件里(/shell05/jumper-server.sh)
- 将菜单定义为一个函数[打印菜单],方便后面调用
- 用case语句来实现用户的选择【交互式定义变量】
- 当用户选择了某一台服务器后,进一步询问用户需要做的事情 case…esac 交互式定义变量
- 使用循环来实现用户不选择一直让其选择
- 限制用户退出后直接关闭终端 exit
4. 落地实现
1 | #!/bin/bash |
进一步完善需求
为了进一步增强跳板机的安全性,工作人员通过跳板机访问生产环境,但是不能在跳板机上停留。
1 | #!/bin/bash |
回顾信号:
1 | 1) SIGHUP 重新加载配置 |
四、正则表达式
##1. 正则表达式是什么?
正则表达式(Regular Expression、regex或regexp,缩写为RE),也译为正规表示法、常规表示法,是一种字符模式,用于在查找过程中==匹配指定的字符==。
许多程序设计语言都支持利用正则表达式进行字符串操作。例如,在Perl中就内建了一个功能强大的正则表达式引擎。
正则表达式这个概念最初是由Unix中的工具软件(例如sed和grep)普及开的。
支持正则表达式的程序如:locate |find| vim| grep| sed |awk
2. 正则能干什么?
- 匹配邮箱、匹配身份证号码、手机号、银行卡号等
- 匹配某些特定字符串,做特定处理等等
3. 正则当中名词解释
元字符
指那些在正则表达式中具有特殊意义的==专用字符==,如:点(.) 星(*) 问号(?)等
前导字符
位于元字符前面的字符. ab==c==* aoo==o==.
##4. 第一类正则表达式
㈠ 正则中普通常用的元字符
| 元字符 | 功能 | 备注 |
|---|---|---|
| . | 匹配除了换行符以外的==任意单个==字符 | |
| * | ==前导字符==出现==0==次或==连续多次== | |
| .* | 任意长度字符 | ab.* |
| ^ | 行首(以…开头) | ^root |
| $ | 行尾(以…结尾) | bash$ |
| ^$ | 空行 | |
| [] | 匹配括号里任意单个字符或一组单个字符 | [abc] |
| [^] | 匹配不包含括号里任一单个字符或一组单个字符 | [^abc] |
| ^[] | 匹配以括号里任意单个字符或一组单个字符开头 | ^[abc] |
| ^[^] | 匹配不以括号里任意单个字符或一组单个字符开头 | ^[^abc] |
- 示例文本
1 | # cat 1.txt |
- 举例说明
1 |
㈡ 正则中其他常用元字符
| 元字符 | 功能 | 备注 |
|---|---|---|
| \< | 取单词的头 | |
| \> | 取单词的尾 | |
| \< \> | 精确匹配 | |
| \{n\} | 匹配前导字符==连续出现n次== | |
| \{n,\} | 匹配前导字符==至少出现n次== | |
| \{n,m\} | 匹配前导字符出现==n次与m次之间== | |
| \( \) | 保存被匹配的字符 | |
| \d | 匹配数字(grep -P) | [0-9] |
| \w | 匹配字母数字下划线(grep -P) | [a-zA-Z0-9_] |
| \s | 匹配空格、制表符、换页符(grep -P) | [\t\r\n] |
举例说明:
1 | 需求:将10.1.1.1替换成10.1.1.254 |
㈢ 扩展类正则常用元字符
==丑话说在前面:==
我说我比较特殊,你要相信!否则我错给你看:smirk:
grep你要用我,必须加 ==-E== 或者 让你兄弟
egrep来找我sed你要用我,必须加 ==-r==
| 扩展元字符 | 功能 | 备注 |
|---|---|---|
| + | 匹配一个或多个前导字符 | bo+ 匹配boo、 bo |
| ? | 匹配零个或一个前导字符 | bo? 匹配b、 bo |
| | | 或 | 匹配a或b |
| () | 组字符(看成整体) | (my|your)self:表示匹配myself或匹配yourself |
| {n} | 前导字符重复n次 | |
| {n,} | 前导字符重复至少n次 | |
| {n,m} | 前导字符重复n到m次 |
举例说明:
1 | # grep "root|ftp|adm" /etc/passwd |
##5. 第二类正则
| 表达式 | 功能 | 示例 |
|---|---|---|
| [:alnum:] | 字母与数字字符 | [[:alnum:]]+ |
| [:alpha:] | 字母字符(包括大小写字母) | [[:alpha:]]{4} |
| [:blank:] | 空格与制表符 | [[:blank:]]* |
| [:digit:] | 数字 | [[:digit:]]? |
| [:lower:] | 小写字母 | [[:lower:]]{4,} |
| [:upper:] | 大写字母 | [[:upper:]]+ |
| [:punct:] | 标点符号 | [[:punct:]] |
| [:space:] | 包括换行符,回车等在内的所有空白 | [[:space:]]+ |
1 | [root@server shell05]# grep -E '^[[:digit:]]+' 1.txt |
6. 正则表达式总结
把握一个原则,让你轻松搞定可恶的正则符号:
- 我要找什么?
- 找数字 [0-9]
- 找字母 [a-zA-Z]
- 找标点符号 [[:punct:]]
- 我要如何找?看心情找
- 以什么为首 ^key
- 以什么结尾 key$
- 包含什么或不包含什么 [abc] ^[abc] [^abc] ^[^abc]
- 我要找多少呀?
- 找前导字符出现0次或连续多次 ab==*==
- 找任意单个(一次)字符 ab==.==
- 找任意字符 ab==.*==
- 找前导字符连续出现几次 {n} {n,m} {n,}
- 找前导字符出现1次或多次 go==+==
- 找前到字符出现0次或1次 go==?==
五、正则元字符一栏表
元字符:在正则中,具有特殊意义的专用字符,如: 星号(*)、加号(+)等
前导字符:元字符前面的字符叫前导字符
| 元字符 | 功能 | 示例 |
|---|---|---|
| * | 前导字符出现0次或者连续多次 | ab* abbbb |
| . | 除了换行符以外,任意单个字符 | ab. ab8 abu |
| .* | 任意长度的字符 | ab.* adfdfdf |
| [] | 括号里的任意单个字符或一组单个字符 | [abc][0-9][a-z] |
| [^] | 不匹配括号里的任意单个字符或一组单个字符 | [^abc] |
| ^[] | 匹配以括号里的任意单个字符开头 | ^[abc] |
| ^[^] | 不匹配以括号里的任意单个字符开头 | |
| ^ | 行的开头 | ^root |
| $ | 行的结尾 | bash$ |
| ^$ | 空行 | |
| \{n\}和{n} | 前导字符连续出现n次 | [0-9]\{3\} |
| \{n,\}和{n,} | 前导字符至少出现n次 | [a-z]{4,} |
| \{n,m\}和{n,m} | 前导字符连续出现n-m次 | go{2,4} |
| \<\> | 精确匹配单词 | \<hello\> |
| \(\) | 保留匹配到的字符 | \(hello\) |
| + | 前导字符出现1次或者多次 | [0-9]+ |
| ? | 前导字符出现0次或者1次 | go? |
| | | 或 | ^root|^ftp |
| () | 组字符 | (hello|world)123 |
| \d | perl内置正则 | grep -P \d+ |
| \w | 匹配字母数字下划线 |
六、正则练习作业
1. 文件准备
1 | # vim test.txt |
2. 具体要求
1 | 1、查找不以大写字母开头的行(三种写法)。 |
#七、课后作业
脚本搭建web服务
要求如下:
- 用户输入web服务器的IP、域名以及数据根目录
- 如果用户不输入则一直提示输入,直到输入为止
- 当访问www.test.cc时可以访问到数据根目录里的首页文件“this is test page”
参考脚本:
1 | 参考: |
07_SHELL编程之文本处理工具sed
#课程目标
- 掌握sed的基本语法结构
- 熟悉sed常用的命令,如打印p,删除d,插入i等
一、文件编辑器知多少
Windows系统

Linux系统
==vim vi== gedit nano emacs
#二、强悍的sed介绍
1. sed用来做啥?
sed是Stream Editor(流编辑器)的缩写,简称流编辑器;用来==处理文件==的。
2. sed如何处理文件?
sed是==一行一行读取==文件内容并==按照要求==进行==处理==,把处理后的结果==输出到屏幕==。

- 首先sed读取文件中的一行内容,把其保存在一个==临时缓存区中==(也称为模式空间)
- 然后==根据需求==处理临时缓冲区中的行,完成后把该行==发送到屏幕上==
总结:
- 由于sed把每一行都存在临时缓冲区中,对这个副本进行编辑,所以==不会直接修改原文件==
- Sed主要用来自动编辑一个或多个文件;简化对文件的反复操作,对文件进行过滤和转换操作
#三、sed使用方法介绍
sed常见的语法格式有两种,一种叫==命令行==模式,另一种叫==脚本==模式。
1. 命令行格式
㈠ 语法格式
sed [options] ==‘==处理动作==’== 文件名
- 常用选项
| 选项 | 说明 | 备注 |
|---|---|---|
| -e | 进行多项(多次)编辑 | |
| ==-n== | 取消默认输出 | 不自动打印模式空间 |
| ==-r== | 使用扩展==正则表达式== | |
| ==-i== | 原地编辑(修改源文件) | |
| -f | 指定sed脚本的文件名 |
- ==常见处理动作==
丑话说在前面:以下所有的==动作==都要在单引号里,你敢出轨,回家跪搓衣板
| 动作 | 说明 | 备注 |
|---|---|---|
| ‘p’ | 打印 | |
| ‘i’ | 在指定行==之前==插入内容 | 类似vim里的大写O |
| ‘a’ | 在指定行==之后==插入内容 | 类似vim里的小写o |
| ‘c’ | 替换指定行所有内容 | |
| ‘d’ | 删除指定行 |
㈡ 举例说明
- 文件准备
1 | # vim a.txt |
① 对文件进行==增、删、改、查==操作
语法:sed 选项 ==’==定位+命令==’== 需要处理的文件
1)打印文件内容
1 | [root@server ~]# sed '' a.txt 对文件什么都不做 |
2)增加文件内容
i 地址定位的上面插入
a 下面插入
1 | [root@server ~]# sed '$a99999' a.txt 文件最后一行下面增加内容 |
3)修改文件内容
c 替换指定的==整行==内容
1 | [root@server ~]# sed '5chello world' a.txt 替换文件第5行内容 |
4)删除文件内容
1 | [root@server ~]# sed '1d' a.txt 删除文件第1行 |
② ==对文件进行搜索替换操作==
语法:sed 选项 ‘==s/搜索的内容/替换的内容/动作==’ 需要处理的文件
其中,==s==表示search搜索;斜杠==/==表示分隔符,可以自己定义;动作一般是打印==p==和全局替换==g==
1 | [root@server ~]# sed -n 's/root/ROOT/p' 1.txt |
③ 其他命令
| 命令 | 解释 | 备注 |
|---|---|---|
| r | 从另外文件中读取内容 | |
| w | 内容另存为 | |
| & | 保存查找串以便在替换串中引用 | 和\(\)相同 |
| = | 打印行号 | |
| ! | 对所选行以外的所有行应用命令,放到行数之后 | ‘1,5!’ |
| q | 退出 |
举例说明:
1 | r 从文件中读取输入行 |
④ 其他选项
1 | -e 多项编辑 |
⑤ ==sed结合正则使用==
sed 选项 ==’==sed==命令==或者==正则表达式==或者==地址定位====’== 文件名
- 定址用于决定对哪些行进行编辑。地址的形式可以是数字、正则表达式、或二者的结合。
- 如果没有指定地址,sed将处理输入文件的所有行。
| 正则 | 说明 | 备注 |
|---|---|---|
| /key/ | 查询包含关键字的行 | sed -n ‘/root/p’ 1.txt |
| /key1/,/key2/ | 匹配包含两个关键字之间的行 | sed -n ‘/^adm/,/^mysql/p’ 1.txt |
| /key/,x | 从匹配关键字的行开始到==文件第x行==之间的行(包含关键字所在行) | sed -n ‘/^ftp/,7p’ |
| x,/key/ | 从文件的第x行开始到与关键字的匹配行之间的行 | |
| x,y! | 不包含x到y行 | |
| /key/! | 不包括关键字的行 | sed -n ‘/bash$/!p’ 1.txt |
##2. 脚本格式
㈠ 用法
1 | # sed -f scripts.sh file //使用脚本处理文件 |
㈡ 注意事项
1 | 1) 脚本文件是一个sed的命令行清单。'commands' |
㈢举例说明
1 | # cat passwd |
##3. 补充扩展总结
1 | 1、正则表达式必须以”/“前后规范间隔 |
#四、课堂练习
- 将任意数字替换成空或者制表符
- 去掉文件1-5行中的数字、冒号、斜杠
- 匹配root关键字替换成hello itcast,并保存到test.txt文件中
- 删除vsftpd.conf、smb.conf、main.cf配置文件里所有注释的行及空行(不要直接修改原文件)
- 使用sed命令截取自己的ip地址
- 使用sed命令一次性截取ip地址、广播地址、子网掩码
- 注释掉文件的2-3行和匹配到以root开头或者以ftp开头的行
1 |
|
#五、课后实战
1、写一个初始化系统的脚本
1)自动修改主机名(如:ip是192.168.0.88,则主机名改为server88.itcast.cc)
a. 更改文件非交互式 sed
/etc/sysconfig/network
b.将本主机的IP截取出来赋值给一个变量ip;再然后将ip变量里以.分割的最后一位赋值给另一个变量ip1
2)自动配置可用的yum源
3)自动关闭防火墙和selinux
2、写一个搭建ftp服务的脚本,要求如下:
1)不支持本地用户登录 local_enable=NO
2) 匿名用户可以上传 新建 删除 anon_upload_enable=YES anon_mkdir_write_enable=YES
3) 匿名用户限速500KBps anon_max_rate=500000
1 | 仅供参考: |
08_SHELL编程之文本处理工具awk
#课程目标
- 熟悉awk的命令行模式基本语法结构
- ==熟悉awk的相关内部变量==
- 熟悉awk常用的打印==函数print==
- 能够在awk中匹配正则表达式打印相关的行
一、awk介绍
1. awk概述
- awk是一种==编程语言==,主要用于在linux/unix下对==文本和数据==进行处理,是linux/unix下的一个工具。数据可以来自标准输入、一个或多个文件,或其它命令的输出。
- awk的处理文本和数据的方式:==逐行扫描==文件,默认从第一行到最后一行,寻找匹配的==特定模式==的行,并在这些行上进行你想要的操作。
- awk分别代表其作者姓氏的第一个字母。因为它的作者是三个人,分别是Alfred Aho、Brian Kernighan、Peter Weinberger。
- gawk是awk的GNU版本,它提供了Bell实验室和GNU的一些扩展。
- 下面介绍的awk是以GNU的gawk为例的,在linux系统中已把awk链接到gawk,所以下面全部以awk进行介绍。
2. awk能干啥?
- awk==用来处理文件和数据==的,是类unix下的一个工具,也是一种编程语言
- 可以用来==统计数据==,比如网站的访问量,访问的IP量等等
- 支持条件判断,支持for和while循环
#二、awk使用方式
1. ==命令行模式使用==
㈠ 语法结构
1 | awk 选项 '命令部分' 文件名 |
###㈡ 常用选项介绍
- ==-F== 定义字段分割符号,默认的分隔符是==空格==
- -v 定义变量并赋值
###㈢ ==’==命名部分说明==’==
- 正则表达式,地址定位
1 | '/root/{awk语句}' sed中: '/root/p' |
- {awk语句1==;==awk语句2==;==…}
1 | '{print $0;print $1}' sed中:'p' |
- BEGIN…END….
1 | 'BEGIN{awk语句};{处理中};END{awk语句}' |
2. 脚本模式使用
㈠ 脚本编写
1 | #!/bin/awk -f 定义魔法字符 |
㈡ 脚本执行
1 | 方法1: |
#三、 awk内部相关变量
| 变量 | 变量说明 | 备注 |
|---|---|---|
| ==$0== | 当前处理行的所有记录 | |
| ==$1,$2,$3…$n== | 文件中每行以==间隔符号==分割的不同字段 | awk -F: ‘{print $1,$3}’ |
| ==NF== | 当前记录的字段数(列数) | awk -F: ‘{print NF}’ |
| ==$NF== | 最后一列 | $(NF-1)表示倒数第二列 |
| ==FNR/NR== | 行号 | |
| ==FS== | 定义间隔符 | ‘BEGIN{FS=”:”};{print $1,$3}’ |
| ==OFS== | 定义输出字段分隔符,==默认空格== | ‘BEGIN{OFS=”\t”};print $1,$3}’ |
| RS | 输入记录分割符,默认换行 | ‘BEGIN{RS=”\t”};{print $0}’ |
| ORS | 输出记录分割符,默认换行 | ‘BEGIN{ORS=”\n\n”};{print $1,$3}’ |
| FILENAME | 当前输入的文件名 |
1、==常用内置变量举例==
1 | # awk -F: '{print $1,$(NF-1)}' 1.txt |
2、内置变量分隔符举例
1 | FS和OFS: |
#四、 awk工作原理
awk -F: '{print $1,$3}' /etc/passwd
awk使用一行作为输入,并将这一行赋给内部变量$0,每一行也可称为一个记录,以换行符(RS)结束
每行被间隔符==:==(默认为空格或制表符)分解成字段(或域),每个字段存储在已编号的变量中,从$1开始
问:awk如何知道用空格来分隔字段的呢?
答:因为有一个内部变量==FS==来确定字段分隔符。初始时,FS赋为空格
awk使用print函数打印字段,打印出来的字段会以==空格分隔==,因为$1,$3之间有一个逗号。逗号比较特殊,它映射为另一个内部变量,称为==输出字段分隔符==OFS,OFS默认为空格
awk处理完一行后,将从文件中获取另一行,并将其存储在$0中,覆盖原来的内容,然后将新的字符串分隔成字段并进行处理。该过程将持续到所有行处理完毕
五、awk使用进阶
1. 格式化输出print和printf
1 | print函数 类似echo "hello world" |
2. awk变量定义
1 | # awk -v NUM=3 -F: '{ print $NUM }' /etc/passwd |
##3. awk中BEGIN…END使用
①==BEGIN==:表示在==程序开始前==执行
②==END== :表示所有文件==处理完后==执行
③用法:'BEGIN{开始处理之前};{处理中};END{处理结束后}'
㈠ 举例说明1
打印最后一列和倒数第二列(登录shell和家目录)
1 | awk -F: 'BEGIN{ print "Login_shell\t\tLogin_home\n*******************"};{print $NF"\t\t"$(NF-1)};END{print "************************"}' 1.txt |
㈡ 举例说明2
打印/etc/passwd里的用户名、家目录及登录shell
1 | u_name h_dir shell |
###4. awk和正则的综合运用
| 运算符 | 说明 |
|---|---|
| == | 等于 |
| != | 不等于 |
| > | 大于 |
| < | 小于 |
| >= | 大于等于 |
| <= | 小于等于 |
| ~ | 匹配 |
| !~ | 不匹配 |
| ! | 逻辑非 |
| && | 逻辑与 |
| || | 逻辑或 |
㈠ 举例说明
1 | 从第一行开始匹配到以lp开头行 |
4. 课堂练习
- 显示可以登录操作系统的用户所有信息 从第7列匹配以bash结尾,输出整行(当前行所有的列)
1 | [root@MissHou ~] awk '/bash$/{print $0}' /etc/passwd |
- 显示可以登录系统的用户名
1 | # awk -F: '$0 ~ /\/bin\/bash/{print $1}' /etc/passwd |
- 打印出系统中普通用户的UID和用户名
1 | 500 stu1 |
##5. awk的脚本编程
㈠ 流程控制语句
① if结构
1 | if语句: |
② if…else结构
1 | if...else语句: |
③ if…elif…else结构
1 | if [xxxx];then |
㈡ 循环语句
① for循环
1 | 打印1~5 |
② while循环
1 | 打印1-5 |
③ 嵌套循环
1 | 嵌套循环: |
##6. awk算数运算
1 | + - * / %(模) ^(幂2^3) |
六、awk统计案例
1、统计系统中各种类型的shell
1 | # awk -F: '{ shells[$NF]++ };END{for (i in shells) {print i,shells[i]} }' /etc/passwd |
2、统计网站访问状态
1 | # ss -antp|grep 80|awk '{states[$1]++};END{for(i in states){print i,states[i]}}' |
3、统计访问网站的每个IP的数量
1 | # netstat -ant |grep :80 |awk -F: '{ip_count[$8]++};END{for(i in ip_count){print i,ip_count[i]} }' |sort |
4、统计网站日志中PV量
1 | 统计Apache/Nginx日志中某一天的PV量 <统计日志> |
名词解释:
==网站浏览量(PV)==
名词:PV=PageView (网站浏览量)
说明:指页面的浏览次数,用以衡量网站用户访问的网页数量。多次打开同一页面则浏览量累计。用户每打开一个页面便记录1次PV。
名词:VV = Visit View(访问次数)
说明:从访客来到您网站到最终关闭网站的所有页面离开,计为1次访问。若访客连续30分钟没有新开和刷新页面,或者访客关闭了浏览器,则被计算为本次访问结束。
独立访客(UV)
名词:UV= Unique Visitor(独立访客数)
说明:1天内相同的访客多次访问您的网站只计算1个UV。
独立IP(IP)
名词:IP=独立IP数
说明:指1天内使用不同IP地址的用户访问网站的数量。同一IP无论访问了几个页面,独立IP数均为1
#七、课后作业
作业1:
1、写一个自动检测磁盘使用率的脚本,当磁盘使用空间达到90%以上时,需要发送邮件给相关人员
2、写一个脚本监控系统内存和交换分区使用情况
作业2:
输入一个IP地址,使用脚本判断其合法性:
必须符合ip地址规范,第1、4位不能以0开头,不能大于255不能小于0
#八、企业实战案例
1. 任务/背景
web服务器集群中总共有9台机器,上面部署的是Apache服务。由于业务不断增长,每天每台机器上都会产生大量的访问日志,现需要将每台web服务器上的apache访问日志保留最近3天的,3天以前的日志转储到一台专门的日志服务器上,已做后续分析。如何实现每台服务器上只保留3天以内的日志?
2. 具体要求
- 每台web服务器的日志对应日志服务器相应的目录里。如:web1——>web1.log(在日志服务器上)
- 每台web服务器上保留最近3天的访问日志,3天以前的日志每天凌晨5:03分转储到日志服务器
- 如果脚本转储失败,运维人员需要通过跳板机的菜单选择手动清理日志
3. 涉及知识点
- shell的基本语法结构
- 文件同步rsync
- 文件查找命令find
- 计划任务crontab
- apache日志切割
- 其他