W6-C2-0426

六周第二次课(4月26日)
9.4/9.5 sed

sed -rnieIpd

1. 简介

sed是一个非交互式的流编辑器.

  • 非交互式: 只能在命令行下通过编辑命令来编辑文本, 然后在屏幕上查看输出
  • 流编辑器: 逐行处理, 每次只从文件(或输入)中读入一行, 对该行进行指定处理, 并将结果输出到屏幕(除非取消了屏幕输出又没有使用打印命令), 接着读入下一行

2. 工作过程

sed有两个缓冲区

  • 模式空间 pattern space
    处理完一行之后就会把模式空间中的内容打印到标准输出,然后自动清空缓存
  • 暂存缓冲区 holding space
    不会自动清空,但也不会主动把此缓冲区中的内容打印到标准输出中。而是需要以下sed命令进行处理

sed不是在原输入上直接进行处理, 而是先将读入的行放到缓冲区中, 对缓冲区里的内容进行处理,处理完毕后也不会写回原文件(除非用shell的输出重定向来保存结果),而是直接输出到屏幕上.

一般情况下,每当运行sed,sed首先把第一行装入模式空间,进行处理后输出到屏幕,然后将第二行装入模式空间替换掉模式空间里原来的内容,然后进行处理,以此类推。

3. 选项

  • -r: 支持扩展正则表达式. 特殊符号需要脱义或加r选项
  • -n: quiet. 不指定操作指令时默认为打印p, sed会将所有输入行打印在标准输出上, 匹配到的行会额外打印一遍.
    -n是取消默认打印操作, 与p命令一起使用表示只打印发生替换的行.
  • -e: 多重编辑, 允许在同一行里执行多条命令, 命令顺序会影响结果. 可使用;代替
    示例: sed -n '1p;2p;4p' 1.txt
  • -f: 后跟文件路径. 从指定的文件中读取脚本并运行
  • -i: 直接修改源文件

4. 地址定界

  • 定界符: 默认是/, 可以换成其他字符如@|
  • #: 指定第#行
  • $: 末行
  • 2,5: 2-5行
  • 5,$: 5-末行
  • ^$: 空白行
  • /regexp/: 任何能被regexp所匹配到的行
  • #,/regexp/: 第#行到匹配regexp的行中间的所有行
  • /regexp1/,/regexp2/
  • #, +n: 从#行开始,一直到向下的n行
  • first~step: 指定起始行,以及步长

5. 编辑命令

  • p: 打印
  • I: 忽略大小写
  • d: 删除

5.1 示例

示例1: sed '1,100'd 123.txt
head test.txt | sed 's/[a-zA-Z]//g' 删除文档内所有英文字母[a-zA-Z]

示例2: 删除空白行: sed '/^$/d' file

示例3: 删除文件第2行: sed '2d' file

示例4: 删除文件最后一行: sed '$d' file

示例5: 删除每行前面的空格; sed 's/^[ ]*//' file

示例6: 删除文件中所有开头是test的行: sed '/^test/'d

示例7: sed '/west/,/east/s/$/VACA/' 11.txt
west 和 east 之间的所有行, 把行尾$替换成VACA, 换行符被移到新的字符串后面

  • s: 替换. s/regexp/replacement/

示例: 将passwd文件里的行第一段和最后一段调换.
head text.txt |sed -r 's/([^:]+):(.*):([^:]+)/\3:\2:\1/'
(一个或多个非冒号的字符) : (.*贪婪匹配) : 一个或多个非冒号的字符
如果是非贪婪匹配后面要加?, 小括号用于匹配子串, 小括号括起来的内容, 后面用\加数字, 或者&调用.
\1 子串匹配标记
& 已匹配字符串标记

示例: 所有行前加字符串 aaa: head test.txt | sed -r 's/(.*)/aaa:&/'
g: 全局替换. 不加g只替换每一行的第一个匹配.
当需要从第N处匹配开始替换时,可以使用/Ng, 如: echo sksksksksksk | sed 's/sk/SK/2g'

  • w: 写入到文件, 后跟文件路径. 如: sed -n '/#/w/root/222.txt' 111.txt
  • r: 在文件指定位置插入另一个文件的所有内容, 完成文件合并.
    示例: sed '$ r/root/222.txt' 111.txt
  • =: 显示行号
    示例: sed '/1/=' 123.txt 打印行号和匹配到的行
  • a\: 在当前行下面插入文本
    示例1: sed i '/^11111$/a\22222' 1.txt 在11111下面加一行22222
    示例2: 在test.conf 文件第2行之后插入 this is a test line.
    sed -i '2a\this is a test line' test.conf
  • i\: 在当前行上面插入文本, 支持用\n实现插入多行
  • c\: 把选定的行改为新的文本
  • y: 替换, 不能用正则
    示例: sed '1,3y/abcdefg/ABCDEFG/' 1.txt
  • \<: 匹配单词的开始
  • \>: 匹配单词的结束

