Shell 学习笔记 - Shell 三剑客篇
Shell 三剑客
1. 什么是 Shell 三剑客
Shell 三剑客指学习和编辑 Shell 脚本用途巨大的三个工具:
grep
: Global Regular Expression Print,核心功能为查找和过滤,用于在文本中搜索匹配指定内容的行,并将匹配到的行打印出来sed
: Stream EDitor,核心功能为编辑和转换文本流,主要用于对文本进行替换、删除、选取、新增等操作。它特别擅长处理按行进行的编辑任务awk
: 由 Aho, Weinberger, Kernighan 三位创始人的姓名命名,核心功能为文本分析和报告生成,它擅长处理结构化文本(如日志、CSV文件),能够按列进行处理和计算,功能最为复杂和强大
2. 正则表达式
学习 Shell 三剑客前,还需要知道一个非常厉害的文本匹配工具:正则表达式
2.1 什么是正则表达式
正则表达式作为一个 partten
,用于将 partten
与字符串匹配,一边查找一个或多个字符串
以下部分学习前,请先准备以下文件:
[alex@controller ~ 15:13:56]$ vim words
cat
category
acat
concatenate
dog
2.2 匹配字符集
语法 | 用法 |
---|---|
[...] | 匹配字符集 |
[a-z] | 匹配某个范围的字符 |
[^...] | 匹配不包含字符集的字符 |
[a.z] | 匹配出换行外任意一个单个字符与指定字符集 |
[\n] | 匹配转义字符,主要用于匹配非打印字符和特殊字符等 |
[cat|dog] | 匹配 cat 或 dog 字符 |
2.3 匹配非打印字符
字符 | 含义 |
---|---|
\n | 换行符 |
\s | 空白字符 |
\S | 非空白字符 |
\w | 任意字母、数字、下划线 |
\W | 与 \w 相反 |
\t | 制表符 |
2.4 定位符
字符 | 含义 |
---|---|
^ | 匹配行首 |
$ | 匹配行尾 |
\b | 匹配单词边界 |
\B | 匹配非单词边界 |
\< \> | 匹配单词左边界、右边界 |
2.5 限定次数
字符 | 含义 |
---|---|
* | 匹配任意次数 |
+ | 匹配一次及以上,属扩展表达式 |
? | 匹配一次及以下,属扩展表达式 |
{n} | 匹配 n 次,属扩展表达式 |
{n,m} | 匹配 n~m 次,一端可保持空白,属扩展表达式 |
2.6 反向引用
对一个正则表达式模式或部分模式两边添加圆括号将导致相关匹配存储到一个临时缓冲区中,所捕获的每个子匹配都按照在正则表达式模式中从左到右出现的顺序存储。
缓冲区编号从 1 开始,最多可存储 99 个捕获的子表达式
2.7 实践
匹配有效 IP 地址
现有一串 IP 地址,需要从中筛选出有效(含 0,255)的 IP 地址
也可自行尝试匹配去掉 0 和 255 的写法
0.0.0.0
1.1.1.1
11.11.11.111
111.111.111.111
999.9.9.9
01.1.1.1
10.0.0.0
0.1.1.1
266.1.1.1
248.1.1.1
256.1.1.1
# 先从第一位下手
# IP 地址的有效范围为 0~255,故有以下几种可能:
# - 1. 三位数,25开头,第三位只能是 0~5
# - 2. 三位数,2开头,第二位只能是 0~4,第三位可以是任意数
# - 3. 三位数,1开头,第二、三位可以是任意数
# - 4. 二位数,第一位不能为 0,第二位可以是任意数
# - 5. 一位数,可以是任意数
# 将上述可能转换为匹配表达式如下:
25[0-5]
2[0-4][0-9]
1[0-9][0-9]
[1-9][0-9]
[0-9]# 将它们合并成为一行,加上或条件,如下:
25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9]# 由于前三个数后带有点,故添加点,并标记为整体,重复匹配 3 次,如下:
((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}# 最后一个数与其他数规则一致,仅少一个点,将整体复制添加在以上代码后方,如下:
((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])# 添加边缘定位符,完整的表达式如下:
'\b((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\b'# 执行命令,运行结果如下:
[root@server ~ 23:47:00]# cat ips | egrep '\b((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\b'
0.0.0.0
1.1.1.1
11.11.11.111
111.111.111.111
10.0.0.0
0.1.1.1
248.1.1.1
3. grep
3.1 grep 基本用法
grep
命令可以用于过滤管道,也可以用于过滤文件
# 过滤管道
命令 | grep [选项] 参数# 过滤文件
grep [选项] 参数 文件名
默认情况下,grep
命令会过滤所有带有参数文本的行
示例:过滤 passwd
文件中含有 usr
文本的行
3.2 内容相关选项
参数 | 用途 |
---|---|
-E | 匹配正则表达式,等价于 egrep |
-e | 同时匹配多个参数 |
-f FILENAME | 同时匹配文件 FILENAME 中存放的多个参数 |
-i | 忽略大小写 |
-w | 仅匹配整个单词 |
-x | 仅匹配整行 |
-v | 反向匹配 |
示例 1: 同时匹配 var
和 usr
示例 2: 匹配文件 word
中的参数
示例 3: 匹配 apache
,忽略大小写
示例 4: 仅匹配 bin
整个单词
示例 5: 匹配除包含 var
外的内容
3.3 匹配与输出相关选项
选项 | 用途 |
---|---|
-mx | 指定匹配 x 行后停止 |
-c | 输出匹配次数 |
-n | 输出行号 |
-o | 仅显示匹配到的内容 |
-q | 输出匹配返回值 |
-s | 不显示提示 |
示例 1: 匹配前 3 行含有 usr
的信息
示例 2: 显示文件中 bin
的匹配次数
示例 3: 匹配文件中带有 var
的行与行号
3.4 目录与文件查找相关选项
选项 | 用途 |
---|---|
-r | 递归匹配目录 |
-R | 递归匹配目录,跟随软连接 |
-h | 不显示匹配项目所在文件的文件名 |
-H | 显示匹配项目所在文件的文件名(默认) |
示例:查找 /etc
目录中含有 Apache
文本的文件
4. sed
4.1 sed 的工作流程
sed 工作流程,说起来真的很简单:读取、执行、显示,然后循环到数据全部处理完成
- 读取行:sed 从输入流 (文件、管道、标准输入流)中读取 一行 并存储在名叫 pattern space 的内部空间中。sed 是行文字处理器。每次只会读取一行。sed 内部会有一个计数器,记录着当前已经处理多少行,也就是当前行的行号
- 执行:按照 sed 命令定义的顺序依次应用于刚刚读取的 一行 数据。默认情况下,sed 一行一行的处理所有的输入数据。但如果我们指定了行号,则只会处理指定的行
- 显示:把经过 sed 命令处理的数据发送到输出流(文件、管道、标准输出),并同时清空 space 空间
pattern space
空间是 sed 在内存中开辟的一个私有的存储区域。内存的特性,会导致关闭命令行或关机数据就没了。默认情况下,sed 命令只会处理 pattern space
空间中的数据,且并不会将处理后的数据
sed 还在内存上开辟了另一个私有的空间 hold space
用于保存处理后的数据以供以后检索。每一个周期执行结束,sed 会清空 pattern space
空间的内容,但 hold space
空间的内容并不会清空。hold space
空间用于存储处理后数据,sed 命令并不会对这里的数据处理
sed 程序执行前,pattern
和 hold space
空间都是空的。如果我们没有传递任何输入文件,sed 默认会从标准输入中读取数据。sed 可以指定只处理输入数据中的行范围。默认情况下是全部行,因此会依次处理每一行。
4.2 sed 基本用法
sed [选项] 文件名# 常用选项
# -e: 执行 sed 命令
# -f: 执行 sed 脚本文件
# -n: 不显示原内容
# -r: 引入正则表达式
sed 命令使用
''
标记
4.3 行寻址
sed '起始行,终止行p'
4.4 模式寻址
模式寻址指通过字符串筛选指定的行
sed '/字符串/p'
4.5 sed 命令
sed 命令 | 用途 |
---|---|
p | 打印所有记录 |
P | 打印第一行记录(默认) |
n | 提前读取下一行,并覆盖之前读取的行 |
N | 将下一行追加到本行 |
s/abc/xyz/ | 用 xyz 替换掉 abc |
aTEXT | 在匹配行下方插入文本 TEXT |
iTEXT | 在匹配行上方插入文本 TEXT |
d | 删除所有记录(模式空间) |
D | 删除第一行记录(模式空间) |
= | 输出行号 |
y/aa/AA/ | 大小写转换 |
r FILENAME | 读取文件 FILENAME 内容 |
w FILENAME | 写入文件 FILENAME 内容 |
5. awk
5.1 awk 命令格式
awk [选项] 脚本|脚本文件 文件名
awk 脚本语法如下:
BEGIN { action }
pattern { action }
END { action }
变量 | 数据类型 | 默认值 | 用途 |
---|---|---|---|
ARGC | number | 1 | 命令行参数的数目 |
ARGIND | number | 0 | 命令行中当前文件的位置(从0开始算) |
ARGV | array | 1 elements | 包含命令行参数的数组 |
CONVFMT | string | “%.6g” | 数字转换格式 |
ERRNO | number | 0 | 最后一个系统错误的描述 |
FIELDWIDTHS | string | “” | 字段宽度列表 |
FILENAME | string | “” | 当前文件名 |
FNR | number | 0 | 同 NR,但相对于当前文件 |
FS | string | " " | 字段分隔符 |
IGNORECASE | number | 0 | 如果为真,则进行忽略大小写的匹配 |
NF | number | 0 | 当前记录中的字段数 |
NR | number | 0 | 当前记录数(读入第几行数据) |
OFMT | string | “%.6g” | 数字的输出格式 |
OFS | string | " " | 输出字段分隔符 |
ORS | string | “\n” | 输出记录分隔符 |
RLENGTH | number | 0 | 由 match 函数所匹配的字符串的长度 |
RS | string | “\n” | 记录分隔符 |
RSTART | number | 0 | 由 match 函数所匹配的字符串的第一个位置 |
SUBSEP | string | “\034” | 数组下标分隔符 |