linux中玩转sed技巧分享

sed命令应用广泛,使用简单,是快速文本处理的利器。它其实没多少技巧,背诵、使用是最合适的学习渠道,属于硬技能。但它又很复杂,因为高级功能太多。本篇不去关注sed的高级功能,仅对常用的一些操作,进行说明。

sed使用

sed编辑器被称作流编辑器,它和vim这种的交互式文本编辑器不同,是根据命令来处理数据流中的数据。会执行下列操作:

  • 一次从输入中读取一行数据(重复该操作直到全部行被读取完)
  • 根据编辑器命令匹配数据
  • 按照命令修改数据流中的数据
  • 将新数据输出到STDOUT(标准输出)

其中sed命令的可以从命令行中输入,也可以从一个命令文件中读取。

sed命令的格式如下:

1
2
3
4
5
6
7
8
9

$ sed options script file
# 添加script中指定的命令
$ sed -e script
# 添加file中指定的命令
$ sed -f file
# 不产生命令输出,使用print命令来完成输出
# -n 这个参数是--quiet或者--silent的意思。表明忽略执行过程的输出,只输出我们的结果即可。
$ sed -n

替换命令s

s命令会用斜线间指定的第二个文本字符串来替换第一个文本字符串模式。

1.用big test替换了test。

1
2
$ echo "This is a test" | sed 's/test/big test/'
This is a big test

2.用cat替换整个文件中的dog

示例文件:

1
2
3
4
5
$ cat data1.txt
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.

使用sed命令进行替换:

1
2
3
4
5
$ sed 's/dog/cat/' data1.txt
The quick brown fox jumps over the lazy cat.
The quick brown fox jumps over the lazy cat.
The quick brown fox jumps over the lazy cat.
The quick brown fox jumps over the lazy cat.

🌟 重要的是,要记住,sed编辑器并不会修改文本文件的数据。它只会将修改后的数据发送到STDOUT。如果你查看原来的文本文件,它仍然保留着原始数据。

3.在命令行使用多个编辑器命令

1
2
3
4
5
$ sed -e 's/brown/green/; s/dog/cat/' data1.txt
The quick green fox jumps over the lazy cat.
The quick green fox jumps over the lazy cat.
The quick green fox jumps over the lazy cat.
The quick green fox jumps over the lazy cat.

4.从文件中读取编辑器命令

如果有大量要处理的sed命令,那么将它们放进一个单独的文件中通常会更方便一些。
可以在sed命令中用-f选项来指定文件。

示例sed编辑器脚本文件

1
2
3
4
$ cat script1.sed
s/brown/green/
s/fox/elephant/
s/dog/cat/

执行sed编辑器脚本文件,按照脚本文件替换。

1
2
3
4
5
$ sed -f script1.sed data1.txt
The quick green elephant jumps over the lazy cat.
The quick green elephant jumps over the lazy cat.
The quick green elephant jumps over the lazy cat.
The quick green elephant jumps over the lazy cat.

更多替换选项

替换标记

替换命令在替换多行中的文本时能正常工作,但默认情况下它只替换每行中出现的第一处。要让替换命令能够替换一行中不同地方出现的文本必须使用替换标记(substitution flag)。

替换标记会在替换命令字符串之后设置。格式如下:

1
s/pattern/replacement/flags

有4种可用的替换标记:

  • 数字,表明新文本将替换第几处模式匹配的地方;
  • g,表明新文本将会替换所有匹配的文本;
  • p,表明原先行的内容要打印出来;
  • w file,将替换的结果写到文件中。

示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# sed编辑器只替换每行中第二次出现的匹配模式
$ sed 's/test/trial/2' data4.txt
This is a test of the trial script.
This is the second test of the trial script.
# g替换标记使你能替换文本中匹配模式所匹配的每处地方
$ sed 's/test/trial/g' data4.txt
This is a trial of the trial script.
This is the second trial of the trial script.
# p替换标记会打印与替换命令中指定的模式匹配的行。-n选项将禁止sed编辑器输出。
# p -n只输出被替换命令修改过的行。
$ cat data5.txt
This is a test line.
This is a different line.
$ sed -n 's/test/trial/p' data5.txt
This is a trial line.
# w替换标记会产生同样的输出,不过会将输出保存到指定文件中。
$ sed 's/test/trial/w test.txt' data5.txt
This is a trial line.
This is a different line.
$ cat test.txt
This is a trial line.