6. 高级用法

h:用模式空间中的内容覆盖保持空间的内容
H:把模式空间中的内容追加至保持空间中内容的后面
g:从保持空间中取到其内容,并将其覆盖模式空间中的内容
G:从保持空间中取到其内容,并将其追加在模式空间中的内容的后面
x:把保持空间和模式空间中的进行交换
n:读取匹配到的行的下一行至模式空间(会覆盖模式空间中的原有内容)
读取下一个输入行,用下一个命令处理新的行而不是用第一个命令
示例1: sed '/eastern/{n;s/AM/Archie/;}' 111.txt
某一行匹配到eastern时, 将他的下一行的AM替换成Archie
示例2: sed '/test/{ n; s/aa/bb/; }' file
如test被匹配,则移到匹配行的下一行,替换该行的aa为bb,并打印该行,然后继续.
N:读取匹配到的行的下一行至模式空间,追加在模式空间中原有内容的后面
d:删除模式空间中的内容
D:删除多行模式空间中的首行

命令功能可使用!取反. 分号可用于分隔脚本.

6.1 示例

6.1.1 示例1. 倒序显示文件内容 sed '1!G;h;$!d' 111.txt

1!G: 第一行不执行G命令,从第二行开始执行
$!d: 最后一行不删除

111.txt内容

#!/bin/bash
a
b
c
d
e
f
执行过程
  1. 读入第一行,匹配1!G,不执行G;h命令没有定界,执行h,从模式空间覆盖到保持空间;不匹配$!d,删除模式空间的内容
  2. 读入第二行a,不匹配1!G,执行G,从保持空间追加到模式空间,变成:a\n#!/bin/bash;执行h,从模式空间覆盖到保持空间,保持空间由#!/bin/bash变成:a\n#!/bin/bash;不匹配$!d,删除模式空间的内容;
  3. 读入第三行b,匹配模式与第二行相同,保持空间内容变为:b\na\n#!/bin/bash
  4. 读入第七行f,匹配模式与第二行相同,保持空间内容变为:f\ne\nd\nc\nb\na\n#!/bin/bash;但最后一行匹配$!d,所以不删除模式空间内容,模式空间内容与保持空间相同,并默认打印模式空间内容。

6.1.2 示例2

在文件中每行后加入空行. sed 'G' 111.txt

6.1.3 示例3

删除行 sed '1d' 111.txt

6.1.4 示例4

保留奇数行
sed 'n;d' 111.txt

6.1.5 示例5

只打印偶数行
sed -n 'n;p' 111.txt

6.1.6 示例6

正则表达式 \w\+ 匹配每一个单词,使用 [&] 替换它

echo this is a test line | sed 's/\w\+/[&]/g'
[this] [is] [a] [test] [line]

\w: 匹配包括下划线的任何单词字符
\W: 匹配任何非单词字符。等价于“[^A-Za-z0-9_]”

6.1.7 示例7

sed表达式可以使用单引号来引用,但是如果表达式内部包含变量字符串,就需要使用双引号。

test=hello
echo hello WORLD | sed "s/$test/HELLO"
HELLO WORLD

6.1.8 示例8

打印奇数行或偶数行
sed -n 'p;n' test.txt #奇数行
sed -n 'n;p' test.txt #偶数行
sed -n '1~2p' test.txt #奇数行. 步长为2, 从第一行开始,每2行输出
sed -n '2~2p' test.txt #偶数行
awk 'NR%2' test1.txt #奇数行, 余数是1则为真
awk '!(NR%2)' test1.txt #偶数行
awk '++i%2' test1.txt #奇数行, i初始值为0, 先自增1再取余
awk 'i++%2' test1.txt #偶数行, 先取余再自增

6.1.9 示例9

打印匹配字符串的下一行
grep -A1 BBB file
sed -n '/BBB/{n;p}' file
awk '/BBB/{getline; print}' file

6.1.10 示例10

隔3行输出
awk 'NR%3==1' test1.txt #从第一行开始
awk 'NR%3==2' test1.txt #从第二行开始
sed -n '1~3p' test1.txt

未经允许不得转载:外贸SOHO笔记 » W6-C2-0426

赞 (0) 打赏

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下作者~

支付宝扫一扫打赏

微信扫一扫打赏