sed学习

sed学习

在Mac OS上使用sed是BSD sed 会产生很多的不便,因此可以替换一下

1
2
brew install gnu-sed
alias sed=gsed

sed(stream editor)流编辑器,用程序的方式来编辑文本。基本上使用正则模式匹配。

sed的官方手册

s替换命令

首先写一下可能会用到的正则的东西

语法 作用 例子
^ 一行的开始 /^#/ 以#开头的匹配
$ 一行的结尾 /}$/ 以}结尾的匹配
\< 字符串的开始 /<adc 表示以abc为首的词
> 字符串的结尾 abc/> 表示以abc为尾的词
. 任何单个字符
* 某个字符出现0到无限次
[] 字符集

有一段如下的文字pet.txt:

1
2
3
4
5
6
7
8
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

要把其中的my替换为Dlala's,就使用

1
sed "s/my/Dlala's/g" pet.txt

这里使用""是为了能转义,其中,s代表替换命令,/my/代表匹配my,’/Dlala’s/‘代表把匹配替换成Dlala’s,/g和正则中一样,为全局模式,表示一行上替换所有的匹配。

上述的sed并没有对文件的内容进行修改,只是把处理后的内容输出出来,如果要修改原文件,就使用重定向,如下

1
sed "s/my/Dlala's/g" pet.txt > Dlala_pet.txt

或者也可以使用-i参数直接修改文件的内容:

1
sed -i "s/my/Dlala's/g" pet.txt

这里如果使用OS X的话要这样写

1
sed -i '' "s/my/Dlala's/g" pet.txt

这是因为Ubuntu ships with GNU sed, where the suffix for the -i option is optional. OS X ships with BSD sed, where the suffix is mandatory. Try sed -i ‘’


来写个实例,获取html标签内的内容

index.html如下

1
2
3
<p>
<b>This</b> is what <span style="text-decoration: underline;">I</span> meant. Understand?
</p>

使用sed命令如下:

1
sed "s/<[^>]*>//g" index.html

输出如下:

1
This is what I meant. Understand?

在每一行的前面加东西:

1
sed "s/^/#/g" pet.txt

在每一行的后面加东西:

1
sed "s/$/ --- /g" pet.txt

替换第三行的制定内容

1
sed "3s/my/your/g" pet.txt

替换3到6行的指定内容

1
sed "3,6s/my/your/g" pet.txt

修改一个txt如下:

1
2
3
4
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

只替换每一行的第一个s:

1
sed "s/s/S/1" pet.txt

只替换每一行的第二个s:

1
sed "s/s/S/2" pet.txt

只替换每一行的第三个以后的s:

1
sed "s/s/S/3g" pet.txt

此命令只能在Linux下执行,原因还是sed的版本问题。


使用&来当做被匹配的变量,然后在其左右加内容

1
sed 's/my/[&]/g' pet.txt

多个匹配

如果需要一次替换多个模式,可以使用多个匹配,每个模式之间使用;分割,下面写两个例子:

第一个例子是这样的,替换一到三行的my,并且第三行到最后一行的This

1
sed '1,3s/my/your/g; 3,$s/This/That/g' pet.txt

这里的''不能用""代替!


上述的命令等价于:

1
sed -e'1,3s/my/your/g' -e '3,$s/This/That/g' pet.txt

(这里就使用了sed的-e命令行参数)这里也不要使用""因为会造成$不起作用的情况。

圆括号匹配

圆括号括起来的正则表达式所匹配的字符串可以当成变量来使用,sed中使用的是\1,\2…

1
sed 's/This is my \([^,]*\),.*is \(.*\)/\1:\2/g' pet.txt

输出结果:

1
2
3
4
cat:betty
dog:frank
fish:george
goat:adam

sed的命令

N命令

N命令–把下一行的内容纳入当成缓冲区做匹配。

例如,当使用N来处理以下pet.txt文件时