🌟 sed并没有对文件内容进行改变,因此如果要写回文件,可以使用重定向。

1.通过重定向写入新文件,如:

1
$ sed "s/dog/cat/g" data1.txt > data1new.txt

或者使用-i参数直接修改文件内容,如下:

1
$ sed -i "s/dog/cat/g" data1.txt

2.在每一行前面添加内容

1
2
3
4
5
$ sed 's/^/#/g' data1.txt
#the quick brown fox jumps over the lazy dog.
#the quick brown fox jumps over the lazy dog.
#the quick brown fox jumps over the lazy dog.
#the quick brown fox jumps over the lazy dog.

3.在每一行最后添加内容

1
2
3
4
5
$ sed 's/$/---/g' data1.txt
the quick brown fox jumps over the lazy dog.---
the quick brown fox jumps over the lazy dog.---
the quick brown fox jumps over the lazy dog.---
the quick brown fox jumps over the lazy dog.---

顺便介绍一下正则表达式的一些最基本的东西:

  • ^ 表示一行的开头。如:/^#/ 以#开头的匹配。
  • $ 表示一行的结尾。如:/}$/ 以}结尾的匹配。
  • < 表示词首。 如:<abc 表示以 abc 为首的詞。
  • > 表示词尾。 如:abc> 表示以 abc 結尾的詞。
  • . 通配符,表示几乎任意字符,除了换行符、回车符、行分隔符和段分隔符除外。记忆方式:想想省略号 … 中的每个点,此处省略了无数个字(什么情况都可能发生)。
  • ?表示某个字符出现了0次或1次。
  • *表示某个字符出现了0次或多次。
  • +表示某个字符出现了1次或多次。
  • [ ] 字符集合。 如:[abc] 表示匹配a或b或c,还有 [a-zA-Z] 表示匹配所有的26个字符。如果其中有^表示反,如 [^a] 表示非a的字符。还有[0-9] 匹配括号中的任何一个字符。
  • {m}前面的匹配重复m次,{m,n} 前面的匹配重复m到n次

💡 强大到无往不利的正则表达式简单示例,比如去除下面html中的tags:

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

sed命令实现:

1
2
3
4
5
6
7
8
# 如果你这样搞的话,就会有问题,贪婪模式,匹配(<)到(>)之间的所有内容
$ sed 's/<.*>//g' html.txt
meant. Understand

# 要解决上面的那个问题,就得像下面这样。
# 其中的'[^>]' 指定了除了>的字符重复0次或多次。
$ sed 's/<[^>]*>//g' html.txt
This is what I meant. Understand?

💡 其他有趣示例

1.输出长度不小于50个字符的行

1
$ sed -n '/^.{50}/p'

2.统计文件中有每个单词出现了多少次

1
$ sed 's/ /n/g' file | sort | uniq -c

3.查找目录中的py文件,删掉所有行级注释

1
$ find ./ -name "*.py" | xargs sed  -i.bak '/^[ ]*#/d'

4.查看第5-7行和10-13行

1
$ sed -n -e '5,7p' -e '10,13p' file

5.仅输出ip地址

1
$ ip route show | sed -n '/src/p' | sed -e 's/  */ /g' | cut -d' ' -f9

使用地址

默认情况下,在sed编辑器中使用的命令会作用于文本数据的所有行。如果只想将命令作用于特定行或某些行,则必须用行寻址(line addressing)。

数字方式寻址

sed编辑器会将文本流中的第一行编号为1,然后继续按顺序为接下来的行分配行号。

1.只修改第二行的数据

1
2
3
4
5
$ sed '2s/dog/cat/' data1.txt
The quick brown fox jumps over the lazy dog
The quick brown fox jumps over the lazy cat
The quick brown fox jumps over the lazy dog
The quick brown fox jumps over the lazy dog

