bash命令: sed的使用

文章目录


sed全名叫stream editor,流编辑器,用程序的方式来编辑文本,相当的hacker啊。sed基本上就是玩正则模式匹配。

sed的基本使用格式

sed [address]s/pattern/replacement/flags input-file
选项含义
-e 脚本命令指定命令,命令用单引号或者双引号包围,单引号不支持转义
-f 脚本命令文件使用文件里的脚本编辑数据
-n禁用默认的输出缓冲区
-i直接修改源文件
flags功能
n替换第n个匹配,比如1行中有3个pattern匹配,但是我们只想替换第1次匹配,这个时候我们指定n=1
g替换所有匹配,不指定g,只会替换第1个匹配,相当于n=1
p打印匹配的行
w file输出到file文件
&引用pattern匹配的内容
\n引用正则里的第n个group,group通过()指定
\转义符,转义: & \等
1. 用s命令替换
演示文本
$ cat pets.txt
This is my cat
  my cat's name is betty
This is my dog
  my dog's name is frank
This is my fish
  my fish's name is george
This is my goat
  my goat's name is adam
案例1: 把my字符串替换成 Lou’s
[root@iZuf6237a4x522d614bn53Z ~]# sed "s/my/Lou's/g" a.txt
This is Lou's cat
  Lou's cat's name is betty
This is Lou's dog
  Lou's dog's name is frank
This is Lou's fish
  Lou's fish's name is george
This is Lou's goat
  Lou's goat's name is adam

s表示替换命令

/my/表示匹配my

/Lou’s/表示把匹配替换成Lou’s

/g 表示一行上的替换所有的匹配):

案例2: 替换并输出到文件
sed "s/my/Hao Chen's/g" a.txt > a_modify.txt
案例3:替换并修改源文件,使用选项 -i
sed -i "s/my/Lou's/g"  a.txt
案例4:使用正则替换,行首、行尾插入
sed 's/^/#/g' a.txt
sed 's/$/#/g' a.txt

可用的正则表达式:

^ 表示一行的开头。如:/^#/ 以#开头的匹配

$ 表示一行的结尾。如:/}$/ 以}结尾的匹配

< 表示词首。 如:<abc 表示以 abc 为首的詞

> 表示词尾。 如:abc> 表示以 abc 結尾的詞

. 表示任何单个字符

* 表示某个字符出现了0次或多次

[ ] 字符集合。 如:[abc] 匹配a、b或c,还有 [a-zA-Z] 所有大小写字母,^表示取反,如 [^a] 表示非a的字符,[0-9]表示1位数字0~9

[[:blank:]] 表示任意空白符

\(\)用于指定分组

[0-9]\{4\}-[0-9]\{2,3\}: \{4\}指定次数, \{2,3\}指定运行2到3次

案例5:指定替换范围,替换第3行
sed "3s/my/your/g" a.txt

在这里插入图片描述

案例5:指定替换范围,替换第3到5行
sed "3,5s/my/your/g" a.txt

在这里插入图片描述

案例6:组合命令
sed 'N;{s/\n/,/;s/s/S/}' a.txt

在这里插入图片描述

案例7:指定替换位置
# 替换第1次匹配
sed 's/s/S/1' a.txt
sed 's/s/S/'  a.txt
# 替换第2次匹配
sed 's/s/S/2' a.txt
# 替换所有匹配
sed 's/s/S/g' a.txt
# 替换第3个及以后
sed 's/s/S/3g' a.txt
# 替换第2、3个匹配
sed 'N;{s/\n/,/; s/s/S/2; s/s/S/2;}' a.txt
案例8:组合语句
sed '1,3s/my/your/g; 3,$s/This/That/g' a.txt
sed -e '1,3s/my/your/g' -e '3,$s/This/That/g' a.txt
案例9:正则引用,引用整个匹配
sed 's/my/[&]/g' my.txt
案例10:正则引用,引用分组
sed 'N; s/\n/,/g; s/This is my \([^,&]*\),.*is \(.*\)/\1:\2/g' a.txt

