LV02-02-shell-07-sed命令的使用

本文主要是shell——sed命令的相关笔记,若笔记中有错误或者不合适的地方,欢迎批评指正😃。

点击查看使用工具及版本
Windows windows11
Ubuntu Ubuntu16.04的64位版本
VMware® Workstation 16 Pro 16.2.3 build-19376536
SecureCRT Version 8.7.2 (x64 build 2214) - 正式版-2020年5月14日
开发板 正点原子 i.MX6ULL Linux阿尔法开发板
uboot NXP官方提供的uboot,NXP提供的版本为uboot-imx-rel_imx_4.1.15_2.1.0_ga(使用的uboot版本为U-Boot 2016.03)
linux内核 linux-4.15(NXP官方提供)
STM32开发板 正点原子战舰V3(STM32F103ZET6)
点击查看本文参考资料
参考方向 参考原文
------
点击查看相关文件下载
--- ---

一、sed 简介

sed 算是是一种在线编辑器,采用的是流编辑模式,它一次处理文件中一行的内容。进行文本处理时,会把当前处理的行存储在临时缓冲区中,称为“模式空间”( pattern space ),接着用 sed 命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕,所以每处理一次就会有一次输出。接着处理下一行,这样不断重复,直到文件末尾。

【注意】 sed 默认不会直接修改源文件数据,而是会将数据复制到缓冲区中,修改也仅限于缓冲区中的数据。

二、 sed 命令

sed 命令,不管是否找到指定的模式,它的退出状态都是 0 。只有当命令存在语法错误时, sed 的退出状态才不是 0 。语法格式如下:

1
sed [ option ] [ action ] file_name
  • option
option -n 该选项会屏蔽启动输出,仅显示script处理后的结果
-i 直接修改文件内容,而不是输出到终端。
-e [script] 以选项中指定的script来处理输入的文本文件,若之前已有命令,此时会将script脚本命令添加到已有的命令中。
-f [script文件] 以选项中指定的script文件来处理输入的文本文件,若之前已有命令,此时会将script文件中的脚本命令添加到已有的命令中。

【注意】 -i 选项要慎用,毕竟会直接修改原文件。

  • action
action a 新增, a 的后面可以接字符串,这些字串会在新的一行出现(当前行的下一行)。
【注意】若要插入多行,则行之间要加上 \ 。
c 替换整行,用此符号后的新文本替换当前行中的文本。
d 删除,通常不接任何东西
i 插入,后面可以跟字符串,在当前行的上一行插入文本
【注意】若要插入多行,则行之间要加上 \ 。
p 打印,通常与 -n 一起使用。
s 替换字符串,可以搭配正则表达式,用一个字符串替换另一个字符串
y 将字符替换为另一字符(不能对正则表达式使用y命令)
r 将一个独立文件的数据插入到当前数据流的指定位置

【注意】 sed 后面接的动作,要以 ‘ ‘ 两个单引号括住。

  • 相关正则表达式
字符 说明 实例
^ 行首定位符 /^a/ 匹配所有以a开头的行。
$ 行尾定位符 /a$/ 匹配所有以 a 结尾的行。
. 匹配除换行符以外的单个字符 /a..b/ 匹配包含字母 a ,后跟两个任意字符,再跟字母 b 的行。
* 匹配除换行符以外的单个字符 /a..b/ 匹配包含字母 a ,后跟两个任意字符,再跟字母 b 的行
[] 匹配指定字符组内的任一字符 /[Aa]b/ 匹配包含 Ab 或 ab 的行。
[^] 匹配不在指定字符组内的任一字符 /[^Aa]b/ 匹配包含 b ,但 b 之前的那个字符不是 A 或 a 的行。
\(..\) 保存已匹配的字符 1,5s/\(you\)self/\1r/ 标记元字符之间的模式,并将其保存为标签 1 ,之后可以使用 \1 来引用它。最多可以定义 9 个标签,从左边开始编号,最左边的是第一个。此例中,对第 1 到第 5 行进行处理,you被保存为标签 1 ,如果发现 youself ,则替换为 your 。
& 保存查找的字符串以便在替换串中引用 s/ab/**&**/ 符号 & 代表查找的字符串,ab 将会被替换为**ab**。
\< 词首定位符 /\<ab/ 匹配包含以 ab 开头的单词的行。
\> 词尾定位符 /ab\>/ 匹配包含以 ab 结尾的单词的行。
a\{n\} 连续 n 个 a /a\{5\}/ 匹配包含连续 5 个 a 的行。
a\{n,\} 至少连续 n 个 a /a\{5,\}/ 匹配包含至少连续 5 个 a 的行。
a\{m,n\} 至少连续 m 个,但不超过连续 n 个 a /a\{5,7\}/ 匹配包含连续 5 到 7 个 a 的行。

