GNU sed 4.5 版参考文档全文翻译 各命令和随带20个示例详细解析(九)

12 篇文章 2 订阅

GNU sed 一个流编辑器(九)

—— 版本 4.5,2018年3月30日

作者:Ken Pizzini, Paolo Bonzini
译者:浙江省杭州市 Samuel        

标签:Linux sed 4.5版本 帮助文档 参考文档 全文翻译 随带20个示例 详细解析

版权声明:本文为博主原创译文,未经博主允许不得转载。https://blog.csdn.net/qq_39785418/article/details/90295373

7、 20个脚本示例

7.7 跨多行文本搜索

  本节使用N和D命令搜索跨越多行的连续出现两次的单词。参见6.3节[多行技术]。
这些示例涉及在一个文档中查找连续出现两次的单词。

  使用GNU grep和简单利用GNU sed查找一行中连续出现两次的同一个单词是容易的:

$ cat two-cities-dup1.txt
It was the best of times,
it was the worst of times,
it was the the age of wisdom,
it was the age of foolishness,

$ grep -E '\b(\w+)\s+\1\b' two-cities-dup1.txt 
it was the the age of wisdom,

  (译者:选项“-E”表示启用扩展正则表达式,两个“\b”分别表示单词的前后边界,“\w+”表示由大小写52个字母、10个数字和下划线组成的单词字符集其中的一个或多个组成的单词,“\s+”表示一个或多个空白字符,“\1”表示反向引用前面的圆括号包围的单词。 )

$ grep -n -E '\b(\w+)\s+\1\b' two-cities-dup1.txt
3:it was the the age of wisdom,
(译者:选项“-n”表示显示行号)
$ sed -En '/\b(\w+)\s+\1\b/p' two-cities-dup1.txt
it was the the age of wisdom,
$ sed -En '/\b(\w+)\s+\1\b/{=;p}' two-cities-dup1.txt
3
it was the the age of wisdom,

  (译者:“=”会打印行号并换行。)

  由于grep和sed都是一行一行操作的,所以,当连续出现两次的单词跨越两行时,上面的正则表达式不能起作用。

  通过使用N和D命令,sed支持正则表达式运用在多行上。(也就是,把多行都保存在模式空间中,正则表达式可以匹配它们):

$ cat two-cities-dup2.txt
It was the best of times, it was the
worst of times, it was the
the age of wisdom,
it was the age of foolishness,

