Linux shell 之 sed 命令详解 第三部分 Linux shell 之 sed 命令详解 第三部分

  目录:

    五、修改行

    六、转换命令

    七、回顾打印

    八、使用 sed 处理文件

五、修改行

  修改( change)命令允许修改数据流中整行文本的内容。它跟插入和附加命令的工作机制一样,你必须在sed命令中单独指定新行。

1 sed '3c
2 > This is a changed line of text.' data4.txt
3 This is line number 1
4 This is line number 2
5 This is a changed line of text.
6 This is line number 4
7 This is line number 5
8 $

  在这个例子中,sed 编辑器会修改第三行中的文本。也可以用文本模式来寻址。

1 $ sed '/number 3/c
2 > This is a changed line of text.' data4.txt
3 This is line number 1
4 This is line number 2
5 This is a changed line of text.
6 This is line number 4
7 This is line number 5
8 $

  文本模式修改命令会修改它匹配的数据流中的任意文本行。 

 1 $ sed '/number 1/c
 2 > This is a changed line of text.' data5.txt
 3 This is a changed line of text.
 4 This is line number 2.
 5 This is line number 3.
 6 This is line number 4.
 7 This is line number 5.
 8 This is line number 6.
 9 This is a changed line of text.
10 This is text you want to keep.
11 This is the last line in the file.
12 $

  你可以在修改命令中使用地址区间,但结果未必如愿。

 1 $ sed '2,3c
 2 > This is a new line of text.' data5.txt
 3 This is line number 1.
 4 This is a new line of text.
 5 This is line number 4.
 6 This is line number 5.
 7 This is line number 6.
 8 This is line number 1 again.
 9 This is text you want to keep.
10 This is the last line in the file.
11 $

  sed 编辑器会用这一行文本来替换数据流中的两行文本,而不是逐一修改这两行文本。

六、转换命令

  转换(transform)命令(y)是唯一可以处理单个字符的 sed 编辑器命令。转换命令格式如下。

    [address]y/inchars/outchars/

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

 1 $ sed 'y/123/789/' data5.txt
 2 This is line number 7.
 3 This is line number 8.
 4 This is line number 9.
 5 This is line number 4.
 6 This is line number 5.
 7 This is line number 6.
 8 This is line number 7 again.
 9 This is text you want to keep.
10 This is the last line in the file.
11 $

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

  转换命令是一个全局命令,也就是说,它会在文本行中找到的所有指定字符自动进行转换,而不会考虑它们出现的位置。

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

  sed 编辑器转换了在文本行中匹配到的字符 1 的两个实例。你无法限定只转换在特定地方出现的字符。

七、回顾打印

  前面写过使用 p 标记和替换命令显示 sed 编辑器修改过的行。另外有 3 个命令也能用来打印数据流中的信息:

    ⭐  p 命令用来打印文本行;

    ⭐  等号( =)命令用来打印行号;

    ⭐  l(小写的L)命令用来列出行。

1、打印行

  跟替换命令中的 p 标记类似, p 命令可以打印 sed 编辑器输出中的一行。如果只用这个命令,也没什么特别的。

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

  它所做的就是打印已有的数据文本。打印命令最常见的用法是打印包含匹配文本模式的行。

 1 $ cat data4.txt
 2 This is line number 1
 3 This is line number 2
 4 This is line number 3
 5 This is line number 4
 6 This is line number 5
 7 $
 8 $ sed -n '/number 3/p' data4.txt
 9 This is line number 3
10 $

  在命令行上用-n选项,你可以禁止输出其他行,只打印包含匹配文本模式的行。

  也可以用它来快速打印数据流中的某些行。

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

  如果需要在修改之前查看行,也可以使用打印命令,比如与替换或修改命令一起使用。可以创建一个脚本在修改行之前显示该行。

 1 $ sed -n '/3/{
 2 > p
 3 > s/line/tag/p
 4 > }' data4.txt
 5 This is line number 3
 6 This is tag number 3
 7 $
 8 $
 9 $
10 $
11 $ sed -n '3{
12 p
13 s/line/tag/p
14 }' data4.txt
15 This is line number 3
16 This is tag number 3
17 $

  sed 编辑器命令会查找包含数字3的行,然后执行两条命令。首先,脚本用 p 命令来打印出原始行;然后它用 s 命令替换文本,并用 p 标记打印出替换结果。输出同时显示了原来的行文本和新的行文本。

2、打印行号

   等号命令会打印行在数据流中的当前行号。行号由数据流中的换行符决定。每次数据流中出现一个换行符, sed 编辑器会认为一行文本结束了。

 1 $ cat data1.txt
 2 the quick brown fox jumps over the lazy dog.
 3 The quick brown fox jumps over the lazy dog.
 4 The quick brown fox jumps over the lazy dog.
 5 The quick brown fox jumps over the lazy dog.
 6 $
 7 zhengchuanyu@zhengchuanyu:~/reverse_xiaoyu$ sed '=' data1.txt
 8 1
 9 the quick brown fox jumps over the lazy dog.
10 2
11 The quick brown fox jumps over the lazy dog.
12 3
13 The quick brown fox jumps over the lazy dog.
14 4
15 The quick brown fox jumps over the lazy dog.
16 $

  sed 编辑器在实际的文本行出现前打印了行号。如果你要在数据流中查找特定文本模式的话,等号命令用起来非常方便。

