前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >《Linux命令行与shell脚本编程大全》第二十一章 sed进阶

《Linux命令行与shell脚本编程大全》第二十一章 sed进阶

作者头像
xcywt
发布2018-01-11 17:55:30
1.6K0
发布2018-01-11 17:55:30
举报
文章被收录于专栏:xcywtxcywt

本章介绍一些sed编辑器提供的高级特性。

21.1 多行命令

按照之前的知识,所有的sed编辑器命令都是针对单行数据执行操作的。

在sed编辑器读取数据流时,它会基于换行符的位置将数据分成行,一次处理一行数据。

有时会需要对跨多行的数据执行特定操作。

比如,在数据中查找一个长的短语Linux system Administrators Group.如果这个短语出现在两行当中,之前的知识就不够用了。

解决方案,sed编辑器包含了三个可用来处理多行文本的特殊命令

N:将数据流中的下一行加进来创建一个多行组(multiline group)来处理

D:删除多行组中的一行

P:打印多行组中的一行

21.1.1 next命令

这个分单行版本的next命令和多行版本的next命令。

1.单行版本的next命令

小写的n命令会告诉sed编辑器移动到数据流中的下一行文本,而不用重新回到命令的最开始再执行一遍。

记住,通常sed编辑器在移动到数据流中下一行文本行之前,会在当前行上执行完所有定义好的命令,而next命令改变了这个流程

例子:

xcy@xcy-virtual-machine:~/shell/21zhang$ cat data1.txt this is the header line this is a data line this is the last line xcy@xcy-virtual-machine:~/shell/21zhang$ sed '/header/{n;d}' data1.txt this is the header line this is a data line this is the last line xcy@xcy-virtual-machine:~/shell/21zhang$

 data1.txt有两个空行,想删掉第一个空行,也就是在header行下一行的空行。

如果这样: $sed ‘/^$/d’ data1.txt    // 这样会把两个空行都删掉。

上面的例子中,先找到包含header的那行,然后n命令会让sed编辑器移动到文本的下一行,就是第一个空行。这时sed编辑器会继续执行命令列表,用d来删掉那行。

2. 合并文本行(多行版本的next)

单行next命令会将数据流中的下一文本行移动到sed编辑器的工作空间(称为模式空间)

多行版本的next命令(N)会将下一行添加到模式空间中已有的文本后。

例子1:

xcy@xcy-virtual-machine:~/shell/21zhang$ cat data2.txt This is line 1 This is line 2 This is line 3 This is line 4 This is line 5 xcy@xcy-virtual-machine:~/shell/21zhang$ sed  '/line 1/{N; s/\n/ /}' data2.txt This is line 1 This is line 2 This is line 3 This is line 4 This is line 5 xcy@xcy-virtual-machine:~/shell/21zhang$ sed -n '/line 1/{N; p}' data2.txt This is line 1 This is line 2 xcy@xcy-virtual-machine:~/shell/21zhang$

说明:第一个先找到line 1行,再读取下一行,再把换行符替换成空格输出。

第二个找到line 1行,再读取下一行,最后一起输出。

例子2:

xcy@xcy-virtual-machine:~/shell/21zhang$ cat data3.txt on Tuesday,the linux System Admin's group meeting will be held. All System Admin should attend Tks for your attendance xcy@xcy-virtual-machine:~/shell/21zhang$ sed 's/System.Admin/Desktop user/' data3.txt on Tuesday,the linux System Admin's group meeting will be held. All Desktop user should attend Tks for your attendance xcy@xcy-virtual-machine:~/shell/21zhang$ sed 'N;s/System.Admin/Desktop user/' data3.txt on Tuesday,the linux Desktop user's group meeting will be held. All Desktop user should attend Tks for your attendance xcy@xcy-virtual-machine:~/shell/21zhang$

说明:第一次执行的命令直接替换,System Admin中间的点号是通配符模式(匹配空格和换行符)。这里无法替换第一行的System Admin。

第二次执行的,可以替换掉第一个System Admin。但是存在问题:当点号匹配到了换行符时就把换行符删掉了,这两行就合并在了一起。

要注意N命令的顺序。

网上看的别人的帖子评论(便于理解):

来源:https://www.cnblogs.com/fhefh/archive/2011/11/14/2248942.html

1)sed正常情况下处理顺序是这样:

读取一行到模式空间-》在模式空间中执行命令-》打印模式空间中的内容,清空模式空间-》读取下一行-》 …… -》直到文件结束。

