sed与awk-第五章-基本sed命令
第五章 基本 sed 命令
sed 命令的语法
sed通用语法:
- 大部分命令:可以接受0个、1个、2个地址(行号/正则模式),支持行范围
|
|
- 少数命令只接受单个行地址,不能用于行范围
|
|
命令分组大括号 { }
对同一个地址,执行多条命令;支持多层嵌套分组。
规则:
- 左大括号
{放在地址行末尾; - 右大括号
}必须独占一整行; - 大括号内部命令行开头可以加空格、制表符做缩进;
- 大括号内每一条命令还可以自带自己的地址,可以多层嵌套。
|
|
同一行写多条命令(分号;)
不推荐日常写脚本,可读性差。
|
|
坑:n ; d n后面加空格会报语法错误;d前面允许空格。
注意:
a i c(追加、插入、更改)不能用分号放同一行,必须多行书写。
注释
sed脚本注释行以 # 开头。
- System V sed限制:注释只能写在脚本第一行;GNU sed可以脚本任意位置写注释。本书示例遵循兼容写法,注释放第一行。
|
|
- 特殊:脚本文件开头
#n>
如果
#后面紧跟字符n(必须是文件前两个字符),等价于命令行参数-n,关闭sed默认输出,后面内容依旧作为注释。
|
|
替换
替换命令完整语法
|
|
flags标志
| 标志 | 作用 |
|---|---|
| 数字n | 只替换一行中第n次匹配,n取值1‑512;默认1(只替换第一次) |
| g | 全局,一行内全部匹配项都替换 |
| p | 替换成功后,打印模式空间内容;只有替换成功才打印 |
| w file | 替换成功后,把模式空间写入指定文件file;替换成功才写文件 |
重点:
p、w标志和独立p/w命令区别:标志只在替换成功才执行动作;独立p命令无条件执行。多个替换作用同一行,带p标志会多次打印该行。
替换分隔符可以自定义
默认用/做分隔符;如果模式里面大量出现斜杠/,可以换成别的字符(! #等,不能换行)。
规则:分隔符一共出现3处;如果分隔符本身出现在模式/替换文本中,需要
\转义。
replacement(替换部分)特殊元字符
注意:正则元字符(
. * [])在替换域失去特殊含义;只有下面3类符号在替换域有特殊作用。
&代表整个正则匹配到的全部内容\1 \2 … \9回调正则中\( \)捕获的分组子串,最多9组\反斜杠:转义&、分隔符、反斜杠本身;还可以转义换行,实现多行替换文本。
示例:
数字n标志示例
把一行中第二个制表符替换成
>
|
|
·代表制表符tab。
替换元字符
替换部分(s/xxx/这里是替换字符串/g):这一块不是正则!绝大多数正则元字符在这里失效,只有少数几个符号还有特殊魔力,这少数几个就叫 替换元字符。
| 替换元字符 | 作用 |
|---|---|
& |
代表:正则匹配到的完整全部内容 |
\1 \2 …\9 |
捕获分组回调,取\( \)括号里捕获到的子内容 |
\ 反斜杠 |
转义:转义 &、反斜杠本身、分隔符;还可以换行实现多行替换 |
1. & 使用示例
输入:on the UNIX Operating System.
|
|
拆解例子:
正则部分:UNIX
简单字面匹配,找到单词 UNIX。
这里正则匹配到的完整内容就是字符串:
UNIX
替换文本:\\s-2&\\s0
这里面 & 就是替换元字符,& = 刚刚匹配到的 UNIX
所以替换字符串 \\s-2&\\s0 展开:
\\s-2→\s-2&→UNIX\\s0→\s0
拼接在一起输出:\s-2UNIX\s0
这不是 sed 语法!是 troff 排版语言的命令。
\s-2:把后面的字体缩小 2 号\s0:恢复原来字号
输出:on the \s‑2UNIX\s0 Operating System.
2. 捕获分组 \( \) 和回调 \1 \2
正则中用\(内容\)捕获片段;替换域用\1、\2取出对应片段。
示例:交叉引用,把See Section 1.4变成粗体
|
|
\1:See Section\2:版本号1.4
交换冒号前后两段文本:
|
|
输入first:second →输出second:first
3. 替换域中转义&符号
如果想输出字面&,必须写\&
|
|
校正索引条目
业务场景:troff索引宏.XX "xxx",只修改.XX开头的索引行,不要改动正文。
示例:只修改索引行内单词,地址限制行范围
|
|
进阶shell脚本
index.edit:批量提取索引条目,自动生成sed替换脚本。 核心思路:grep提取所有.XX行,交给sed动态拼接生成sed替换命令,输出保存成脚本文件,再批量修改源文件。 坑:如果索引条目包含* .等正则元字符,脚本不会自动转义,会出错,高级处理放在第六章。
删除 d 命令
语法:[address]d
- d删除整个模式空间的一行,不是只删除部分字符;只删部分字符要用替换、替换为空字符串。
- 执行d之后:清空模式空间,直接读取下一行输入,本脚本后续命令不再对本行执行(改变控制流)。
示例:
注意区分:大写
D是高级多行删除命令,第六章讲解。
追加a、插入i、更改c
三者语法特殊,必须多行书写,不能用分号压缩到一行。
| 命令 | 语法 | 行为 | 地址限制 |
|---|---|---|---|
| i 插入 | [line‑address]i\ 文本内容 |
输出到当前行的前面 | 只能单个行地址,不能行范围 |
| a 追加 | [line‑address]a\ 文本内容 |
输出到当前行的后面 | 只能单个行地址,不能行范围 |
| c 更改 | [address]c\ 文本内容 |
清除模式空间,用新文本替换原行内容 | 支持行范围 |
语法硬性规则:
- 命令后面写反斜杠
\,然后换行;真正文本写在下一行; - 多行文本:除最后一行外,每一行末尾都加
\; - a/i输出的新增文本不会进入模式空间,后续sed命令不会处理新增出来的文本。
i 插入示例
匹配.Ls行,行前面插入两行troff指令
a追加示例
匹配.Le行,行后面追加两行
c更改示例
行范围:把从
^From到第一个空行之间全部多行,替换成一行<Mail Header Removed>。
坑:如果c写在大括号内部,对范围中每一行都会输出替换文本,会重复输出多次。
c命令执行后清空模式空间,本行后续脚本命令不会执行。
列表 l 命令
语法:[address]l
l,就是sed 的 list 命令(字母小写 L)
命令
l(list):打印模式空间内容;看不见的控制字符会转成八进制转义输出,用来排查看不见的隐藏字符(\r回车、^A、^M退格等)。 一般搭配‑n使用,否则一行输出两遍。
示例:
|
|
拆解整条命令:
sed:程序-n:命令行选项,关闭默认输出-e "l":‑e代表:后面引号里面内容是 sed 脚本片段"l"引号内部:l,就是sed 的 list 命令(字母小写 L)
test/spchar:输入文件名
作用:查看文本里面隐藏的^A ^M ^G等看不见的控制字符。
小技巧vi中输入特殊控制字符:
Ctrl‑V再按控制键。
案例:清除nroff输出的退格格式
nroff为实现粗体,生成类似N^HN^H序列。
可以清除man手册输出里粗体、下划线特殊格式。
转换 y 命令
语法:[address]y/源字符集/目标字符集/
按字符位置一一对应转换,不是正则匹配! 源字符第1个→目标第1个;源第2个→目标第2个。没有元字符概念。
示例全部小写转大写:
|
|
注意:y不能只转换单词,会处理整行全部字符;只转换部分内容,需要第六章保持空间hold space。
打印 p 命令
语法:[address]p
输出模式空间内容;不修改模式空间,不改变脚本流程。 不加
‑n的情况下,sed默认还要输出一遍,会造成重复打印。
区分:
s///p:替换成功才打印(替换标志)p独立命令:无条件打印模式空间。
调试示例:匹配.Ah行,打印原始行,替换后再打印。
打印行号 =
语法:[line‑address]=
只接受单个行地址,不能写行范围
1,3=,语法错误
=只会输出行号,不会输出那一行本身的文本
通常配合-n(或者脚本开头#n)抑制默认输出;想要同时看到行号 + 行内容,就再加p打印命令。
测试文件:
输出:
只打印匹配 if 的那些行:先输出行号,再输出源代码文本。
next n 命令
语法:[address]n
next命令流程:
- 输出当前模式空间内容;
- 读取下一行输入,覆盖替换模式空间;
- 脚本不从脚本开头重新跑,继续执行n后面的命令。
坑:n前面的命令作用旧行;n后面命令作用新读入的行。
示例:.H1标题行之后,如果紧跟着空行就删除这个空行
逻辑:匹配.H1,输出当前行,读入下一行;如果新行是空行,执行d删除。
普通是「脚本跑完才换内容」;
n是「脚本执行半路,强行换掉模式空间里面的内容」。
大写N是高级多行next,第六章。
测试文件:
脚本
一步步拆解执行
- sed 读取
AAA,放入模式空间
模式空间:
AAA
- 匹配
/^AAA/,进入大括号 s/AAA/AAA改/
模式空间现在变成:
AAA改
现在执行n命令,做两件事:
① 输出模式空间当前内容 → 打印AAA改
② 立刻读取文件的下一行BBB,把BBB写入模式空间
重点:模式空间原来存的
AAA改直接消失!被新读进来的BBB顶替掉,这就叫覆盖模式空间。
此时模式空间:
BBB,旧的AAA改已经不在缓冲区里面了,已经输出完事。
不会跳回脚本开头!继续运行 n 后面的命令:s/BBB/BBB改/
修改现在模式空间里面的
BBB→BBB改
大括号全部执行完毕,脚本这一轮结束,输出模式空间内容 →打印BBB改
进入主循环,读取下一行CCC放入模式空间,跑脚本,输出CCC
读 r、写 w 文件
r读文件:[line‑address]r filename
只接受单行地址;匹配行输出完成之后,把外部文件全部内容追加输出;读进来的文本不会进入模式空间,后续sed命令不能修改读入的内容。 文件不存在不会报错。
示例:文件最后一行后面插入closing文件全部内容
|
|
w写文件:[address]w filename
将当前模式空间的内容写入指定文件;匹配就写,不等脚本结束。 文件不存在则创建;多次写同一个文件,是追加内容。sed脚本最多同时打开10个文件。
示例:把按地区把人员分别写入4个文件
退出 q 命令
语法:[line‑address]q
只接受单行地址。一旦执行q:立刻终止整个sed程序,不再读取任何新输入行。
示例:输出文件前100行,读到100行直接退出,类似head。
|
|
性能优势:处理超大文件,找到目标就q退出,不用扫描全部剩余内容。
检查参考页
实战完整综合案例:把纯文本命令参考页,自动加上troff格式化宏。
设计思路:逐行分析输入文本,设计地址与命令;优先处理特殊情况;最后清理通用空行、制表符。 关键点:
c更改命令替换大块标签;大括号分组;范围地址;处理各种边界不一致输入。 完整脚本参考书中refsed,运行方式:sed -f refsed refpage输出到屏幕/重定向新文件,不修改原始文件。
本章核心速记卡片(复习)
- 语法:
[地址]命令;{}分组,}必须独占一行;a/i/c必须多行书写。 - 替换
s:可以自定义分隔符;替换域元字符只有& \1‑\9 \。 d删除整行;执行d直接读下一行,后续命令不再执行本行。i前插、a后追加:只能单行地址;c更改支持范围;a/i输出文本不进模式空间。l查看看不见的控制字符;y字符一一映射转换。p打印模式空间;=打印行号;n读取下一行,继续执行后续命令。r读取外部文件追加输出;w把模式空间写入文件。q找到行直接退出程序,适合大文件提升速度。- 注意区分:标志
p/w(替换成功才执行)和独立命令p/w(无条件执行)。
文章作者 会写代码的小郎中
上次更新 2011-08-04
许可协议 CC BY-NC-ND 4.0