1
2
3
4
5
6
7
8
This is your cat
my cat's name is betty
This is your dog
my dog's name is frank
This is your fish
my fish's name is george
This is your goat
my goat's name is adam

会把原文本中的偶数行纳入奇数行进行匹配,就成了以下效果:

1
2
3
4
This is my cat\n  my cat's name is betty
This is my dog\n my dog's name is frank
This is my fish\n my fish's name is george
This is my goat\n my goat's name is adam

那么使用命令

1
sed 'N;s/\n/,/' pet.txt

就会出现以下效果:

1
2
3
4
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

a命令和i命令

a : append

i : insert

这两条命令是用来添加行的。分别举个例子:

1
sed "1 i This is Lyh"

表示在第一行插入一行(insert)


1
sed "1 a This is Lyh"

表示在第一行插入一行(append)

还可以使用匹配来添加文本:

1
sed "/fish/a This is Lyh" pet.txt

d命令

删除匹配行,举三个例子

1
2
3
4
5
6
7
8
sed '/fish/d' pet.txt
#删除fish这一行

sed '2d' pet.txt
#删除第二行

sed '2,$d' pet.txt
#删除第二到最后一行

p命令

p命令可以理解为是grep式的命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 匹配fish并输出,可以看到fish的那一行被打了两遍,
# 这是因为sed处理时会把处理的信息输出
$ sed '/fish/p' pet.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 fish, my fish's name is george
This is my goat, my goat's name is adam

# 使用n参数就能只输出一行
$ sed -n '/fish/p' pet.txt
This is my fish, my fish's name is george

# 从一个模式到另一个模式
$ sed -n '/dog/,/fish/p' pet.txt
This is my dog, my dog's name is frank
This is my fish, my fish's name is george

#从第一行打印到匹配fish成功的那一行
$ sed -n '1,/fish/p' pet.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

基本知识

  • Pattern Space: 关于参数-n,表示取消默认输出,相当于–quiet,–silent。在sed处理文件的时候,每一行都被保存在一个叫模式空间的临时缓冲区中,除非行被删除或者输出被取消,否则所有被处理的行都将打印在屏幕上。接着模式空间被清空,并存入新的一行等待处理。

  • Address:[address[,address]][!]{cmd},其中的!表示匹配成功后是否执行命令,address可以是一个数字,也可以是一个模式,可以通过逗号分隔两个address表示两个address的区间。

  • 命令打包:cmd可以是多个,它们可以用分号分开,可以用大括号括起来作为嵌套命令

举个例子:

1
2
sed '3,6 {/This/{/fish/d}}' pet.txt
#对3行到第6行,匹配/This/成功后,再匹配/fish/,成功后执行d命令
1
2
sed '1,${/This/d ; s/^ *//g}' pets.txt
#从第一行到最后一行,如果匹配到This,则删除之;如果前面有空格,则去除空格
  • HoldSpace: 保持空间
1
2
3
4
5
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的内容

举个例子:

1
sed -e '/test/h' -e '$G‘  example

在这个例子里,匹配test的行被找到后,将存入模式空间,h命令将其复制并存入一个称为保持缓存区的特殊缓冲区内。第二条语句的意思是,当到达最后一行后,G命令取出保持缓冲区的行,然后把它放回模式空间中,且追加到现在已经存在于模式空间中的行的末尾。在这个例子中就是追加到最后一行。简单来说,任何包含test的行都被复制并追加到该文件的末尾。

1
sed -e '/test/h' -e '/check/x' example

互换模式空间和保持缓冲区的内容。也就是把包含test与check的行互换。

  • 执行sed脚本:sed -f test.sed

Sed对于脚本中输入的命令非常挑剔,在命令的末尾不能有任何空白或文本,如果在一行中有多个命令,要用分号分隔。以#开头的行为注释行,且不能跨行。

ps: 去除空白行:sed ‘/^ *$/d’ file