在这里插入图片描述

2. sed命令
N命令: 将下一行读入缓冲区
  • 两行合一行
sed 'N; s/\n//' a.txt
a命令:append一行
# 指定行号添加
[root@iZuf6237a4x522d614bn53Z ~]# sed '1a What is the fuck' a.txt
This is my cat
What is the fuck
  my cat's name is betty
...

# 模式匹配后添加
[root@iZuf6237a4x522d614bn53Z ~]# sed '/dog/a What is the fuck' a.txt
This is my cat
  my cat's name is betty
This is my dog
What is the fuck

i命令:insert一行
[root@iZuf6237a4x522d614bn53Z ~]# sed '1i What is the fuck' a.txt
What is the fuck
This is my cat
  my cat's name is betty
...
c命令:替换
[root@iZuf6237a4x522d614bn53Z ~]# sed '2c What is the fuck' a.txt
This is my cat
What is the fuck
This is my dog
...
[root@iZuf6237a4x522d614bn53Z ~]# sed '/dog/c What is the fuck' a.txt
This is my cat
  my cat's name is betty
What is the fuck
...
d命令:删除
[root@iZuf6237a4x522d614bn53Z ~]# sed '2d' a.txt
This is my cat
This is my dog
...

[root@iZuf6237a4x522d614bn53Z ~]# sed '/dog/d' a.txt
This is my cat
  my cat's name is betty
This is my fish
...
p命令:打印
# -n: 不输出,p匹配/fish/的输出
[root@iZuf6237a4x522d614bn53Z ~]# sed -n '/fish/p' a.txt
This is my fish
  my fish's name is george

# 没有-n是默认输出一边,匹配/fish/的p命令输出一边
[root@iZuf6237a4x522d614bn53Z ~]# sed '/fish/p' a.txt
This is my cat
  my cat's name is betty
This is my dog
  my dog's name is frank
This is my fish
This is my fish
  my fish's name is george
  my fish's name is george
This is my goat
  my goat's name is adam
r命令: 将一个文件的数据插入到当前数据流指定位置
# 使用格式
# [address]r filename

[root@localhost ~]# cat data12.txt
This is an added line.
This is the second added line.
[root@localhost ~]# sed '3r data12.txt' data6.txt
This is line number 1.
This is line number 2.
This is line number 3.
This is an added line.
This is the second added line.
This is line number 4.
y命令: 字符替换
[root@localhost ~]# sed 'y/123/789/' data8.txt
This is line number 7.
This is line number 8.
This is line number 9.
This is line number 4.
知识点
Pattern Space

sed处理数据的时候先将数据读取到Pattern Space,然后用sed命令对数据做处理,如果没有指定-n选项的话,最后会把Pattern Space内容输出。

从伪代码的角度来看Pattern Space和-n是实现:

foreach line in file {
    //放入把行Pattern_Space
    Pattern_Space <= line;
    // 对每个pattern space执行sed命令
    Pattern_Space <= EXEC(sed_cmd, Pattern_Space);
    // 如果没有指定 -n 则输出处理后的Pattern_Space
    if (sed option hasn't "-n")  {
       print Pattern_Space
    }
}
Address

Address用于指定sed命令的作用范围,格式:

[address[,address]][!]{cmd}

address可以是数字,也可以是模式,!表示匹配的行不执行cmd,从伪代码来看address的实现:

bool bexec = false
foreach line in file {
    if ( match(address1) ){
        bexec = true;
    }
    if ( bexec == true) {
        EXEC(sed_cmd);
    }
    if ( match (address2) ) {
        bexec = false;
    }
}

在这里插入图片描述

命令组合
sed -n '3,6 {/This/{/fish/p; s/my/Your/p}}' a.txt
sed '1,3s/my/your/g; 3,$s/This/That/g' a.txt
sed -e '1,3s/my/your/g' -e '3,$s/This/That/g' a.txt
[root@localhost ~]# sed -n '/3/{
> p
> s/line/test/p
> }' data6.txt
This is line number 3.
This is test number 3.