但是有时脚本中某个命令被执行会希望模式空间能保留下来,以便下一次使用。这个时候n  N命令的作用就来了。

2)命令n:读取下一行到模式空间,这时模式空间有两行内容了。但是先读取的那行不会被取代、覆盖或删除。

当n命令后,还有其他命令p的时候,此时打印的结果是n命令读取的那一行

3)命令N:将下一行添加到模式空间中去。将当前读入行和用N命令添加的下一行看成“一行”

例子:

xcy@xcy-virtual-machine:~/shell/21zhang$ cat data2.txt This is line 1 This is line 2 This is line 3 This is line 4 This is line 5 xcy@xcy-virtual-machine:~/shell/21zhang$ sed -n 'n; /line 2/p' data2.txt This is line 2  # n命令读取的是这行 xcy@xcy-virtual-machine:~/shell/21zhang$ sed -n 'N; /line 2/p' data2.txt This is line 1  # 当前读入行 This is line 2  # N命令读入行, 看成一行 xcy@xcy-virtual-machine:~/shell/21zhang$

4)帖子下面的评论:

不管是n还是N,都不能改变sed每次只处理一行的规定。

用n时,把下一行读到模式空间,实际上只处理第2行,不理会第一行。

用N时,也是把下一行读到模式空间,但是在这里已经只对第一行进行处理,而不理会第二行。

我的观点:我觉得上面斜体部分好像有点问题,应该是把两行当做一个整体了,肯定也会处理第二行的。

21.1.2 多行删除命令

单行删除命令d

多行删除命令D

1.$sed ‘N; /System\nAdim/d’ data.txt

data.txt内容如下:

xxxx xxxx System

Adim xxx

xxx

那么上面的命令会把前两行都删掉。

2. D命令:它只删除模式空间中的第一行,该命令会删除到换行符(含换行符)为止的所有字符

例子:

xcy@xcy-virtual-machine:~/shell/21zhang$ cat data5.txt this is header line this is second line this is last line xcy@xcy-virtual-machine:~/shell/21zhang$ sed '/^$/{N; /header/D}' data5.txt this is header line this is second line this is last line xcy@xcy-virtual-machine:~/shell/21zhang$

为了删除第一个空行,保留第二个空行。

上述命令会先查找空白行,然后用N命令将下一文本添加到模式空间。

假如新的模式空间中有header,那么删除模式空间中的第一行。

21.1.3 多行打印命令P

单行打印命令p(小写):会打印模式空间中的所有行

多行打印命令P(大写):会打印模式空间中的第一行

例子:

xcy@xcy-virtual-machine:~/shell/21zhang$ sed -n 'N; /header/p' data5.txt this is header line xcy@xcy-virtual-machine:~/shell/21zhang$ sed -n 'N; /header/P' data5.txt xcy@xcy-virtual-machine:~/shell/21zhang$

说明:第一个是单行打印,第二个是多行打印(只打印模式空间的第一行)

这里要去理解模式空间的概念。

21.2 保持空间

1.模式空间(pattern space)是一块活跃的缓冲区,在sed编辑器上执行命令时它会保存待检查的文本,但它并不是sed编辑器保存文本的唯一区间。

还有另外一块缓冲区,叫保持空间(hold space)。在处理模式空间中的某些行时,可以用保持空间来临时保存一些行。

有5条命令可以来操作保持空间:

命令

描述

h

将模式空间复制到保持空间

H

将模式空间附加到保持空间

g

将保持空间复制到模式空间

G

将保持空间附加到模式空间

x

交换模式空间和保持空间的内容

2.通常用了h或H将字符串移动到保持空间时,最终还要用g,G或x命令将保存的字符串移回到模式空间(否则,你就不用在一开始考虑保存它们了)。

3.例子:

xcy@xcy-virtual-machine:~/shell/21zhang$ cat data2.txt This is line 1 This is line 2 This is line 3 This is line 4 This is line 5 xcy@xcy-virtual-machine:~/shell/21zhang$ sed -n '/line 1/ {h;p;n;p;g;p}' data2.txt This is line 1 This is line 2 This is line 1 xcy@xcy-virtual-machine:~/shell/21zhang$

说明:

1)先找含有line 1 是行

2)把那行读进保持空间

3)打印模式空间中的内容

4)n命令读取数据流中的下一行(line 2),并放到模式空间中去。

5)打印模式空间中的内容(第2行)