三、sed 使用实例

只说参数并不能很好理解如何使用,这里将会有大量的实例来帮忙理解。先写一个测试用的文件,就以 Hexo 的站点配置文件为例,删除一些东西,留下一些用于测试使用。文件内容如下:

1
2
3
4
5
6
7
8
9
10
11
[1] title: Hexo
[2] author: John Doe
[3] language: en
[4] url: http://example.com
[5] permalink: :year/:month/:day/:title/
[6]
[7] theme: theme: landscape theme
[8] theme: aaa
[9] theme: landscape
[10]theme: landscape
[11]Theme: def

【说明】我这里用的是 Windows 下 Git 的 bash ,与 linux 中应该是一样的。另外运行脚本中的 $ ./1.sh 表示在命令行运行该脚本文件,下边的为输出结果,文件中前边方括号里边的内容为这一行在源文件的行号。

1. a 和 i 动作

1.1 在第 n 行前插入一行

1
2
3
4
5
#!/bin/sh
# sed [ option ] [ action ] file_name
# 注意:原文件不变
# 格式:sed 'ni\string' file_name
sed '2i\这是第2行前新插入的行' ./_config.yml

运行结果如下:

原文件 缓冲区输出(屏幕显示)
[1] title: Hexo
[2] author: John Doe
[3] language: en
[4] url: http://example.com
[5] permalink: :year/:month/:day/:title/
[6]
[7] theme: theme: landscape theme
[8] theme: aaa
[9] theme: landscape
[10]theme: landscape
[11]Theme: def
[1] title: Hexo
这是第2行前新插入的行
[2] author: John Doe
[3] language: en
[4] url: http://example.com
[5] permalink: :year/:month/:day/:title/
[6]
[7] theme: theme: landscape theme
[8] theme: aaa
[9] theme: landscape
[10]theme: landscape
[11]Theme: def

1.2 在第 n 行后插入一行

1
2
3
4
5
#!/bin/sh
# sed [ option ] [ action ] file_name
# 注意:原文件不变
# 格式:sed 'na\string' file_name
sed '2a\这是第2行后新插入的行' ./_config.yml

运行结果如下:

原文件 缓冲区输出(屏幕显示)
[1] title: Hexo
[2] author: John Doe
[3] language: en
[4] url: http://example.com
[5] permalink: :year/:month/:day/:title/
[6]
[7] theme: theme: landscape theme
[8] theme: aaa
[9] theme: landscape
[10]theme: landscape
[11]Theme: def
[1] title: Hexo
[2] author: John Doe
这是第2行后新插入的行
[3] language: en
[4] url: http://example.com
[5] permalink: :year/:month/:day/:title/
[6]
[7] theme: theme: landscape theme
[8] theme: aaa
[9] theme: landscape
[10]theme: landscape
[11]Theme: def

1.3 在最后一行前插入一行

1
2
3
4
5
#!/bin/sh
# sed [ option ] [ action ] file_name
# 注意:原文件不变
# 格式:sed '$i\string' file_name
sed '$i\这是最后一行行前新插入的行' ./_config.yml

运行结果如下:

原文件 缓冲区输出(屏幕显示)
[1] title: Hexo
[2] author: John Doe
[3] language: en
[4] url: http://example.com
[5] permalink: :year/:month/:day/:title/
[6]
[7] theme: theme: landscape theme
[8] theme: aaa
[9] theme: landscape
[10]theme: landscape
[11]Theme: def
[1] title: Hexo
[2] author: John Doe
[3] language: en
[4] url: http://example.com
[5] permalink: :year/:month/:day/:title/
[6]
[7] theme: theme: landscape theme
[8] theme: aaa
[9] theme: landscape
[10]theme: landscape
这是最后一行行前新插入的行
[11]Theme: def

1.4 在最后一行后插入一行

1
2
3
4
5
#!/bin/sh
# sed [ option ] [ action ] file_name
# 注意:原文件不变
# 格式:sed '$a\string' file_name
sed '$a\这是最后一行行前新插入的行' ./_config.yml

运行结果如下:

原文件 缓冲区输出(屏幕显示)
[1] title: Hexo
[2] author: John Doe
[3] language: en
[4] url: http://example.com
[5] permalink: :year/:month/:day/:title/
[6]
[7] theme: theme: landscape theme
[8] theme: aaa
[9] theme: landscape
[10]theme: landscape
[11]Theme: def
[1] title: Hexo
[2] author: John Doe
[3] language: en
[4] url: http://example.com
[5] permalink: :year/:month/:day/:title/
[6]
[7] theme: theme: landscape theme
[8] theme: aaa
[9] theme: landscape
[10]theme: landscape
[11]Theme: def
这是最后一行行后新插入的行

2. d 动作

2.1 通过行号指定删除行

1
2
3
4
5
#!/bin/sh
# sed [ option ] [ action ] file_name
# 注意:原文件不变
# 格式:sed 'nd' filename
sed '2d' ./_config.yml # 删除第2行

运行结果如下:

原文件 缓冲区输出(屏幕显示)
[1] title: Hexo
[2] author: John Doe
[3] language: en
[4] url: http://example.com
[5] permalink: :year/:month/:day/:title/
[6]
[7] theme: theme: landscape theme
[8] theme: aaa
[9] theme: landscape
[10]theme: landscape
[11]Theme: def
[1] title: Hexo
[3] language: en
[4] url: http://example.com
[5] permalink: :year/:month/:day/:title/
[6]
[7] theme: theme: landscape theme
[8] theme: aaa
[9] theme: landscape
[10]theme: landscape
[11]Theme: def

2.2 通过区间删除行

1
2
3
4
5
#!/bin/sh
# sed [ option ] [ action ] file_name
# 注意:原文件不变
# 格式:sed 'n1,n2d' filename
sed '2,4d' ./_config.yml # 删除2-4行,共删除3行

运行结果如下:

原文件 缓冲区输出(屏幕显示)
[1] title: Hexo
[2] author: John Doe
[3] language: en
[4] url: http://example.com
[5] permalink: :year/:month/:day/:title/
[6]
[7] theme: theme: landscape theme
[8] theme: aaa
[9] theme: landscape
[10]theme: landscape
[11]Theme: def
[1] title: Hexo
[5] permalink: :year/:month/:day/:title/
[6]
[7] theme: theme: landscape theme
[8] theme: aaa
[9] theme: landscape
[10]theme: landscape
[11]Theme: def

2.3 通过数据搜索删除行

1
2
3
4
5
#!/bin/sh
# sed [ option ] [ action ] file_name
# 注意:原文件不变
# 格式:sed '/<string>/d' filename
sed '/theme/d' ./_config.yml # 删除含有theme的行

运行结果如下:

原文件 缓冲区输出(屏幕显示)
[1] title: Hexo
[2] author: John Doe
[3] language: en
[4] url: http://example.com
[5] permalink: :year/:month/:day/:title/
[6]
[7] theme: theme: landscape theme
[8] theme: aaa
[9] theme: landscape
[10]theme: landscape
[11]Theme: def
[1] title: Hexo
[2] author: John Doe
[3] language: en
[4] url: http://example.com
[5] permalink: :year/:month/:day/:title/
[6]
[11]Theme: def

3. c 动作

3.1 通过行号指定替换行

1
2
3
4
5
#!/bin/sh
# sed [ option ] [ action ] file_name
# 注意:原文件不变
# 格式:sed '2c <string>' filename
sed '2c 这是替换后的第2行' ./_config.yml