在这里插入图片描述

Hold Space

Hold Space的概念,我们先来看四个命令:

g: 将hold space中的内容拷贝到pattern space中,原来pattern space里的内容清除

G: 将hold space中的内容append到pattern space\n后

h: 将pattern space中的内容拷贝到hold space中,原来的hold space里的内容被清除

H: 将pattern space中的内容append到hold space\n后

x: 交换pattern space和hold space的内容

累计输出

# 因为H先在Hold Space加\n,然后再将Pattern Space拷入Hold Space
# 导致每次输出Pattern Space前面都多一个空行
[root@iZuf6237a4x522d614bn53Z ~]# sed  'H;g' t.txt

one

one
two

one
two
three
# 第一行不从Hold Space拷,那么第一行的空行就没了
[root@iZuf6237a4x522d614bn53Z ~]# sed  'H;1!g' t.txt
one

one
two

one
two
three
# 第一行直接拿Pattern Space替换Hold Space就不会有空行出现
[root@iZuf6237a4x522d614bn53Z ~]# sed  '{1h;1!H};g' t.txt
one
one
two
one
two
three

在这里插入图片描述

反序输出

sed '1!G;h;$!d' t.txt

1!G,第一行不把Hold Space的内容append到Pattern Space,后面都要

h; 将Pattern Space内容覆盖Hold Space

$!d; 最后输出一次
在这里插入图片描述

2. 高阶用法
2.1 n和N命令
1. n命令会输出当前Pattern Space,清空Pattern Space,并读取下一行
[randy@qaserver1 sed_test]$printf '%s\n' aa bb cc dd | sed 'p;n'
aa
aa
bb
cc
cc
dd

执行过程:

  1. sed循环,读入aa到Pattern Space,由p命令打印第一个aa,n命令再次导致打印aa并读取下一行bb,然后由循环输出bb,结束一次循环
  2. sed循环,读入cc到Paatern Spcae, 由p命令打印第一个cc,n命令再次导致打印cc并读取下一行dd,然后由循环输出dd,结束一次循环
2. -n选项会抑制默认的sed循环输出,也会抑制n命令的输出
[randy@qaserver1 sed_test]$printf '%s\n' aa bb cc dd | sed -n 'p;n'
aa
cc

-n会导致n命令和p命令的输出都不显示

3. n和N命令的区别是: n是读取下一行覆盖Pattern Space,而N是读取下一行拼接到当前Pattern Space内容中

sed循环本身会清空Pattern Space,所以如果n或N命令后没有输出的话,就相当于丢弃一行

[randy@qaserver1 sed_test]$sed -n 'p;n' a.txt
This is my cat
This is my dog
This is my fish
This is my goat
[randy@qaserver1 sed_test]$sed -n 'p;N' a.txt
This is my cat
This is my dog
This is my fish
This is my goat

n是读取下一行覆盖Pattern Space,如果覆盖前没有输出,相当于丢一行。 但是N没有这个问题,它会缓存两行在Pattern Space中,一次性输出

[randy@qaserver1 sed_test]$sed -n 'n;p;' a.txt
  my cat's name is betty
  my dog's name is frank
  my fish's name is george
  my goat's name is adam
[randy@qaserver1 sed_test]$sed -n 'N;p;' a.txt
This is my cat
  my cat's name is betty
This is my dog
  my dog's name is frank
This is my fish
  my fish's name is george
This is my goat
  my goat's name is adam
3. 不抑制输出时, n是每行输出一次,N是在一个循环结束后一次性输出

比如下面这个例子,虽然输出是一样的,但实际上n输出了3次,而N只输出了一次。

[randy@qaserver1 sed_test]$seq 3 | sed ':x ; N ; bx'
1
2
3
[randy@qaserver1 sed_test]$seq 3 | sed ':x ; n ; bx'
1
2
3

通过命令=输出行号,可以观察到n是打印一行输出一个行号,而N直接输出多个行号后,一次性输出内容。