2.修改第二行和第三行,使用行地址区间

1
2
3
4
5
$ sed '2,3s/dog/cat/' data1.txt
The quick brown fox jumps over the lazy dog
The quick brown fox jumps over the lazy cat
The quick brown fox jumps over the lazy cat
The quick brown fox jumps over the lazy dog

3.也可以匹配从文本中某行开始到结束的所有行

1
2
3
4
5
$ sed '2,$s/dog/cat/' data1.txt
The quick brown fox jumps over the lazy dog
The quick brown fox jumps over the lazy cat
The quick brown fox jumps over the lazy cat
The quick brown fox jumps over the lazy cat

使用文本过滤器

sed编辑器允许指定文本模式来过滤出命令要作用的行。格式如下:

1
/pattern/command

必须用正斜线将要指定的pattern封起来。sed编辑器会将该命令作用到包含指定文本模式的行上。

举个栗子🌰来说明一下吧,在/etc/passwd中只修改用户Samantha的默认shell,如下:

1
2
3
4
5
6
7
8
9
$ grep Samantha /etc/passwd
Samantha:x:502:502::/home/Samantha:/bin/bash
$ sed '/Samantha/s/bash/csh/' /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
[...]
Christine:x:501:501:Christine B:/home/Christine:/bin/bash
Samantha:x:502:502::/home/Samantha:/bin/csh
Timothy:x:503:503::/home/Timothy:/bin/bash

删除行

使用删除命令d对文本进行删除操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 删除所有文本
sed 'd' data1.txt

# 删除单行
sed '2d' data1.txt

# 删除行区间[2,3]
sed '2,3d' data1.txt

# 删除行区间[2,endline]
sed '2,$d' data1.txt

# 删除匹配文本aa的行
sed '/aa/d' data1.txt

# 删除两个匹配文本之间的文本 匹配到1和3的行之间的文本全部被删除
sed '/1/,/3/d' data1.txt

插入、附加文本

1.插入命令i在指定行前增加新行

2.附加命令a在指定行后增加新行

1
2
3
4
5
6
7
8
9
# 追加
$ echo "Test Line 2" | sed 'aTest Line 1'
Test Line 2
Test Line 1

# 插入
$ echo "Test Line 2" | sed 'iTest Line 1'
Test Line 1
Test Line 2

修改行

使用c命令来修改一行数据

1
2
3
4
5
6
7
# 修改第三行文本
$ sed '3c
This is a changed line of text.' data1.txt
the quick brown fox jumps over the lazy dog.
the quick brown fox jumps over the lazy dog.
This is a changed line of text.
the quick brown fox jumps over the lazy dog.

转换命令

命令格式sed 'y/inchar/outchar'

将inchar中的字符一一对应地转换成outchar的字符

1
2
3
$ echo "This 1 is a test of 1 try." | sed 'y/123/456/'
# 输出
This 4 is a test of 4 try.

💡 如你在输出中看到的,inchars模式中指定字符的每个实例都会被替换成outchars模式中
相同位置的那个字符。

打印命令

1.打印数据文本

1
2
3
$ echo "this is a test" | sed 'p'
this is a test
this is a test

2.打印包含匹配文本模式的行

1
2
3
4
5
6
7
8
9
10
11
12
$ cat data6.txt
This is line number 1.
This is line number 2.
This is line number 3.
This is line number 4.
# 模式匹配
$ sed -n '/number 3/p' data6.txt
This is line number 3.
# 从一个模式到另一个模式
$ sed -n '/number 2/,/number 3/p' data6.txt
this is line number 2.
this is line number 3.

3.快速打印数据流中的某些行

1
2
3
$ sed -n '2,3p' data6.txt
This is line number 2.
This is line number 3.

4.从第一行打印匹配3成功的那一行

1
2
3
4
$ sed -n '1,/3/p' data6.txt
this is line number 1.
this is line number 2.
this is line number 3.

参考链接:
SED 简明教程
Linux生产环境上,最常用的一套“Sed“技巧