sed和awk
准备:
一台Rocky Linux9 的虚拟机
sed
sed是一款流编辑工具,用来对文本进行过滤,编辑操作,用于需要对几十个配置文件统一修改。sed一次只读取一行内容,对内容执行某些指令进行处理,然后输出,更适合大数据文件。
sed首先读取文件内容,将读入内容复制到缓冲区(模式空间pattern space),所有指令都是在缓冲区进行,sed根据指令修改后输出结果,默认输出到标准输出
sed基本语法
sed 【选项】 ... {脚本指令} [输入文件] ...
选项:
--version 显示sed版本
--help 显示帮助文档
-n, --quite, --slient 静默输出,默认情况下,sed执行完毕后将自动打印模式空间的内容,这个选项屏蔽自动打印
-e script 允许多个脚本指令被执行
-f script-file 从文件中读取脚本指令
-i, --in-place 直接修改源文件
-r 在脚本指令中使用正则
-s 默认情况下,sed将输入的多个文件名作为一个长的,连续的输入流,而GNU sed 允许把他们作为单独的文件
基本格式规范:
脚本指令常用:a 追加 i 插入 d 删除 s替换
脚本指令基本格式: 【地址】指令
指令可用花括号进行组合,组合后用于同一个地址:
address{
command1
command2
command3
}
eg:从etc下将passwd文件复制到root目录下
bash
cp /etc/passwd .
cat passwd

在第二行后面追加一个test1
bash
sed '2a test1' passwd

在第三行前追加test2,因为这些操作都是在缓冲中操作的,所有读取源文件会发现没有任何修改
bash
sed '3i test2' passwd
cat passwd


将文件中所有bin修改为bash
bash
sed 's/bin/bash/g' passwd # 结尾添加g为所有全部更改,不加只会修改每一行第一个匹配成功的

删除文件中第2,3,4行(第2到4行)内容
bash
sed '2,4d' passwd

综合使用:
在第二行后添加test1,第五行前添加test2,将所有的bin替换为bash,删除7,8行
bash
sed '{
2a test1
5i test2
s/bin/bash/g
7,8d
}' passwd

也可以单独指定一行使用,如指定修改第三行的daemon为zhangsan,所有的2为45
bash
sed 3'{
s/daemon/zhangsan/g
s/2/45/g
}' passwd

sed正则匹配
因为实际使用中,更多的时候,我们并不知道所需要修改的内容所在行号的,所以需要使用正则匹配区匹配内容然后修改
格式:
sed '/正则/指令' 文件
eg:
在adm下一行添加test3
bash
sed '/^adm/a test3' passwd

修改games行所有的0为?号
bash
sed '/games/s/0/?/g' passwd

sed地址匹配
1、在sed中通过 开始行~步长 的方式来指定步长操作
eg:从第一行开始每2行后面添加一行test
bash
sed '1~2a test' passwd

2、\cregexpc 在\c与c之间进行正则表达式匹配,c字符可以用任意字符代替,但是注意只能为单个字符
eg:
将mail行的8替换为20
bash
sed '\cmailcs/8/20/' passwd

3、addr1,addr2 匹配地址1到地址2之间的所有行
eg:将第3行到第6行之间的所有bin替换为bash
bash
sed '3,6s/bin/bash/' passwd

4、addr1,+N 匹配操作地址1及后面的N行内容
eg: 将第4行和后面的3行中的bin换为bash
bash
sed '4,+3s/bin/bash/' passwd

sed指令与脚本
sed常用指令
| 指令 | 功能 | 指令 | 功能 |
|---|---|---|---|
| s | 替换 | d | 删除 |
| a | 追加 | i | 插入 |
| c | 更改 | l | 打印,可以显示非打印字符 |
| y | 按字符转换 | = | 打印当前行 |
| p | 打印 | r | 读入文件内容 |
| w | 保存至文件 | q | 立刻推出sed脚本 |
sed脚本
sed脚本也是sh脚本,需要使用sed -f 参数去运行
格式: sed -f 脚本文件 需要修改的文件
eg:
1、编写一个html文件,将其中错误的body换为/body
bash
echo '''
<html>
<title> First Web </title>
<body> This is a html file <body>
</html> ''' > index.html

编写sed脚本,这里第一个是正则匹配包含body的那行,s//第一个空则为修改前面正则匹配的内容,第二个/body \为注释掉后面的/,使其识别为/而不是sed替换里面的/
bash
echo '/body/{s//\/body/2}' > sed.sh

