目录
前言
Linux中最重要的三个命令在业界被称为“三剑客”,它们是awk,sed,grep。熟练使用这三个工具可以提升运维效率。这章内容重点讲解sed 和awk 的功能。
一、文本三剑客之sed
1.1 sed 介绍
sed 即 Stream EDitor,是行编辑器
Sed是从文件或管道中读取一行,处理一行,输出一行;再读取一行,再处理一行,再输出一行,直到最后一行。每当处理一行时,把当前处理的行存储在临时缓冲区中,称为模式空间(PatternSpace),接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接着处理下一行,这样不断重复,直到文件末尾。一次处理一行的设计模式使得sed性能很高,sed在读取大文件时不会出现卡顿的现象。如果使用vi命令打开几十M上百M的文件,明显会出现有卡顿的现象,这是因为vi命令打开文件是一次性将文件加载到内存,然后再打开。Sed就避免了这种情况,一行一行的处理,打开速度非常快,执行速度也很快
sed(Stream EDitor)是一个强大而简单的文本解析转换工具,可以读取文本,并根据指定的条件对文本内容进行编辑(删除、替换、添加、移动等),最后输出所有行或者仅输出处理的某些行。sed 也可以在无交互的情况下实现相当复杂的文本处理操作,被广泛应用于 Shell 脚本中,用以完成各种自动化处理任务。
1.2 sed 工作流程
sed 的工作流程主要包括读取、执行和显示三个过程。
读取:sed 从输入流(文件、管道、标准输入)中读取一行内容并存储到临时的缓冲区中(又称模式空间,pattern space)。
执行:默认情况下,所有的 sed 命令都在模式空间中顺序地执行,除非指定了行的地址,否则 sed 命令将会在所有的行上依次执行。
显示:发送修改后的内容到输出流。在发送数据后,模式空间将会被清空。
在所有的文件内容都被处理完成之前,上述过程将重复执行,直至所有内容被处理完。
注意:默认情况下所有的sed命令都是在模式空间内执行的,因此输入的文件并不会发生任何变化,除非是用重定向存储输出。
1.3 sed 工作原理
工作原理:
读入新的一行内容到缓存空间;
从指定的操作指令中取出第一条指令,判断是否匹配pattern;
如果不匹配,则忽略后读的编辑命令,回到第2步继续取出下一条指令;
如果匹配,则针对缓存的行执行后续的编辑命令;完成后,回到第2步继续取出下一条指令;
当所有指令都应用之后,输出缓存行的内容;回到第1步继续读入下一行内容;
当所有行都处理完之后,结束;
1.4 sed命令常见用法
通常情况下调用sed命令有两种格式,如下所示。
其中,"参数"是指操作的目标文件,当存在多个操作对象时用,文件之间用逗号" ,"分隔;而 scriptfile表示脚本文件,需要用"-f"选项指定,当脚本文件出现在目标文件之前时,表示通过指定的脚本文件来处理输入的目标文件。
1.4.1 语法结构
sed [选项] '操作' 参数
sed [选项] -f scriptfile 参数
1.4.2 常见的选项
选项 | 作用 |
-e或 --expression= | 表示用指定命令或者脚本来处理输入的文本文件 |
-f 或 --file= | 表示用指定的脚本文件来处理输入的文本文件 |
-h 或 --help | 显示帮助 |
-n、--quiet 或 silent | 表示仅显示处理后的结果 |
-i.bak | 直接编辑文本文件 |
-r,-E | 使用扩展正则表达式 |
-s | 将多个文件视为独立文件,而不是单个连续的长文件流 |
1.4.3 常见的操作
"操作"用于指定对文件操作的动作行为,也就是sed的命令。通常情况下是采用的"[n1 [,n2] ]"操作参数的格式。n1、n2是可选的,代表选择进行操作的行数,如操作需要在5~20行之间进行,则表示为"5,20动作行为”。
参数 | 作用 |
a | 增加,在当前行下面增加一行指定内容 |
c | 替换,将选定行替换为指定内容 |
d | 删除,删除选定的行 |
i | 插入,在选定行上面插入一行指定内容 |
p | 打印,如果同时指定行,表示打印指定行;如果不指定行,则表示打印所有内容;如果有非打印字符,则以ASCII 码输出。其通常与"一n"选项一起使用 |
s | 替换,替换指定字符 |
y | 字符转换 |
1.5 sed用法示例
1.5.1 输出符合条件的文本(p 表示正常输出)
输出所有内容,等同于cat test.txt
输出3~5行
输出所有奇数行,n 表示读入下一行资料
输出所有偶数行,n 表示读入下一行资料
输出第 1~5 行之间的奇数行(第 1、3、5 行)
直接显示第二行内容
输出第 10 行至文件尾之间的偶数行
以上是 sed 命令的基本用法,sed 命令结合正则表达式时,格式略有不同,正则表达式以“/”包围。例如,以下操作是 sed 命令与正则表达式结合使用的示例。
输出包含the 的行
输出从第 4 行至第一个包含 the 的行
输出包含the 的行所在的行号,等号(=)用来输出行号
输出以数字结尾的行
输出包含单词wood 的行,\<、\>代表单词边界
1.5.2 删除符合条件的文本(d)
下面命令中 nl 命令用于计算文件的行数,结合该命令可以更加直观地查看到命令执行的结果。
删除第 3 行
删除第 3~5 行
删除包含 cross 的行,原本的第 9 行被删除;
如果要删除不包含 cross 的行,用!符号表示取反操作, 如'/cross/!d'
删除以小写字母开头的行
删除以"."结尾的行
删除所有空行
注 意 : 若 是 删 除 重 复 的 空行 , 即 连 续 的 空 行 只 保 留 一 个 , “cat -s test.txt”。
1.5.3 替换符合条件的文本
在使用 sed 命令进行替换操作时需要用到 s(字符串替换)、c(整行/整块替换)、y(字符转换)命令选项,常见的用法如下所示。
将每行中的第一个the 替换为 THE
将每行中的第 2 个 l 替换为 L
将文件中的所有o 删除(替换为空串)
在每行行首插入#号
在每行行尾插入字符串EOF
将包含the 的所有行中的 o 都替换为 O
插入符合条件的行使用-i 表示在行的前面插入一个新行
使用-i.bak 可以使要编辑的文本进行备份
1.5.4 迁移符合条件的文本
在使用 sed 命令迁移符合条件的文本时,常用到以下参数.
H:复制到剪贴板;
g、G:将剪贴板中的数据覆盖/追加至指定行;
w:保存为文件;
r:读取指定文件;
a:追加指定内容。具体操作方法如下所示。
I,i : 忽略大小写
案例:
将包含the 的行迁移至文件末尾, {;}用于多个操作
将第 1~5 行内容转移至第 7 行后
将包含the 的行另存为文件 out.txt
将文件/etc/hostname 的内容添加到包含 the 的每行以后
在第 3 行后插入一个新行,内容为New
在第 3 行后插入多行内容,中间的\n 表示换行
在包含the 的每行后插入一个新行,内容为 New
1.5.5 使用脚本编辑文件
使用 sed 脚本将多个编辑指令存放到文件中(每行一条编辑指令),通过“-f”选项来调用。
例如执行以下命令即可将第 1~5 行内容转移至第 16 行后。
方法一:sed 命令 sed '1,5{H;d};16G' test.txt //将第 1~5 行内容转移至第 16 行后
方法二:脚本方法:将多个编辑指令存放到文件中(每行一条编辑指令),通过“-f”选项来调用
1.5.6 分组操作
当我们需要对一行数据进行多次操作的时候我们可以使用{}进行分组
当我们运行多个命令时也可以使用选项 -e 来表示
注:-e 可以将多个命令连接起来,也可以将多个编辑命令保存到文件中,通过 -f 指定文件,以完成多个处理操作。
1.5.7 直接修改文件内容 【 i 】
在每一行的开头插入#号,直接修改原文件
将每一行的开头#号删除,直接修改原文件
编写一个脚本,用来调整vsftpd 服务配置,要求禁止匿名用户,但允许本地用户(也允许写入)。
二、awk
在 Linux/UNIX 系统中,awk 是一个功能强大的编辑工具,逐行读取输入文本,并根据指定的匹配模式进行查找,对符合条件的内容进行格式化输出或者过滤处理,可以在无交互的情况下实现相当复杂的文本操作,被广泛应用于 Shell 脚本,完成各种自动化配置任务。
20世纪70年代诞生于贝尔实验室,现在centos7用的是gawk,之所以叫AWK 是因为其取了三位创始人 Alfred Aho, Peter Weinberger 和 Brian Kernighan 的 family name 的首字符。
2.1 awk常见用法
通常情况下 awk 所使用的命令格式如下所示,其中,单引号加上大括号“{}”用于设置对数据进行的
处理动作。awk 可以直接处理目标文件,也可以通过“-f”读取脚本对目标文件进行处理。
格式:
awk 选项 '模式或条件 {编辑指令}' 文件 1 文件 2 „ //过滤并输出文件符条件的内容
awk -f 脚本文件 文件 1 文件 2 „ //从脚本中调用编辑指令,过滤并输出内容
前面提到 sed 命令常用于一整行的处理,而 awk 比较倾向于将一行分成多个“字段”然后再进行处理,且默认情况下字段的分隔符为空格或者 tab 键。awk 执行结果可以通过 print 的功能将字段数据打印显示。
在使用 awk 命令的过程中,可以使用逻辑操作符“&&”,表示“与”, “||”表示“或”,“!”表示“非”;还可以进行简单的数学运算,如+、-、*、/、%、^分别 表示加、减、乘、除、取余和乘方。
awk 从输入文件或者标准输入中读入信息,与 sed 一样,信息的读入也是逐行读取的。
不同的是 awk 将文本文件中的一行视为一个记录,而将一行中的某一部分(列)作为记录中的一个字段(域)
为了操作这些不同的字段,awk 借用 shell 中类似于位置变量的方法, 用**$1、$2、$3„顺序地表示行(记录)中的不同字段**。另外 awk 用$0 表示整个行(记录)
不同的字段之间是通过指定的字符分隔
awk 默认的分隔符是空格
awk 允许在命令行中用“-F 分隔符”的形式来指定分隔符
2.2 工作原理
逐行读取文本,默认以空格为分隔符进行分隔,将分隔所得的各个字段保存到内建变量中,并按模
式或着条件执行编辑命令。
awk 命令对/etc/passwd 文件的处理过程图:
2.3 awk 内置变量
awk 包含几个特殊的内建变量(可直接用):
变量 | 解释 |
FS | 指定每行文本的字段分隔符,默认为空格或制表位(tab) |
NF | 当前处理的行的字段个数 |
NR | 当前处理的行的行号(序数) |
$0 | 当前处理的行的整行内容 |
$n | 当前处理行的第 n 个字段(第 n 列) |
FILENAME | 被处理的文件名 |
RS | 数据记录分隔,默认为\n,即每行为一条记录(\n表示回车) |
2.4 用法示例
2.4.1 awk 基本用法
输出所有内容
或者 awk '{print $0}' shuiguo.txt //输出所有内容,等同于 cat shuiguo.txt
以冒号作为分割符,显示出第五列的内容
注:awk默认把这一行当做一列,因为没有被空格分隔,awk默认以空格或tab键分隔
打印出第1和第3列
注:显示一个空格,空格需要用双引号引起来,如果不用引号默认以变量看待,如果是常量就需要双引号引起来
用制表符作为分隔符输出
定义多个分隔符,只要看到其中一个都算作分隔符
2.4.2 awk常用内置变量
$1:代表第一列
$2:代表第二列以此类推
$0:代表整行
NF:一行的列数
NR:行数
打印包含root的整行内容
打印包含root的行的第一列和第六列
打印每一行的列数
显示行号 使用NR参数
显示出每行的行号和内容
打印第二行
打印第二行的第一列
打印最后一列
打印总行数 END 表示汇总的意思
打印文件最后一行
显示出文件第几行有几列
2.4.3 通过管道、双引号调用 Shell 命令
操作命令放在{}中
管道符号前面的命令输出的内容交给管道符号后面的命令处理
结合正则表达式,正则表达式同样要被/包围
调用的shell命令需要用""引起来
{}中多个命令之间也能过;分隔
调用wc -l 命令统计使用bash的用户个数(双引号之间直接调命令"wc -l")等同于 grep -c “bash$” /etc/passwd
统计以冒号分隔的文本段落数,END{ }语句块中,往往会放入打印结果等语句
查看当前内存使用百分比
网卡的ip、流量
2.4.4 BEGIN、END
逐行执行开始之前执行什么任务,结束之后再执行什么任务
BEGIN一般用来做初始化操作,仅在读取数据记录之前执行一次
END一般用来做汇总操作,仅在读取完数据记录之后执行一次
如果不用引号awk就当作一个变量来输出了,所以不需要加$了
注:BEGIN在处理文件之前,所以后面不跟文件名也不影响
BEGIN亦可以进行运算
先写’BEGIN{x=0}; ;END{print x}’ ,然后再写中间的匹配// 以/bin/bash结尾 ,因为/有其他匹配的意思,要加转义符号\ ,最后再加{x++},转到下一行
扩展:
BEGIN语句块在awk开始从输入流中读取行之前被运行,这是一个可选的语句块,比方变量初始化、打印输出表格的表头等语句通常能够写在BEGIN语句块中。
END语句块在awk从输入流中读取全然部的行之后即被运行。比方打印全部行的分析结果这类信息汇总都是在END语句块中完毕,它也是一个可选语句块。
pattern语句块中的通用命令是最重要的部分,它也是可选的。假设没有提供pattern语句块,则默认运行{ print },即打印每个读取到的行。awk读取的每一行都会运行该语句块。
这三个部分缺少任何一部分都可以
2.4.5 模糊匹配
用~表示包含,!~表示不包含
模糊匹配,只要有ro就匹配上
匹配结尾不是nologin的行可以使用 ! 取反操作
2.4.6 关于数值与字符串的比较
比较符号:== != <= >= < >
打印出第五行的内容
进行精确匹配 一定是root
打印出行号小于5的行
打印出第3列大于等于1000的行,以冒号作为分隔符
逻辑运算 &&(表示且) || (表示或)
打印出第3列小于10或大于1000的行
打印出行号4到9的行
打印1-200之间所有能被7整除并且包含数字7的整数数字
2.4.7 其他内置变量的用法
FS、OFS、NR、FNR、RS、ORS
FS:输入字段的分隔符 默认是空格
OFS:输出字段的分隔符 默认也是空格
NR : 当前处理行的行号,从1开始
FNR:读取文件的记录数(行号),从1开始,新的文件重新重1开始计数
RS:输入行分隔符 默认为换行符
ORS:输出行分隔符 默认也是为换行符
在打印之前定义字段分隔符为冒号
OFS定义了输出时以什么分隔,$1$2中间要用逗号分隔,因为逗号默认被映射为OFS变量,而这个变量默认是空格
使用FNR的行号可以在追加当有多个文件时,分别列出每个文件的行号数,新的文件都是从1开始的,而NR是列出的行号数是从1开始,不会分别列出各个文件
RS:指定以什么为换行符,这里指定是冒号,你指定的肯定是原文里存在的字符
把多行合并成一行输出,输出的时候自定义以空格分隔每行,本来默认的是回车键
2.4.8 调用函数getline
定义引用变量
awk直接定义变量并引用
调用函数getline,读取一行数据的时候并不是得到当前行而是当前行的下一行
显示奇偶数行
2.4.9 awk的 if语句
awk的if语句也分为单分支、双分支和多分支
单分支为if(){}
双分支为if(){}else{}
多分支为if(){}else if(){}else{}
第三列小于10的打印整行
第三列小于10的打印第三列,否则打印第一列
2.4.10 awk 也可用于for,while,数组
写一个while 循环,来测定行数,去除上面地9行内容,得到分区数
案例:$1=$1是用来激活$0的重新赋值,也就是说字段$1...和字段数NF的改变会促使awk重新计算$0的值,通常是在改变OFS后而需要输出$0时这样做
案例:数组
awk 'BEGIN{a[0]=10;a[1]=20;print a[1]}'
awk 'BEGIN{a[0]=10;a[1]=20;print a[0]}'
awk 'BEGIN{a["abc"]=10;a["xyz"]=20;print a["abc"]}'
awk 'BEGIN{a["abc"]=10;a["xyz"]=20;print a["xyz"]}'
awk 'BEGIN{a["abc"]="aabbcc";a["xyz"]="xxyyzz";print a["xyz"]}'
awk 'BEGIN{a[0]=10;a[1]=20;a[2]=30;for(i in a){print i,a[i]}}'
三、总结
1. sed工具除了调用文件或脚本执行命令,否则命令都需要加上' ' 符号
即:调用 sed 命令有两种格式
sed[选项] '操作' 参数
sed [选项] -f scriptfile 参数
其中,“参数”是指操作的目标文件,当存在多个操作对象时用,文件之间用逗号“,”分隔;
而 scriptfile 表示脚本文件,需要用“-f”选项指定,当脚本文件出现在目标文件之前时,表示通过指定的脚本文件来处理输入的目标文件
-n选项在符合条件输出和结合正则表达式的时候使用
{}用于奇数行和偶数行的筛选或者奇数行和偶数号的其他操作
sed 命令结合正则表达式时,格式略有不同,正则表达式以“/”包围
使用sed删除命令时,nl 命令用于计算文件的行数,结合该命令可以更加直观地查看到命令执行的结果,而不使用-n
2. sed操作指令置于’'中,awk比sed多一个{}
sed[选项] '操作' 参数
awk 选项 '模式或条件 {编辑指令}' 文件 1 文件 2
w,who,whoami,who am i
w 显示已经登录的用户及正在进行的操作
who 显示已经登录的用户名、终端名称、登录时间及登录IP
whoami 显示当前用户的用户名
who am i 显示登录系统的时候的用户名,即使已经切换到其他用户也显示登录时的用户
一般输出关于段,列的信息使用awk,其他的使用sed或grep更加方便
awk 输出的奇偶行都使用绝对路径
sed 输出的奇偶行都使用相对路径
使用awk调用shell命令,统计数量时,n是个变量,可自定义
若没有定义n的初始值,则n=0
awk判断条件中双引号之间的内容,如果有特殊符号不需要使用转义符
FS在{}中间使用,F在{}外面使用