sed 命令学习笔记

本文是一篇关于sed命令的学习笔记,详细讲解了sed的执行过程、-i和--in-place选项、正则表达式以及常用命令。通过实例展示了如何选择处理特定文本行、如何进行替换操作,并探讨了与其他文本处理命令的区别和使用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

跳过目录

简介

返回目录
本文介绍了sed命令的基本规则和基础用法。如果希望了解sed命令的高级用法,请搜索其它教程。据说完整地介绍sed需要一本书。

sed是 Stream EDitor 的缩写。sed的好处是,不需要像vim那样打开文件后才能编辑,在shell脚本中,如果要对文本做一些简单的处理(比如插入、删除文本行、替换),可以用sed命令实现。

sed 命令的执行过程

返回目录
执行 sed 命令需要告诉 sed 两样东西:sed script和待处理的文本。sed script包含一条或多条sed commandsed 命令)。开始执行后,sed命令一行一行地处理给定的文本,对每一行,依次应用给定的sed命令。

# 把单词 'hello' 替换成 'world'
$ echo 'hello' | sed 's/hello/world/'
world

这个示例中,sed命令只有一条:s/hello/word/,待处理的文本也只有一行:word。命令的作用:用word替换hello

sed确定sed script和待处理文本的逻辑是:

  1. -e指定sed命令,或者用-f指定`sed 脚本的文件命名
  2. 如果这两个选项都没有,那第一个非sed选项参数被解析为sed 命令
  3. 其余非选项参数被人为是待处理的文本文件的名字。
  4. 如果没有给定待处理的文件名,或这文件名为-,则从标准输入 stdin读取待处理文本。非sed选项参数是指第一个不以-开头的参数。

可以同时使用-e-f,可以多次使用-e-f

下面是相应的示例代码。

# 用含有三行带编号的 hello 的文件做测试
$ cat tri-hello.txt
1 hello
2 hello
3 hello
# 把每一行的 hello 替换为 "world" 
$ sed -e 's/hello/world/' tri-hello.txt
1 world
2 world
3 world
# 如果不用 -e 和 -f 选项,第一个非选项参数就是要执行的 sed 命令
$ sed 's/hello/world/' tri-hello.txt
1 world
2 world
3 world
# 用 -e 选项,可以把要执行的 sed (子)命令放在后面,例如:
$ sed  tri-hello.txt  -e 's/hello/world/'
1 world
2 world
3 world
# 如果省略文件名,sed命令会从标准输入获取要处理的文本
$ echo 'word' | sed 's/hello/world/'
world
$ cat tri-hello.txt | sed 's/hello/world/'
1 world
2 world
3 world

sed命令开始执行后,其处理步骤简要概括如下:

  1. input stream中取出一行文本,放入一个叫pattern sapce的地方,
  2. 把 sed script 里的命令逐个应用到这一行文本上,
  3. 如果没有指定 -n选项,把pattern space里的内容(就是处理后的文本)输出到output stream中,否则转至步骤 4.
  4. 最后清空pattern space
  5. 取出下一行文本,继续下一个处理循环。

完整的处理循环参考 gnu 关于 sed 的在线文档中Execution-Cycle部分的内容。

-i --in-place选项

返回目录
,使用-i直接修改文件内容,不输出。

$ for i in {1..5}; do echo $i hello; done > th.txt
# sed默认把结果打印到屏幕上
$ sed 's,he,H-,' th.txt
1 H-llo
2 H-llo
3 H-llo
4 H-llo
5 H-llo
# 使用 -i 选项,直接修改文件
$ sed 's,he,H-,' -i th.txt
$ cat th.txt
1 H-llo
2 H-llo
3 H-llo
4 H-llo
5 H-llo
# 使用重定向写入原来的文件不靠谱,因为th.txt既做为输入又作为输出的时候,sed命令没有对最终结果做保证
# 这是我在CentOS7虚拟机上做的试验,命令卡死了
$ sed 's,he,H-,' > th.txt
^C
# Ctrl-C结束命令后文件是空的。
$ cat th.txt
$ file th.txt
th.txt: empty
# MSYS上试验的,直接是空文件
$ sed 's,he,H-,' th.txt
1 H-llo
2 H-llo
3 H-llo
4 H-llo
5 H-llo
$ sed 's,he,H-,' th.txt > th.txt
$ cat th.txt
$ file th.txt
th.txt: empty

-r -E 使用扩展的正则表达式

返回目录
sed的替换命令s默认使用的是BRE(基本正则表达式),使用-r选项,将支持ERE(扩展的正则表达式)。就跟grepgrep -E一样。


选择要处理的文本行

返回目录
大多数sed命令都可以加上一个address(地址)前缀。省略address的时候,命令会应用在每一行上,指定了address,命令就只在address选定的文本行上起作用。可以把address理解为条件判断,sed命令只处理符合条件的文本行。

最简单的address是直接指定行号,行号从 1 开始编号。第一行1,第三行到第五行1,5。示例如下:

# 最简单的`address`就是行号。行号从 1 开始编号
# 替换第一行
$ cat tri-hello.txt | sed '1s/hello/----/'
1 ----
2 hello
3 hello
# 替换第二行
$ cat tri-hello.txt | sed '2s/hello/----/'
1 hello
2 ----
3 hello
# 指定超过返回的行号,不会报错
$ cat tri-hello.txt | sed '5s/hello/----/'
1 hello
2 hello
3 hello
# 更常用的是指定行号范围,把“hello”换成“------”
$ cat ten-hello.txt | sed '2,4s/hello/------/'
1 hello
2 ------
3 ------
4 ------
5 hello
6 hello
7 hello
8 hello
9 hello
10 hello

sed的常用命令

返回目录
除了替换命令ssed提供了其它文本处理命令。

commanddescription
p打印当前行
i在当前行前面插入文本
a在当前行后面插入文本
d删除当前行
s对当前行作文本替换
### 测试用的文本,head 命令的 -n 参数在不同的示例中会取不同的值
$ nl /etc/passwd | head -n 5
     1  root:x:0:0:root:/root:/bin/bash
     2  bin:x:1:1:bin:/bin:/sbin/nologin
     3  daemon:x:2:2:daemon:/sbin:/sbin/nologin
     4  adm:x:3:4:adm:/var/adm:/sbin/nologin
     5  lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
### 打印命令:p,(联想单词 print,帮助记忆)
# 一般和 -n 选项结合使用,下面的命令打印文件的第3行到第8行
$ nl /etc/passwd | head -n 10 | sed -n '3,7p'
     3  daemon:x:2:2:daemon:/sbin:/sbin/nologin
     4  adm:x:3:4:adm:/var/adm:/sbin/nologin
     5  lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
     6  sync:x:5:0:sync:/sbin:/bin/sync
     7  shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
### 插入命令:i,(联想单词 insert 帮助记忆)
# 格式是 i<text>,比如在第一行的前面插入一行内容'hello'
$ nl /etc/passwd | head -n 4 | sed '1ihello'
hello
     1  root:x:0:0:root:/root:/bin/bash
     2  bin:x:1:1:bin:/bin:/sbin/nologin
     3  daemon:x:2:2:daemon:/sbin:/sbin/nologin
     4  adm:x:3:4:adm:/var/adm:/sbin/nologin
### 插入命令:a,(联想单词 append)
# 格式是 a<text>,比如在第一行的后面插入一行
$ nl /etc/passwd | head -n4 | sed '1ahello'
     1  root:x:0:0:root:/root:/bin/bash
hello
     2  bin:x:1:1:bin:/bin:/sbin/nologin
     3  daemon:x:2:2:daemon:/sbin:/sbin/nologin
     4  adm:x:3:4:adm:/var/adm:/sbin/nologin
### 删除命令:d (delete)
$ nl /etc/passwd | head | sed '2,5d'
     1  root:x:0:0:root:/root:/bin/bash
     6  sync:x:5:0:sync:/sbin:/bin/sync
     7  shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
     8  halt:x:7:0:halt:/sbin:/sbin/halt
     9  mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
    10  news:x:9:13:news:/etc/news:
# 可以看到,2,3,4,5 行都被删除了

命令s是常用命令,所以单列一节,详细学习一下。

替换命令 s

返回目录
命令s可以看作单词substitute(替换)或search-and-replace(搜索并替换)的首字母。而且,seds命令和vi里的:s命令很相近。
回到最开始的例子,找找感觉。

$ echo hello | sed 's/hello/world/'
world

完整的语法是s/regexp/replacement/g它的作用是把符合正则表达式regexp的字符串替换为replacement对应的字符串。后面的g是可选的。

第一,选项g(待续)
第二,分隔符可以任意选择,只是习惯一般上使用/。紧跟在字母s后的第一个字符就是分隔符,比如,使用下划线_做分隔符:

# 用下划线做分隔符:
$ echo hello | sed 's_hello_world_'
world
# 惯例,使用斜杠做分隔符;但在某些情况下换个字符做分隔符可以提高可读性,
# 比如替换字符串中本身含有斜杠
$ echo '04/16' | sed 's_/_-_'
04-16
# 如果非得用斜杠(/)做分分隔符,就需要用反斜杠(\)对不是分隔符的斜杠转义:
$ echo '04/16' | sed 's/\//-/'
04-16

第三,正则表达式语法基本语法(待续)
第四,BREERE(待续)
第五,正则表达式中的反向引用(待续)
第六,有些情况,用命令awk实现更方便(待续)

address的语法

返回目录

AddressDescription
nA line number where n is a positive integer.
$The last line.
/regexp/Lines matching a POSIX basic regular expression. Note that the \regular expression is delimited by slash characters. Optionally, the regular expression may be delimited by an character, by specifying the expression with \cregexpc, where c is the alternate character.
addr1,addrA range of lines from addr1 to addr2, inclusive. Addresses may be any of the single address forms above.
first~stepMatch the line represented by the number first, then each subsequent line at step intervals. For example 1~2 refers to each odd numbered line, 5~5 refers to the fifth line and every fifth line thereafter.
addr1,+nMatch addr1 and the following n lines.
addr!Match all lines except addr, which may be any of the forms above

学习中想到的一些问题

返回目录

  1. sed和其它命令的比较

    可以编写复杂的sed脚本,sed可以实现相当复杂的文本处理任务,但通常只用sed做一些简单的文本处理任务,就是,在命令行中提供一两条简单sed命令,而不是使用复杂的sed脚本

    It is most often used for simple, one-line tasks rather than long scripts.

    sed看作文本处理命令,相关命令有 catsortuniqcutpastejoincommondiffpatchtr

    这些文本处理命令的功能有重合的地方,sed 的用法更复杂,功能也更强大,常见的文本处理任务中,除了文本替换其它任务用别的命令也能实现,而且用起来更简单些。

    a. 输出文件内容:cat命令,或者sed-n选项+p命令
    b. 文本替换

    1. 一般的替换: 只有 seds命令
    2. 大小写转换:tr命令,或者sedy命令

    c. 正则过滤: grep 命令,sedaddress+p命令

    awk是比sed功能更强大的文本处理命令,也更复杂。awk适合处理表格数据。

  2. -e
    第一个非选项参数就是sed 命令,那为什么还要提供-e选项?能去掉-e选项吗?

    1. 加上 -e可以把sed 命令的放在其它位置,而不仅仅是只限定在第一个非选项参数。
    2. -e选项可以出现多次,从而一次性提供多个sed命令
  3. i 和 a 命令
    为什么a和i的功能重复的命令?能去掉其中的一个吗?
    不是完全重复,在第一行前面插入一行文本,用 a 就没法实现;在最后一行的后面插入文本,用 i 就没法实现。

sed的常见任务

返回目录

  1. 取文件 ten-hello.txt 的第 6到第9行的内容。
# 用 sed 命令,
$ sed '6,9p' -n ten-hello.txt
6 hello
7 hello
8 hello
9 hello
# 另一种方式,用 head + tail 命令
$ head -n 9 ten-hello.txt | tail -n $((9-6+1))
6 hello
7 hello
8 hello
9 hello

相关测试文件

生成这些文件的命令
# 生成测试文件
$ nl /etc/passwd | head -n 12 > hp.txt
$ for i in {1..10};do echo $i hello ;done > ten-hello.txt
$ head -n 3 hello.txt > tri-hello.txt
hp.txt 文件内容

返回目录

1  root:x:0:0:root:/root:/bin/bash
2  bin:x:1:1:bin:/bin:/sbin/nologin
3  daemon:x:2:2:daemon:/sbin:/sbin/nologin
4  adm:x:3:4:adm:/var/adm:/sbin/nologin
5  lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
6  sync:x:5:0:sync:/sbin:/bin/sync
7  shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
8  halt:x:7:0:halt:/sbin:/sbin/halt
9  mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
10  news:x:9:13:news:/etc/news:
11  uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
12  operator:x:11:0:operator:/root:/sbin/nologin
ten-hello.txt 文件的内容

返回目录

1 hello
2 hello
3 hello
4 hello
5 hello
6 hello
7 hello
8 hello
9 hello
10 hello

参考链接

返回目录

The Linux Command Line
鸟哥的 Linux 私房菜
$ man sed 或者在线手册

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值