1 $ sed -n '/number 4/{
2 > =
3 > p
4 > }' data4.txt
5 4
6 This is line number 4
7 $

  利用 -n 选项,你就能让 sed 编辑器只显示包含匹配文本模式的行的行号和文本。

3、列出行

  列出( list)命令( l)可以打印数据流中的文本和不可打印的 ASCII 字符。任何不可打印字符要么在其八进制值前加一个反斜线,要么使用标准C风格的命名法(用于常见的不可打印字符),比如 ,来代表制表符。

 1 $ cat data4.txt
 2 This is line number 1
 3 This is line number 2
 4 This is line number 3
 5 This is line number 4
 6 This is line number 5
 7 $
 8 $ sed -n 'l' data4.txt
 9 This is line number 1$
10 This is line number 2$
11 This is line number 3$
12 This is line number 4$
13 This is line number 5$
14 $
1 $ cat data6.txt
2 I       love    linux   shell
3 $
4 $ sed -n 'l' data6.txt
5 I	love	linux	shell$
6 $

  制表符的位置使用 来显示。行尾的美元符表示换行符。如果数据流包含了转义字符,列出命令会在必要时候用八进制码来显示。

1 $ cat data10.txt
2 This line contains an escape character.
3 $
4 $ sed -n 'l' data10.txt
5 This line contains an escape character. a$
6 $

  data10.txt 文本文件包含了一个转义控制码来产生铃声。当用 cat 命令来显示文本文件时,你看不到转义控制码,只能听到声音(如果你的音箱打开的话)。但是,利用列出命令,你就能显示出所使用的转义控制码。

八、使用 sed 处理文件

  替换命令包含一些可以用于文件的标记。还有一些 sed 编辑器命令也可以实现同样的目标,不需要非得替换文本。

1、写入文件

  w 命令用来向文件写入行。该命令的格式如下:

    [address]w filename

  filename 可以使用相对路径或绝对路径,但不管是哪种,运行 sed 编辑器的用户都必须有文件的写权限。地址可以是 sed 中支持的任意类型的寻址方式,例如单个行号、文本模式、行区间或文本模式。

  下面的例子是将数据流中的前两行打印到一个文本文件中。

 1 $ sed '1,2w test.txt' data4.txt
 2 This is line number 1
 3 This is line number 2
 4 This is line number 3
 5 This is line number 4
 6 This is line number 5
 7 $
 8 $ cat test.txt
 9 This is line number 1
10 This is line number 2
11 $

  当然,如果你不想让行显示到 STDOUT 上,你可以用 sed 命令的 -n 选项。

  如果要根据一些公用的文本值从主文件中创建一份数据文件,比如下面的邮件列表中的,那么 w 命令会非常好用。

 1 $ cat data11.txt
 2 Blum, R Browncoat
 3 McGuiness, A Alliance
 4 Bresnahan, C Browncoat
 5 Harken, C Alliance
 6 $
 7 $ sed -n '/Browncoat/w Browncoats.txt' data11.txt
 8 $
 9 $ cat Browncoats.txt
10 Blum, R Browncoat
11 Bresnahan, C Browncoat
12 $

 

  sed 编辑器会只将包含文本模式的数据行写入目标文件。

2、从文件读取数据

  了解了如何在 sed 命令行上向数据流中插入或附加文本。读取( read)命令( r)允许你将一个独立文件中的数据插入到数据流中。

  读取命令的格式如下:

    [address]r filename

  filename 参数指定了数据文件的绝对路径或相对路径。你在读取命令中使用地址区间,只能指定单独一个行号或文本模式地址。 sed 编辑器会将文件中的文本插入到指定地址后。

 1 $ cat data7.txt
 2 I love linux shell
 3 $ sed '$r data7.txt' data4.txt
 4 This is line number 1
 5 This is line number 2
 6 This is line number 3
 7 This is line number 4
 8 This is line number 5
 9 I love linux shell
10 $

  sed 编辑器会将数据文件中的所有文本行都插入到数据流中。同样的方法在使用文本模式地址时也适用。

1 $ sed '/number 2/r data12.txt' data6.txt
2 This is line number 1.
3 This is line number 2.
4 This is an added line.
5 This is the second added line.
6 This is line number 3.
7 This is line number 4.
8 $

  如果你要在数据流的末尾添加文本,只需用美元符地址符就行了。

  读取命令的另一个很酷的用法是和删除命令配合使用:利用另一个文件中的数据来替换文件中的占位文本。举例来说,假定你有一份套用信件保存在文本文件中:

1 $ cat notice.std
2 Would the following people:
3 LIST
4 please report to the ship's captain.
5 $

  套用信件将通用占位文本 LIST 放在人物名单的位置。要在占位文本后插入名单,只需读取命令就行了。但这样的话,占位文本仍然会留在输出中。要删除占位文本的话,你可以用删除命令。结果如下:

 1 $ sed '/LIST/{
 2 > r data11.txt
 3 > d
 4 > }' notice.std
 5 Would the following people:
 6 Blum, R Browncoat
 7 McGuiness, A Alliance
 8 Bresnahan, C Browncoat
 9 Harken, C Alliance
10 please report to the ship's captain.
11 $

  现在占位文本已经被替换成了数据文件中的名单。