6)将保持空间的内容复制到模式空间,会替换之前的模式空间的内容

7)打印模式空间中的内容,就是(line 1)

这样可以将整个文件的文本行反转

21.3 排除命令

可以配置命令使其不要作用到数据流中的特定地址或地址区间

感叹号(!)命令用来排除命令,也就是让原本会起作用的命令不起作用。

例子:

$sed –n ‘/line 2/!p’ data2.txt   // 包含line 2的行不打印,其他的打印

还可以这样:

$sed ‘$!N > s/System\nAdmin/Desktop\nUser/ > s/System Admin/Desktop User/ > ’ data.txt

假如data.txt的最后一行有System Admin,分两种情况分析:

1)如果仅仅是$sed ‘N ……’。这样,那么最后一行的System Admin就替换不了。因为读取最后一行时,还会运行N命令,但是却没有下一行了。所以就不执行下面的了。也就不会进行替换了。

2)如果是上面那么写,表示读取最后一行时不运行N命令了,(也就是不读下一行了)(但是对其他行都执行了N命令)。这样就还会运行后面的命令,也就可以提换到了。

实例:将文本翻转输出

不需要将保持空间文本附加要处理的第一行文本后面。可以用感叹号实现。 1!G

$sed -n ‘{1!G;h;$p}’ data2.txt

说明:

读取第一行时不执行G命令,

读取到最后一行时才去执行p,p去打印模式空间的内容。

如果没有$,表示每读取一行都会执行p,每次都会打印模式空间的内容。就像下面的例子一样。

循环1执行了h命令。

循环2执行了G h命令。

循环3执行了G h命令。

循环4执行了G h命令。

循环5执行了G h p命令。

$sed ‘1!G; h; $1d’ data2.txt

这个也可以实现类似的效果

备注:linux下的翻转命令tac。(正好跟cat相反)

21.4 改变流

通常,sed编辑器会从脚本的顶部开始,一直执行到脚本的结尾(D命令例外,它会强制sed编辑器返回到脚本的顶部,而不读取新的行)。

sed编辑器提供了一个方法来改变命令脚本的执行流程,其结果与结构化编程类似。

21.4.1 分支

sed编辑器提供了一种方法可以基于地址、地址模式或地址区间排除一整块命令。这允许你只对数据流中的特定行执行一组命令

分支(branch)命令b格式如下:

[address]b [label]

address决定了哪些行的数据会触发分支命令

label参数定义了要跳转到的位置。

例子:

$sed ‘{2,3b; s/line/new_line/}’ data.txt

分支命令在数据流中的第2行和第3行跳过了替换命令。其他行会执行替换命令。

要是不想跳到脚本的结尾,可以为分支命令定义一个要跳转的标签。

标签以冒号开始,最多七个字符长度。

实例:

1)说明:第一行跳到jump1。第2行开始不跳了。顺序执行命令

xcy@xcy-virtual-machine:~/shell/21zhang$ sed '{/line 1/b jump1; s/line/new li22ne/; :jump1 s/line/line_jump/}' data2.txt This is line_jump 1 This is new li22ne 2 This is new li22ne 3 This is new li22ne 4 This is new li22ne 5

2)第2 行,先进行第一个替换,再接着进行第二个替换。

xcy@xcy-virtual-machine:~/shell/21zhang$ sed '{/line 1/b jump1; s/line/new line/; :jump1 s/line/line_jump/}' data2.txt This is line_jump 1 This is new line_jump 2 This is new line_jump 3 This is new line_jump 4 This is new line_jump 5 xcy@xcy-virtual-machine:~/shell/21zhang$

实例2:

xcy@xcy-virtual-machine:~/shell/21zhang$ echo "This, is, a, cat," | sed -n '{s/,//p}' #只替换一个 This is, a, cat, xcy@xcy-virtual-machine:~/shell/21zhang$ echo "This, is, a, cat," | sed -n '{s/,//gp}' # 全部替换 This is a cat # 下面的例子中要找到逗号才会跳转。如果没有这个会一直循环下去 xcy@xcy-virtual-machine:~/shell/21zhang$ echo "This, is, a, cat," | sed '{:start s/,//1p; /,/b start}' This is, a, cat, This is a, cat, This is a cat, This is a cat This is a cat xcy@xcy-virtual-machine:~/shell/21zhang$

21.4.2 测试

测试(test)命令(t)也可以用来改变sed编辑器脚本的执行流程。

测试命令会根据替换命令的结果跳转到某个标签,而不是根据地址跳转。