使用sed运行sed脚本
bash
sed -f sed.sh index.html

当然,也可以用其他符号来替代/,只要是有3个就行,哪怕是数字,字母,下面就是用a来替换/的作用

2、修改index.html如下,将其中h1h2h3 第一个加上<>变为<h1><h2> <h3>第二个h1h2h3变为</h1></h2><h3>

编写sed脚本,在这里面用&来替代h[1-3],因为是加上<>符号,所以需要添加转译
bash
/h[1-3]/{
s//\<&\>/1
s//\<\/&\>/2
}

执行sed脚本

3、从/etc/NetworkManager/system-connections下将ens160.nmconnection文件复制到/root下,把包含id=ens160修改为id=eth0
bash
cp /etc/NetworkManager/system-connections/ens160.nmconnection /root

使用sed,命令
bash
sed '/^id/c id=eth0' ens160.nmconnection

4、将上面的文件的小写全部修改为大写
编写sed脚本,/y是将后面第一个的所有字符用第二个替换
bash
vim sed.sh
/.*/{
//y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/
}

如果需要单独换某行:
bash
/.*/{
/autoconnect/y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/
}

5、先读取ens160文件,再读取index.html文件
符号表示在文件最后一行读完后开始读index.html文件。如果不添加符号,会每读一句ens160文件中的内容都输出一遍index.html内容
bash
sed '$r index.html' ens160.nmconnection

不加$示例
编写sed脚本,读取1到4行,每一行读完后都读一遍index.html
bash
/.*/{
5,$d
r index.html
}

sed高级应用
多行读取Next(N)
Next(N)指令通过读取新的输入行,将其追加至模式空间的现有内容之后,来创建多行模式空间,其中的换行符直接显示为\n,一个N往下多读一行,两个N多读两行
eg:有一个简易的user_info文件:

这个文件需要将Name和Mail同行显示
使用sed命令,这个命令表示,通过匹配文件中的Name字符,当匹配成功时读取当前行和下一行,换行符用\n替代:
bash
sed -n '/Name/{N;l}' user_info

多行打印Print(P)
多行打印Print(P)仅输出多行模式空间中的第一部分,直到\n为止

N;l会读取两行作为一行,但因为l会将输出的不显示的字符正常显示,所以会输出读取到的内容,读取到的\n作为字符显示
N;P会将N读取到的内容交由P处理,N读完两行后换行地方有\n结尾有$,P读取到\n就结束了,所以只会输出\n前面的内容
N;p会正常的将N读出的内容输出,其中\n作为换行符正常生效
多行删除Delete(D)
d为删除指令,作用为删除模式空间中的内容并读入新的输入行,如果在d后面有多条指令,则剩下的指令不会执行,而是返回第一条指令对新读入的内容进行处理,多行删除指令D将删除模式空间中的第一个插入的换行符\n前面的内容,不会读入新的输入行,并返回sed脚本的顶端,使剩余的指令可以继续作用于模式空间的其他内容
Hold(h,H)、Get(g,G)
除了模式空间外,还有保持空间(hold space),两者可以互相复制数据,Hold和Get用于两者之间移动数据
Hold(h|H)将模式空间中的内容复制或追加到保持空间
Get(g|G)将保持空间中的内容复制或追加到模式空间
Exchange(x) 交换保持空间和模式空间的内容
eg:如下的文件test.txt

编写sed脚本,将aaa行放入保持空间,然后删除aaa行,在ccc行后面将aaa行取出:
bash
/aaa/{
h
d
}
/ccc/{
G
}