[randy@qaserver1 sed_test]$printf '%s\n' aa bb cc dd | sed ':x ; N ; = ; bx'
2
3
4
aa
bb
cc
dd
[randy@qaserver1 sed_test]$printf '%s\n' aa bb cc dd | sed ':x ; n ; = ; bx'
aa
2
bb
3
cc
4
dd

替换n的Pattern Space的换行符不会有效果,因为此时Pattern Space只存放了不包括换行符的一行内容,而N中的换行符是可以的

[randy@qaserver1 sed_test]$printf '%s\n' aa bb cc dd | sed ':x ; n ; s/\n/***/ ; bx'
aa
bb
cc
dd
[randy@qaserver1 sed_test]$printf '%s\n' aa bb cc dd | sed ':x ; N ; s/\n/***/ ; bx'
aa***bb***cc***dd
2.2 b t T

我们可以通":字母",比如":a"定义一个lable(按Java的lable理解),通过b{label名},如ba;跳到label定义位置继续执行,不算一个新的循环(不清空Pattern Pattern)。
t命令和b的区别是会检查在:a定义到ta;直接需要有一个替换操作s/xxx/###/,如果成功替换,跳转到label定义的位置。
T命令是t的反向选择,没有替换成功的时候跳转到lable定义的位置。

测试文案

[randy@qaserver1 sed_test]$cat b.txt
All the wor=
ld's a stag=
e,
And all the=
 men and wo=
men merely =
players:
They have t=
heir exits =
and their e=
ntrances;
And one man=
 in his tim=
e plays man=
y parts.

目的是将=号结尾的行和接下来一行合并

1. 方法一
[randy@qaserver1 sed_test]$sed  -n ':a; /=$/!p;  /=$/ { N; s/=\n//g; ta; }' b.txt
All the world's a stage,
And all the men and women merely players:
They have their exits and their entrances;
And one man in his time plays many parts.

如果当前行不是以=号结尾,直接打印当前行;否则读取下一行并替换=\n,如果替换成功,重新跳到:a(不是开始新循环,Pattern Space保留),前面加了判断只要不是最后一行有=就能正常替换。

2. 方法二: 死循环式的读,直到不匹配或者不以=结尾
[randy@qaserver1 sed_test]$sed  ':a; /=$/ { N; s/=\n//g; ba; }' b.txt
All the world's a stage,
And all the men and women merely players:
They have their exits and their entrances;
And one man in his time plays many parts.

一直读,直到不以=结尾或者最后一行,然后有sed自己输出

2.3 案例
1. 不提供label,相当于于空命令,启动新一轮循环(清除Pattern Space)
[randy@qaserver1 sed_test]$seq 3 | sed b
1
2
3
2. l(小写L)命令,打印不可见字符,和p类似,但是会把空白字符转义后打印
[randy@qaserver1 sed_test]$seq 6 | sed -n -e 'N; l ; D'
1\n2$
2\n3$
3\n4$
4\n5$
5\n6$
3. D命令,用于删除Pattern Space里的内容到第一个换行符(“\n”),保留剩余部分
[randy@qaserver1 sed_test]$seq 6 | sed -n -e 'N; l ; N; D'
1\n2$
2\n3\n4$
3\n4\n5\n6$

指定了D命令不会重新开始循环(清除Pattern Scape),相当于sed也不会自动读取行(除了第一次启动)。

执行过程:

  1. 启动时sed读取1,N1命令读出数字2,l命令打印1\n2$N2命令读取数字3,D命令删除Pattern Space数字1和换行符(剩余内容2\n3),
  2. N1命令读取数组4,l命令打印2\n3\n4N2命令读取数字5,D命令删除Pattern Space里的数字2,保留3\n4\n5
  3. 最后N1命令再次读取数组6,读取完成最后打印
4. P(大写)命令,打印Pattern Space里的内容(截止到第一个换行符为止)的内容
[randy@qaserver1 sed_test]$seq 6 | sed -n -e 'N; N; P'
1
4
  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值