格式:

[address] t [label]

实例:

xcy@xcy-virtual-machine:~/shell/21zhang$ cat data2.txt This is line 1 This is line 2 This is line 3 This is line 4 This is line 5 xcy@xcy-virtual-machine:~/shell/21zhang$ sed 's/line 1/line one/; t xcy; s/line/new_line/; :xcy s/This/This222/' data2.txt This222 is line one This222 is new_line 2 This222 is new_line 3 This222 is new_line 4 This222 is new_line 5 xcy@xcy-virtual-machine:~/shell/21zhang$

如果匹配了line 1。就把line 1换成line one。然后跳到标签xcy。进行This 替换。

第2行匹配不了line 1。不跳转,直接将line 换成new_line。

21.5 模式替代

比如有这个需求:把所有*at 的单词都加上双引号

$echo “The cat is hat, bat” | sed ‘s/.at/”.at”’

这样会全部换成”.at”。不会把cat变成”cat”。 不会把hat变成”hat”。

21.5.1 &符号

&符号可以用来代替替换命令中的匹配的模式。不管模式匹配的是什么样的文本。

比如:

$echo “The cat is hat, bat” | sed ‘s/.at/”&”’

当匹配到cat时,&就变成了cat

当匹配到hat时,&就变成了hat。

21.5.2 替代单独的单词

有时需要提取这个字符串的一部分。

sed编辑器用圆括号来定义替换模式中的子模式。你可以在替代模式中使用特殊字符来引用每个子模式。

替代字符由反斜线和数字组成,\1  \2  \3  等,数字表明子模式的位置。

sed编辑器会给第一个子模式分配字符\1,第二个子模式分配\2,以此类推。

比如:

将cat is替换成cat are。后面那个is就不会替换。

cat是一个子模式。\1用来提取它。

xcy@xcy-virtual-machine:~/shell/21zhang$ echo "The cat is hat is" | sed 's/\(cat\) is/\1 are/' The cat are hat is xcy@xcy-virtual-machine:~/shell/21zhang$

还可以用一个单词替换一个短语:

将.at看成一个子模式,这样就把furry删除了。

$ echo "That furry cat is pretty" | sed 's/furry \(.at\)/\1/' That cat is pretty $ echo "That furry hat is pretty" | sed 's/furry \(.at\)/\1/' That hat is pretty

实例:

$ echo "12345678" | sed '{:start s/\(.*[0-9]\)\([0-9]\{3\}\)/\1,\2/; t start}'

12,345,678

第一个子模式是以数字结尾的任意长度的字符

第二个子模式是若干组三位数字。

第一次先匹配到了12345 678,然后插入一个,

第二次匹配到了12 345,678,然后插入一个逗号

第三次匹配不到了

21.6 在脚本中使用sed

21.6.1 使用包装脚本

可以将sed编辑器命令放到shell包装脚本中。包装脚本充当着sed编辑器和命令行之间的中间人角色。

例子:

之前那个将文本翻转的例子:

xcy@xcy-virtual-machine:~/shell/21zhang$ cat tac.sh #!/bin/bash sed -n '1!G;h;$p' $1 xcy@xcy-virtual-machine:~/shell/21zhang$ ./tac.sh data2.txt This is line 5 This is line 4 This is line 3 This is line 2 This is line 1 xcy@xcy-virtual-machine:~/shell/21zhang$

21.6.2 重定向sed的输出

默认情况下sed编辑器的输出到STDOUT上。可以在shell脚本找那个使用各种标准方法对sed编辑器的输出进行重定向。

例子:对数值计算的结果加上逗号

  1 #!/bin/bash   2 factorial=1   3 counter=1   4 number=$1   5   6 while [ $counter -le $number ]   7 do   8         factorial=$[ $factorial * $counter ]   9         counter=$[ $counter + 1 ]  10 done  11  12 result=$(echo $factorial | sed '{  13 :start  14 s/\(.*[0-9]\)\([0-9]\{3\}\)/\1,\2/  15 t start  16 }'  17 )  18  19 echo "the result = $result"

用法:$./fact.sh 20     // 求20的阶乘

21.7 创建sed实用工具

21.7.1 加倍行间距

sed ‘$!G’ data2.txt

每读取一行都会将保持空间追加到模式空间。只不过保持空间是一个空行而已。

最后一行就不需要追加了,最后一行不执行G 命令。

21.7.2 对可能含有空白行的文件加倍行间距