AWK
Awk是一种编程语言,用于在Linux/Unix下的对文本和数据进行扫描和处理,数据可以来自标准输入,文件、管道。分为gawk和mawk,其中RedHat使用gawk,Ubuntu使用mawk
AWK工作流程
逐行扫描文件,从第一行到最后一行,寻找匹配特定模式的行,并在这些行上进行用户想要的操作,Awk基本结构由模式匹配和处理过程
awk读取文件内容的每一行时,将对比该行是否与给定的模式相匹配,匹配则执行处理过程,否则不对该行做任何处理。若没有处理过程,则显示匹配的行(默认处理为print),若没有匹配模式,则默认所有数据
awk两个特殊的模式:BEGIN和END,他们分别在没有读取任何数据之前和所有数据读取完毕后执行
AWK语法基本格式
gawk [选项] -f program-file [--] file ...
选项:
-F fs 指定以fs作为输入行的分隔符(默认为空格或制表符)
-v var=val,--assign var=val,在执行处理过程前设置一个变量var值为val
-f program-file,--file program-file,从脚本文件中读取awk指令,以取代命令参数中输入处理脚本
-W compat,-W traditional,--compat, --traditional 使用兼容模式运行AWk,GNU扩展选项将会被忽略
-W copyleft,-W copyright,--copyleft,--copyright,输出简短的GNU版权信息
-W dump-variables[=file], --dump-variables[--file]打印全局变量(变量名,类型,值)到文件中,如果没有提供文件名,则自动输出至名为dump-variables的文件中
-W help,-W usage, --help, --usage 显示各个选项的简短描述
AWK语法结构:一个AWK程序包含一系列模式(动作指令)或函数定义,模式可以是BEGIN,END,表达式,用来限定操作对象的多个表达式用逗号分隔,动作指令用{}包裹
eg:
1、通过正则表达式匹配空白行,然后打印Blank Line ,每有一个空白行,打印
一个Blank Line
使用ens160文件
bash
awk '/^$/ { print "Blank Line" }' ens160.nmconnection

使用awk脚本执行
bash
# awk.sh文件内容
/^$/ {print "Blank Line"}
# 命令行
awk -f awk.sh ens160-nmconnection

2、打印包含系统名的行
bash
awk '/PRETTY_NAME/' /etc/os-release

AWK操作指令
1、记录与字段
awk一次从文件读取一条记录,并将记录存储在字段变量0中,记录被分割为字段并存储在1,2,... , NF中(默认空格或制表符分割),内建变量NF记录字段个数
eg:

2、字段分隔符
默认情况用空格或制表符来分隔字段,但可以用-F 来自定义分隔符
eg:
查看passwd文件,里面是使用:作为分隔符的



3、内置变量
| 变量名 | 描述 |
|---|---|
| ARGC | 命令行参数个数 |
| FILENAME | 当前输入文件名称 |
| FNR | 当前输入文件的行记录编号,尤其是多个输入文件时有用 |
| NR | 输入流的当前行记录编号 |
| NF | 当前记录中的字段个数 |
| FS | 分隔字符号 |
| OFS | 输出字段分隔符,默认空格 |
| ORS | 输出记录分隔符,默认换行符\n |
| RS | 输入记录分隔符,默认换行符\n |
4、表达式与操作符
表达式由变量、常量、函数、正则表达式、操作符组成,Awk中的变量有字符变量和数字变量。如果Awk中变量未初始化,则初始值为0或空,对字符进行操作时一定要加引号
操作符:
| 操作符 | 作用 | 操作符 | 作用 |
|---|---|---|---|
| + | 加 | /= | 相除后赋值给变量 |
| - | 减 | > | 大于 |
| * | 乘 | < | 小于 |
| / | 除 | >= | 大于等于 |
| % | 取余 | <= | 小于等于 |
| ^ | 幂运算 | == | 等于 |
| ++ | 自加1 | != | 不等于 |
| -- | 自减1 | ~ | 匹配 |
| += | 相加后赋值给变量 | !~ | 不匹配 |
| -= | 相减后赋值给变量 | && | 与 |
| *= | 相乘后赋值给变量 | || | 或 |
eg:






高级用法
if条件判断
语法格式1:
if (表达式)
动作1
else
动作2
语法格式2:
if (表达式)动作1;else 动作2
eg:
编写awk.sh输出第三个字段大于60的项
bash
{
if ($3 > 60)
print $0
}
awk -F: -f awk.sh passwd


2、while循环
语法格式1:
while (条件)
动作
语法格式2:
do
动作
while (条件)
eg:


3、for循环
for 语法格式:类似于C语言的for循环
for (变量;条件;计数器)
动作
eg:

4、Break和Continue
break跳出循环,终止接下来所有循环
continue跳出当前循环,终止当前循环所有动作,开始下一次循环
eg:

5、函数
(1)rand()产生0-1宅男的浮点类型随机数,但需要通过srand()设置参数,否则每次产生的数都一样,srand可以自己添加随机种子,默认是当前时间作为随机种子,所以如果太快的话输出也是一样的



(2)gsub(x,y,z)
在字符串z中使用字符串y替换与正则表达式x项匹配的所有字符串,z默认$0

(3)sub(x,y,z)
在字符串z中使用字符串y替换与正则表达式x项匹配的第一个字符串,z默认$0

(4)length(z)
计算并返回字符串z的值

(5)getline
从输入中读取下一行内容