运行结果如下:

原文件 缓冲区输出(屏幕显示)
[1] title: Hexo
[2] author: John Doe
[3] language: en
[4] url: http://example.com
[5] permalink: :year/:month/:day/:title/
[6]
[7] theme: theme: landscape theme
[8] theme: aaa
[9] theme: landscape
[10]theme: landscape
[11]Theme: def
[1] title: Hexo
这是替换后的第2行
[3] language: en
[4] url: http://example.com
[5] permalink: :year/:month/:day/:title/
[6]
[7] theme: theme: landscape theme
[8] theme: aaa
[9] theme: landscape
[10]theme: landscape
[11]Theme: def

3.2 通过区间指定替换行

1
2
3
4
5
#!/bin/sh
# sed [ option ] [ action ] file_name
# 注意:原文件不变
# 格式:sed 'n1,n2c <string>' filename
sed '2,3c 2,3行已被替换,这是替换后的行' ./_config.yml

运行结果如下:

原文件 缓冲区输出(屏幕显示)
[1] title: Hexo
[2] author: John Doe
[3] language: en
[4] url: http://example.com
[5] permalink: :year/:month/:day/:title/
[6]
[7] theme: theme: landscape theme
[8] theme: aaa
[9] theme: landscape
[10]theme: landscape
[11]Theme: def
[1] title: Hexo
2,3行已被替换,这是替换后的行
[4] url: http://example.com
[5] permalink: :year/:month/:day/:title/
[6]
[7] theme: theme: landscape theme
[8] theme: aaa
[9] theme: landscape
[10]theme: landscape
[11]Theme: def

4. -n选项与p动作

4.1 数据的搜索显示

1
2
3
4
5
#!/bin/sh
# sed [ option ] [ action ] file_name
# 注意:原文件不变
# 格式:sed '/<string>/p' filename
sed '/theme/p' ./_config.yml # 显示含有 theme 的行

运行结果如下:

原文件 缓冲区输出(屏幕显示)
[1] title: Hexo
[2] author: John Doe
[3] language: en
[4] url: http://example.com
[5] permalink: :year/:month/:day/:title/
[6]
[7] theme: theme: landscape theme
[8] theme: aaa
[9] theme: landscape
[10]theme: landscape
[11]Theme: def
[1] title: Hexo
[2] author: John Doe
[3] language: en
[4] url: http://example.com
[5] permalink: :year/:month/:day/:title/
[6]
[7] theme: theme: landscape theme
[7] theme: theme: landscape theme
[8] theme: aaa
[8] theme: aaa
[9] theme: landscape
[9] theme: landscape
[10]theme: landscape
[10]theme: landscape
[11]Theme: def

4.2 加上 -n ?

我们会发现上边的输出中,含有 theme 的行每行都被显示了两次,一次是处理的时候的输出,另一次是 p 动作的输出。那么如何只输出我所需要的行呢?

1
2
3
4
5
#!/bin/sh
# sed [ option ] [ action ] file_name
# 注意:原文件不变
# 格式:sed -n '/<string>/p' filename
sed -n '/theme/p' ./_config.yml # 显示含有 theme的行

运行结果如下:

原文件 缓冲区输出(屏幕显示)
[1] title: Hexo
[2] author: John Doe
[3] language: en
[4] url: http://example.com
[5] permalink: :year/:month/:day/:title/
[6]
[7] theme: theme: landscape theme
[8] theme: aaa
[9] theme: landscape
[10]theme: landscape
[11]Theme: def
[7] theme: theme: landscape theme
[8] theme: aaa
[9] theme: landscape
[10]theme: landscape

5.  s 动作

5.1 使用格式

s 就是字符串替换的命令,使用格式如下:

1
s/original/target/flags
original 需要替换的字符串,也就是原来的字符串
target 替换后的字符串,也就是目标字符串
flags n 1 ~ 512 之间的数字,表示指定要替换的字符串出现第几次时才进行替换,例如,一行中有 5 个 a,但用户只想替换第 3 个 a,就可以使用此标记。
g 对数据中所有匹配到的内容进行替换,如果没有 g,则只会在第 1 次匹配成功时做替换操作。
p 会打印与替换命令中指定的模式匹配的行。此标记通常与 -n 选项一起使用。
w file 将缓冲区中的内容写到指定的 file 文件中。
& 用正则表达式匹配的内容进行替换。
\n 匹配第 n 个子串,该子串之前在 original 中用 \(\) 指定。
\ 转义(转义替换部分包含:&、\ 等)。

5.2 实例1:替换字符串的 n 与 g 标识

1
2
3
4
5
6
7
#!/bin/sh
# sed [ option ] [ action ] file_name
# 注意:原文件不变
# 格式:sed 's/original/target/g' filename
# sed 's/original/target/n' filename
# sed 's/theme/我是替换的字符串/g' ./_config.yml # 替换匹配到的所有 theme
sed 's/theme/我是替换的字符串/2' ./_config.yml # 替换匹配到的第2个 theme

运行结果如下:

原文件 缓冲区输出(屏幕显示)
[1] title: Hexo
[2] author: John Doe
[3] language: en
[4] url: http://example.com
[5] permalink: :year/:month/:day/:title/
[6]
[7] theme: theme: landscape theme
[8] theme: aaa
[9] theme: landscape
[10]theme: landscape
[11]Theme: def
[1] title: Hexo
[2] author: John Doe
[3] language: en
[4] url: http://example.com
[5] permalink: :year/:month/:day/:title/
[6]
[7] theme: 我是替换的字符串: landscape theme
[8] theme: aaa
[9] theme: landscape
[10]theme: landscape
[11]Theme: def

【说明】 -g 选项则是替换所有的匹配值,这里不再说明。

5.3 实例2:显示替换行的 p 标识

1
2
3
4
5
#!/bin/sh
# sed [ option ] [ action ] file_name
# 注意:原文件不变
# 格式:sed -n 's/original/target/p' filename
sed -n 's/theme/我是替换的字符串/p' ./_config.yml

运行结果如下:

原文件 缓冲区输出(屏幕显示)
[1] title: Hexo
[2] author: John Doe
[3] language: en
[4] url: http://example.com
[5] permalink: :year/:month/:day/:title/
[6]
[7] theme: theme: landscape theme
[8] theme: aaa
[9] theme: landscape
[10]theme: landscape
[11]Theme: def
[7] 我是替换的字符串: theme: landscape theme
[8] 我是替换的字符串: aaa
[9] 我是替换的字符串: landscape
[10]我是替换的字符串: landscape

【说明】此时仅仅输出了替换的行,但是,只要含有 theme 的行,每行的第一个 theme 都会被替换。

5.4 实例3:匹配结果进行保存的 w file 标识

1
2
3
4
5
#!/bin/sh
# sed [ option ] [ action ] file_name
# 注意:原文件不变
# 格式:sed 's/original/target/w test.txt' filename
sed -n 's/theme/我是替换的字符串/w test.txt' ./_config.yml

运行结果如下:

原文件 text.txt文件内容(屏幕不显示)
[1] title: Hexo
[2] author: John Doe
[3] language: en
[4] url: http://example.com
[5] permalink: :year/:month/:day/:title/
[6]
[7] theme: theme: landscape theme
[8] theme: aaa
[9] theme: landscape
[10]theme: landscape
[11]Theme: def
[7] 我是替换的字符串: theme: landscape theme
[8] 我是替换的字符串: aaa
[9] 我是替换的字符串: landscape
[10]我是替换的字符串: landscape

5.5 实例4:转义标识 \

主要是用于替换文件中的路径时用的较多。

1
2
3
4
#!/bin/sh
# sed [ option ] [ action ] file_name
# 格式:sed 's/original/target/g' filename
sed 's/\/bin\/bash/\/abs\/df/g' ./_config.yml

运行结果如下:

原文件(这里增加了第12行用于测试) 缓冲区输出(屏幕显示)
[1] title: Hexo
[2] author: John Doe
[3] language: en
[4] url: http://example.com
[5] permalink: :year/:month/:day/:title/
[6]
[7] theme: theme: landscape theme
[8] theme: aaa
[9] theme: landscape
[10]theme: landscape
[11]Theme: def
[12]/bin/bash
[1] title: Hexo
[2] author: John Doe
[3] language: en
[4] url: http://example.com
[5] permalink: :year/:month/:day/:title/
[6]
[7] theme: theme: landscape theme
[8] theme: aaa
[9] theme: landscape
[10]theme: landscape
[11]Theme: def
[12]/abs/df

5.5 实例5:数据搜索并显示并执行命令

1
2
3
4
5
#!/bin/sh
# sed [ option ] [ action ] file_name
# 注意:原文件不变
# 格式:sed -n '/string/{s/original/target/;p;q}' filename
sed -n '/theme/{s/landscape/next/;p;q}' ./_config.yml

运行结果如下:

原文件 缓冲区输出(屏幕显示)
[1] title: Hexo
[2] author: John Doe
[3] language: en
[4] url: http://example.com
[5] permalink: :year/:month/:day/:title/
[6]
[7] theme: theme: landscape theme
[8] theme: aaa
[9] theme: landscape
[10]theme: landscape
[11]Theme: def
[7] theme: theme: next theme

【说明】该命令会找到 string 出现的第一行,再执行后面花括号中的一组命令,每个命令之间用分号分隔,这里把 landscape 替换为 next ,p 表示显示处理结果, q 表示退出。

6. y动作

6.1 使用格式

y 转换命令是唯一可以处理单个字符的 sed 脚本命令。

1
[address]y/inchars/outchars/

转换命令会对 inchars 和 outchars 值进行一对一的映射,即 inchars 中的第一个字符会被转换为 outchars 中的第一个字符,第二个字符会被转换成 outchars 中的第二个字符…,这个映射过程会一直持续到处理完指定字符。如果 inchars 和 outchars 的长度不同,则 sed 会产生一条错误消息。

6.2 使用实例

1
2
3
4
5
6
#!/bin/sh
# sed [ option ] [ action ] file_name
# 注意:原文件不变
sed '1,$y/theme:/THEME*/' datafile
# 将 1 到尾行内所有行,所有的 't' 'h' 'e' 'm' 'e' 5个字母分别转换成 'T' 'H' 'E' 'M' 'E' 5个字母,将 ':' 转换成 '*'
# 正则表达式元字符对y命令不起作用。与s命令的分隔符一样,斜线可以被替换成其它的字符。

运行结果如下:

原文件 缓冲区输出(屏幕显示)
[1] title: Hexo
[2] author: John Doe
[3] language: en
[4] url: http://example.com
[5] permalink: :year/:month/:day/:title/
[6]
[7] theme: theme: landscape theme
[8] theme: aaa
[9] theme: landscape
[10]theme: landscape
[11]Theme: def
[1] TiTlE* HExo
[2] auTHor* JoHn DoE
[3] languagE* En
[4] url* HTTp*//ExaMplE.coM
[5] pErMalink* *yEar/*MonTH/*day/*TiTlE/
[6]
[7] THEME* THEME* landscapE THEME
[8] THEME* aaa
[9] THEME* landscapE
[10]THEME* landscapE
[11]THEME* dEf

7. r 动作

创建一个 test.txt 的文件,里边写入数据 theme: next 。

1
2
3
4
#!/bin/sh
# sed [ option ] [ action ] file_name
# 注意:原文件不变
sed '3r test.txt' ./_config.yml # 将test.txt中的文件插入到_config.yml文件第三行后面一行

运行结果如下:

原文件 缓冲区输出(屏幕显示)
[1] title: Hexo
[2] author: John Doe
[3] language: en
[4] url: http://example.com
[5] permalink: :year/:month/:day/:title/
[6]
[7] theme: theme: landscape theme
[8] theme: aaa
[9] theme: landscape
[10]theme: landscape
[11]Theme: def
[1] title: Hexo
[2] author: John Doe
[3] language: en
theme: next
[4] url: http://example.com
[5] permalink: :year/:month/:day/:title/
[6]
[7] theme: theme: landscape theme
[8] theme: aaa
[9] theme: landscape
[10]theme: landscape
[11]Theme: def

8. -e 选项

  • 多条命令连接
1
2
3
4
#!/bin/sh
# sed [ option ] [ action ] file_name
# 注意:原文件不变
sed -e '2,3d' -e 's/theme/string/' ./_config.yml

运行结果如下:

原文件 缓冲区输出(屏幕显示)
[1] title: Hexo
[2] author: John Doe
[3] language: en
[4] url: http://example.com
[5] permalink: :year/:month/:day/:title/
[6]
[7] theme: theme: landscape theme
[8] theme: aaa
[9] theme: landscape
[10]theme: landscape
[11]Theme: def
[1] title: Hexo
[4] url: http://example.com
[5] permalink: :year/:month/:day/:title/
[6]
[7] string: theme: landscape theme
[8] string: aaa
[9] string: landscape
[10]string: landscape
[11]Theme: def

【说明】删除第 2,3 行,然后将文件中的 theme 用 string 替换。

9. -i 选项(慎用)

  • 直接修改文件
1
2
3
4
#!/bin/sh
# sed [ option ] [ action ] file_name
# 注意:原文件被修改
sed -i 's/landscape/next/' ./_config.yml

运行结果如下:

原文件 修改后的文件(屏幕无显示)
[1] title: Hexo
[2] author: John Doe
[3] language: en
[4] url: http://example.com
[5] permalink: :year/:month/:day/:title/
[6]
[7] theme: theme: landscape theme
[8] theme: aaa
[9] theme: landscape
[10]theme: landscape
[11]Theme: def
[1] title: Hexo
[2] author: John Doe
[3] language: en
[4] url: http://example.com
[5] permalink: :year/:month/:day/:title/
[6]
[7] theme: theme: next theme
[8] theme: aaa
[9] theme: next
[10]theme: next
[11]Theme: def

【说明】可以看到,命令直接替换了所有的字符串。

10. -f 选项

  • sed 脚本

sed 脚本就是写在文件中的一列 sed 命令。脚本中,命令的末尾不能有任何多余的空格或文本。如果在一行中有多个命令,要用分号分隔。使用 sed 脚本时,不再用引号来确保 sed 命令不被 shell 解释

执行脚本时, sed 先将输入文件中第一行复制到模式缓冲区,然后对其执行脚本中所有的命令。每一行处理完毕后, sed 再复制文件中下一行到模式缓冲区,对其执行脚本中所有命令。

四、使用变量?

我们可以在sed命令中使用变量吗?这样我们的脚本的通用性不就很高了吗。我们这里用实例来说明

1. 命令用双引号

第一种方式就是sed后边的命令用双引号括起来,我们可以直接引用变量,需要注意的是在变量中若有路径也要注意转义一下,例如:

1
2
3
4
5
6
7
#!/bin/sh
# sed [ option ] [ action ] file_name
# 注意:原文件不变
# 格式:sed 's/original/target/g' filename
source_path="\/bin\/bash"
target_path="ab\/cd\/ef\/gh"
sed "s/${source_path}/${target_path}/g" ./_config.yml

运行结果如下:

原文件(这里增加了第12行用于测试) 缓冲区输出(屏幕显示)
[1] title: Hexo
[2] author: John Doe
[3] language: en
[4] url: http://example.com
[5] permalink: :year/:month/:day/:title/
[6]
[7] theme: theme: landscape theme
[8] theme: aaa
[9] theme: landscape
[10]theme: landscape
[11]Theme: def
[12]/bin/bash
[1] title: Hexo
[2] author: John Doe
[3] language: en
[4] url: http://example.com
[5] permalink: :year/:month/:day/:title/
[6]
[7] theme: theme: landscape theme
[8] theme: aaa
[9] theme: landscape
[10]theme: landscape
[11]Theme: def
[12]ab/cd/ef/gh

2. 命令用单引号

第二种就是命令若是单引号的话,引用的变量也要单引号括起来,需要注意的是在变量中若有路径也要注意转义一下,例如:

1
2
3
4
5
6
7
#!/bin/sh
# sed [ option ] [ action ] file_name
# 注意:原文件不变
# 格式:sed 's/original/target/g' filename
source_path="\/bin\/bash"
target_path="ab\/cd\/ef\/gh"
sed 's/'${source_path}'/'${target_path}'/g' ./_config.yml

运行结果如下:

原文件(这里增加了第12行用于测试) 缓冲区输出(屏幕显示)
[1] title: Hexo
[2] author: John Doe
[3] language: en
[4] url: http://example.com
[5] permalink: :year/:month/:day/:title/
[6]
[7] theme: theme: landscape theme
[8] theme: aaa
[9] theme: landscape
[10]theme: landscape
[11]Theme: def
[12]/bin/bash
[1] title: Hexo
[2] author: John Doe
[3] language: en
[4] url: http://example.com
[5] permalink: :year/:month/:day/:title/
[6]
[7] theme: theme: landscape theme
[8] theme: aaa
[9] theme: landscape
[10]theme: landscape
[11]Theme: def
[12]ab/cd/ef/gh

五、空文件不生效?

后来在使用过程中,遇到过这样一种情况,我需要新创建一个文件,然后直接用sed命令添加数据,我们来看一下直接这样来做会发生什么,我们由于要修改文件,所以就直接使用 -i 命令,我们这里使用向文件末尾追加的命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/bin/bash
# sed [ option ] [ action ] file_name
# 格式:sed '\$a\string' file_name
# 注意这里使用sh会有报错,所以这里使用了bash
newfile=test.txt
data=( "插入的第1行"
"插入的第2行"
"插入的第3行"
"插入的第4行"
"插入的第5行")
touch ${newfile}
echo "sed 命令前的 ${newfile}文件内容:"
cat ${newfile}
echo "sed===========> start"
for data_temp in "${data[@]}"
do
echo ${data_temp}
sed -i "\$a${data_temp}" ${newfile}
done
echo "sed===========> end"
echo "sed 命令后的 ${newfile}文件内容:"
cat ${newfile}

我们可以看到终端有以下输出:

1
2
3
4
5
6
7
8
9
10
hk@ubuntu-22-04:~/1sharedfiles/6temp$ ./1.sh 
sed 命令前的 test.txt文件内容:
sed===========> start
插入的第1行
插入的第2行
插入的第3行
插入的第4行
插入的第5行
sed===========> end
sed 命令后的 test.txt文件内容:

我们会发现文件依然是空的,没有任何数据,网上查了一下,发现是因为sed是基于行来处理的文件流编辑器,如果文件为空的话,它是处理不了的,那我们怎么处理呢?我们可以判断一下,当是空文件的时候使用echo来写,非空的时候用sed追加:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#!/bin/bash
# sed [ option ] [ action ] file_name
# 格式:sed '$a\string' file_name
newfile=test.txt
data=( "插入的第1行"
"插入的第2行"
"插入的第3行"
"插入的第4行"
"插入的第5行")
touch ${newfile}
echo "sed 命令前的 ${newfile}文件内容:"
cat ${newfile}
echo "sed===========> start"
for data_temp in "${data[@]}"
do
echo ${data_temp}
# test -s ${newfile} && sed -i "\$a${data_temp}" ${newfile} || echo "${data_temp}" >> ${newfile}
if test -s ${newfile};then
sed -i "\$a${data_temp}" ${newfile}
else
echo "${data_temp}" >> ${newfile}
fi
done
echo "sed===========> end"
echo "sed 命令后的 ${newfile}文件内容:"
cat ${newfile}

执行的结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
hk@ubuntu-22-04:~/1sharedfiles/6temp$ ./1.sh 
sed 命令前的 test.txt文件内容:
sed===========> start
插入的第1行
插入的第2行
插入的第3行
插入的第4行
插入的第5行
sed===========> end
sed 命令后的 test.txt文件内容:
插入的第1行
插入的第2行
插入的第3行
插入的第4行
插入的第5行

【说明】文章到这里就暂时结束了,没有遇到过相应的使用方式,笔记先到这里, sed 还有其他的用法,后续有用到再进行补充。