假如本来有空行,则不加(否则会出现两个空行)。

方法就是先删除空行,再加空行

$sed ‘/^$/d; $!G’ fact.sh

21.7.3 给文件中的行编号(等号=)

用=号:

sed ‘=’ data2.txt

这样的结果很丑。

下面这个好看点:

$sed ‘=’ data2.txt | sed ‘N; s/\n/: /’

把换行符换成冒号空格。

有一些其他命令也可以加行号:

$nl data2.txt

$cat –n data2.txt

21.7.4 打印末尾行

$代表数据流中的最后一行

$sed –n ‘$p’ data2.txt

如何用美元符显示数据流末尾的若干行呢?答案是创建滚动窗口

N命令将下一行文本附加到模式空间中已有的文本行后面。

D命令会删除模式空间的第一行

例子:显示最后5行,注意下面的6:

xcy@xcy-virtual-machine:~/shell/21zhang$ cat print.sh #!/bin/bash sed '{ :start $q; N; 6,$D b start }' $1 xcy@xcy-virtual-machine:~/shell/21zhang$ ./print.sh data3.txt This is line 6 This is line 7 This is line 8 This is line 9 This is line 10 xcy@xcy-virtual-machine:~/shell/21zhang$

分析:

1)如果是最后一行则退出

2)N命令将下一行附加到模式空间中的当前行之后

3)如果是在第6到结尾行,就删除模式空间中的第一行。

21.7.5 删除行

1、删除连续的空白行

无论文件的数据行之间有多少个空白行,在输出中只会保留一个空白行。

关键在于创建包含一个非空白行和一个空白行的区间。如果遇到了这个区间,就不删除。对于不匹配这个区间(两个或者更多的空行)的行则删除。

$sed ‘/./,/^$/!d’ data2.txt

区间就是/./ 到 /^$/。开始会匹配包含至少一个字符的行。区间的结束是空行。

2.删除开头的空白行

也是用区间删除

$sed ‘/./,$!d’ data.txt

3. 删除结尾的空白行

例子:

xcy@xcy-virtual-machine:~/shell/21zhang$ cat data2.txt This is line 1 This is line 2 This is line 3 This is line 4 xcy@xcy-virtual-machine:~/shell/21zhang$ sed -n '/^\n*$/p' data2.txt xcy@xcy-virtual-machine:~/shell/21zhang$ sed '{:start /^\n*$/ {$d; N; b start}}' data2.txt This is line 1 This is line 2 This is line 3 This is line 4 xcy@xcy-virtual-machine:~/shell/21zhang$

地址模式能够匹配只含有一个换行符的行。如果找到了这样的行,而且还是最后一行,删除命令会删掉它。如果不是最后一行,N命令会将下一行附加到它的后面,分支命令跳到循环起始位置重新开始。

21.7.6 删除HTML标签

xcy@xcy-virtual-machine:~/shell/21zhang$ cat data.txt <html> <title>This is the page </title> hahah, my name is xcy Are you ok? I am fine, and you? </html>

内容如上,下面分三步进行分析:

1.先删除以<开头, >结尾的且有数据的文本字符串

$sed ‘s/<.*>//g’ data.txt

2.上面的第2行不能被删掉了。解决方法是让sed编辑器忽略任何嵌入到原始标签中的大于号。可以创建一个字符组来排除大于号。 <>中间不能有>。否则不删除。

$sed ‘s/<[^>]*>//g’ data.txt

3. 删除多余空行

$sed ‘s/<[^>]*>//g; /^$/d’ data.txt

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017-12-08 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 21.1 多行命令
    • 21.1.1 next命令
      • 21.1.2 多行删除命令
        • 21.1.3 多行打印命令P
        • 21.2 保持空间
        • 21.3 排除命令
        • 21.4 改变流
          • 21.4.1 分支
            • 21.4.2 测试
            • 21.5 模式替代
              • 21.5.1 &符号
                • 21.5.2 替代单独的单词
                • 21.6 在脚本中使用sed
                  • 21.6.1 使用包装脚本
                    • 21.6.2 重定向sed的输出
                    • 21.7 创建sed实用工具
                      • 21.7.1 加倍行间距
                        • 21.7.2 对可能含有空白行的文件加倍行间距
                          • 21.7.3 给文件中的行编号(等号=)
                            • 21.7.4 打印末尾行
                              • 21.7.5 删除行
                                • 21.7.6 删除HTML标签
                                领券
                                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档