$ sed -En 'N; /\b(\w+)\s+\1\b/{=; p}; D' two-cities-dup2.txt 
3
worst of times, it was the
the age of wisdom,

  (译者: N是next[下一行]的缩写,大写的N命令的作用是确保模式空间中有一行以上,行与行之间以一个换行符分隔。本脚本使用了D命令只删除模式空间的文本直到第一个换行符(含)为止,还有部分遗留在模式空间中,不会是空的。这样,下一轮循环开始后,只在执行N命令时才会读入下一输入行并追加到模式空间中;如果把D换成d命令——清空模式空间立即进行下一轮循环;或者第一次循环时,会先读入一行,遇到N还会再读一行。

  1、sed开始后先读取第一输入行“It was the best of times, it was the”,执行N命令在模式空间中追加一个换行符和读取的第二输入行;此时空间中是“It was the best of times, it was the\nworst of times, it was the”;由于没有匹配到连续出现两次的单词,注意换行符“\n”是单词边界,所以跳过花括号包围的命令组;执行D命令,删除模式空间至第一个换行符(含)为止,成“worst of times, it was the”;

  2、开始第二次循环,遇到N命令,读入第三行,由于模式空间已有一行,就追加一换行符和该行,成“worst of times, it was the\nthe age of wisdom,”由于能匹配正则表达式,所以执行“=”命令,打印行号,3并换行;然后p打印模式空间所有内容;执行D命令,删除模式空间至第一个换行符(含)为止,成“the age of wisdom,”;

  3、开始第三次循环,读入第四行,……。

7.8 调整行长度

  上节使用N和D命令搜索跨越多行的连续出现两次的单词,且b命令用于分支跳转。参见6.3节[多行技术]和6.4节[分支和流程控制]。

  这个示例处理以下输入文件,使文本在第40个字符后自动换行:

$ cat wrap40.sed
#!/usr/bin/sed -f
# wrap40.sed
# 外部循环
:x

    # 添加一个换行符和下一输入行到模式空间 
    N   
        
    # 把模式空间中的换行符替换成一个空格
    s/\n/ /g
        
    # 内部循环
    :y  
        
        # 如果匹配这个表达式,说明模式空间的文本长度超过了
        # 40个字符,并在第40个字符后面添加一个换行符
        # 否则,不会替换,模式空间中没有换行符
        s/\(.\{40,40\}\)/\1\n/
        
        # 如果模式空间中有一个换行符,则执行以下命令组:
        /\n/ {
            # P命令打印模式空间至第一个换行符为止(含)。
            P 
            # 把P命令打印过的内容删除
            s/.*\n// 
            # 无条件分支跳转到标签y位置————重复内部循环
            by  
        }   
        
    # 如果模式空间中没有换行符,则无条件分支跳转到标签x位置,重复外部循环
    # 读取下一输入行,在没有开始下一轮循环下,直到N命令遇到数据文件结尾退出。
bx

$ chmod +x wrap40.sed
$ ./wrap40.sed two-cities-mix.txt
It was the best of times, it was the wor
st of times, it was the age of wisdom, i
t was the age of foolishness,

7.9 反转文件行

  该示例从一系列完全无用,但有趣的脚本开始,模仿各种UNIX命令,特别类似tac工作机制。
请注意,在GNU sed以外的实现中,此脚本可能比较容易导致内部缓冲区溢出的问题。

$ cat tac.sed
#!/usr/bin/sed -nf

# 逆转输入的所有行,例如,第一行变成最后一行,第二行变成倒数第二行,...

# G命令的作用是把一个换行符和保持空间的所有内容追加到模式空间中。
# 下面的代码表示,如果行号是1,不执行G命令;而从第2行开始执行。
1 ! G

# 如果当前行是最后一行,小写p命令打印所有内容。
$ p

# 用模式空间中的内容替换保持空间
h

$ chmod +x tac.sed
$ seq 3 | ./tac.sed
3
2
1

7.10 行编号

  这个脚本取代了’cat-n’;事实上,它的输出格式与GNU cat完全相同。

  当然,这是完全是无用的,原因有二个:第一,已经有人使用C语言做了一个。第二,下面的bash脚本可能具有同样的功能,且运行速度更快:

$cat cat-n.data
first line
second line
third line

$ sed = cat-n.data 
1
first line
2
second line
3
third line

  (译者:从上面的测试来看,第一个sed脚本的作用就是,打印行号、换行符和自动打印行数据。)

$ cat cat-n.sh
#!/bin/bash

# cat-n.sh

sed -e "=" $@ | sed -e '
    s/^/      /            # 在行开头插入六个空格
    N
    s/^ *\(......\)\n/\1  /
'

  (译者:第二个sed脚本中,第一个s命令就是在当前的行号的前面增加六个空格。N命令形成 “ 1\nfirst line”,成为以换行符分隔的六个空格行号和行数据。第二个s命令的作用就是用两个空格替换“\n”。它会匹配开头的部分空格、圆括号包围的包含行号的六个字符、“\n”。替换后,成 “ 1 first line”。自动打印内容并清空模式空间。开始下一轮循环…。

$./cat-n.sh cat-n.data   
     1  first line
     2  second line
     3  third line

  这个脚本的教学效果不如下面介绍的那么好。

  用于递增的算法使用两个缓冲区,因此该行将尽快打印,然后丢弃。将以是否需要进位进行数字拆分,要更改的数字进入模式缓冲区,而未更改的数字进入保持缓冲区;要更改的数字在后一个步骤中进行修改(使用y命令)。然后将下一行的行号组合并存储在保留空间中,以便在下一次迭代中使用。

#!/usr/bin/sed -nf

# 脚本开始后,模式空间含有第一读入行文本“first line”,保持空间为空。
# 如果不是第一轮循环,保持空间中已经有相应的行号了。
# x交换两个空间,当前内容保存到保持空间,模式空间第一次为空,其他有相应行号,
# 如果匹配地址为空,执行s命令后,在模式空间中有一个数字即行号1。
x
/^$/ s/^.*$/1/

# G命令把一个换行符和保持空间的文本追加到模式空间中,
# 例如“1\nfirst line”,h命令用该文本替换保持空间,此时两个空间内容一致。
G
h

# 按照行号前面插入6个空格,用2个空格替换行号后的换行符,格式化文本,
# 替换成功后,p打印文本,“      1  first line”,并清空模式空间。
s/^/      /
s/^ *\(......\)\n/\1  /p

# 下面的所有代码的作用是在现有的行号基层上递增1.
# g命令把保持空间中保存的内容替换模式空间,s命令把换行符及其后面的文本去除,
# 此时只留下了行号。如果表达式地址匹配到“行号的个位数字是1个或多个9”,
# 例如行号是9、99等。此时行号要递增1,则需要进位,s命令在行号前面插入一个0。
g
s/\n.*$//
/^9*$/ s/^/0/

# s命令搜索部分会匹配到行号中以任意一位非9的数字后跟0个或多个9结尾,
# 例如行号为“1299”,会匹配“299”,而“1”、“123”等会匹配到最后一位数字,
# 然后替换后,被匹配部分前面插入一个字符x,例如“1x299”、“x1”、“12x3”
s/.9*$/x&/

# h命令把改变后的文本替换保持空间,例如“1x299”、“1x”、“12x3
# s命令把文本中字符x及其前面的字符删除,只留下后面的数字,
# 例如1x299-->299、x1-->1、12x3-->3
# y替换命令会把所有数字都递增1,例如299-->300、1-->2、3-->4
# x命令交换两个空间,此时模式空间的文本例如1x299、x1、12x3,
# 而保持空间为300、2或4。
h
s/^.*x//
y/0123456789/1234567890/
x

# 把x及其后面的所有数字去掉,例如1x299-->1、x1-->空、12x3-->12
s/x.*$//

# G命令作用是合并两个空间的文本,只是两个数字文本之间有一个换行符分隔。
# 例如1\n300、\n2、12\n4。s命令删除这个换行符,成1300、2、124.
# h命令把这个行号保存在保持空间中,为下一轮循环使用。
G
s/\n//
h

$ chmod +x cat-n.sed
$ cat cat-n.data
first line
second line
third line
$ ./cat-n.sed cat-n.data 
     1  first line
     2  second line
     3  third line

7.11 非空行编号

  模拟“cat-b”,几乎与“cat-n”相同,我们只需选择要编号的行。

  这个脚本和前一个脚本相同的部分没有注释,以显示正确注释sed脚本有多么重要…。

#!/usr/bin/sed -nf

# 如果是空行,直接打印,然后跳转最后开始下一轮循环
/^$/ {
    p
    b
}

# Same as cat - n from now
x
/^$/ s/^.*$/1/
G
h
s/^/      /
s/^ *\(......\)\n/\1  /p
x
s/\n.*$//
/^9*$/ s/^/0/
s/.9*$/x&/
h
s/^.*x//
y/0123456789/1234567890/
x
s/x.*$//
G
s/\n//
h

  

[GNU sed 4.5 版参考文档全文翻译 各命令和随带20个示例详细解析(十)] (https://blog.csdn.net/qq_39785418/article/details/90295778)

  如果您觉得译文对您有帮助,不妨给个  微信打赏   翻译不易,各位的支持,能激发和鼓励我更大的热情。谢谢!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值