zoukankan      html  css  js  c++  java
  • 世界上最好的Sed教程

    这是一份世界上最好的sed教程,sed是unix系统下流编辑里的超人。最初我写这份说明是为了我的
    第二本电子书,然而随后我决定把这份说明变成一本免费电子书预览的同时再次做为文章发布到这里。

    Sed说明

    掌握sed可以简化为理解和操作sed的四种空间,这四种空间分别为:

    • 输入流
    • 模式空间
    • 保持空间
    • 输出流

    可以这样去想像空间这个词,sed读入输入流和产生输入流,在内部它有模式空间和保持空间。sed从输入流读入数据直到它读到换行字符(\n),然后它把当前读到的数据(不包含新行字符)放入模式空间。大部分的sed命令在模式空间操作读入的数据。保持空间的存在是为了方便操作,可以把它想像成一个你可以在模式空间和保持空间之间复制和交换数据的临时缓冲。当sed执行完所有的命令后,它输出模式空间的内容并在结尾加上一个换行符(\n).

    可以使用-n选项去修改sed的行为。当使用-n选项的时候,sed不输出模式空间,你必须使用p或P命令明确指定打印。
    让我们通过一些实例来理解这四种空间和sed。这些仅仅是一些描述sed看起来像什么 和它是什么的例子。

    以下可能是最简单的sed程序

    sed ‘s/foo/bar/’
    

    这个程序在每一行上将文本foo替换为文本bar。它的工作方式是这样的,考虑你有一个包含这些行的文件:

    abc
    foo
    123-foo-456
    

    sed打开这个文件作为输入流,并开始读入这个文件。当它读abc的时候发现一个新行字符(\n), 它就把abc放入模式空间并应用s/foo/bar命令,因为在模式空间的文本字符是“abc”,没有文本字符“foo”,sed不对模式空间做任何操作。 此刻,sed已经执行完了所有的命令(此例中仅仅只有一个命令),当所有的命令执行完的默认动作是打印模式空间和新行字符(\n),所以第一行的输出是“abc\n”

    现在sed读第二行到模式空间,执行s/foo/bar. 这将会用foo替代bar,模式空间里就只包含“bar”, 到达命令的结尾,然后sed打印模式空间的内容,跟着是新行字符(\n). 第二行输出为“bar\n”

    现在读入第三行的内容,模式空间的内容为“123-foo-456”, 因为文本“123-foo-456里含 有foo”,命令“s/foo/bar执行成功,模式空间里的内容就变为“123-bar-456”,到达命令的结尾,然后sed打印模式空间的内容。输出为“123-bar-456\n”

    此刻文件所有的行已经读入处理然后sed退出。示例脚本的输出为

    abc
    bar
    123-bar-456
    

    因为不需要临时存储这个例子里没有用到保持缓冲空间

    在看有临时存储的例子之前,让我们来看一看三个命令行开关:-n,-e和-i。首先是-n

    如果对sed指明-n选项,如下:

    [kennminn@bogon Script]$ sed -n 's/foo/bar/' t1.txt
    

    然后当执行完脚本时sed将不会打印模式空间的内容。所以如果你对上面的示例文件执行这个程序,将不会有输出。你必须使用sed的p命令强制打印空间的内容。

    [kennminn@bogon Script]$ sed -n 's/foo/bar/;p' t1.txt
    abc
    bar
    123-bar-456
    

    你可以看到,sed命令以分号(;)分隔。你也可以使用-e选项来分隔命令:

    
    [kennminn@bogon Script]$ sed -n -e 's/foo/bar/' -e 'p' t1.txt
    abc
    bar
    123-bar-456
    

    它和你使用分号(;)分隔是一样的效果,接下来,让我们看一看-i这个命令行选项。这个命令强制sed原位置修改目标文件。意味着它会读取这个文件内容,执行sed命令,然后把新的内容放回到文件。
    这里有一个例子,考虑你有一个文件叫做“users”,它里面有以下内容

    pkrumins:hacker
    esr:guru
    rms:geek
    

    你希望将整个文件中的“:”以“;”替换。你可以这样简单的处理:

    [kennminn@bogon Script]$ sed -i 's/:/;/' users.txt
    pkrumings;hacker
    esr;guru
    rms;geek
    

    它将静静的在文件中所有行上执行‘s/;/’命令并执行所有的替换操作。当使用-i选项的时候请务必小心,因为它是破坏性的且不可逆。通常,安全的做法是执行不带-i选项的sed命令,然后自己手动替换原始文件。
    另一种方法就是你可以通过-i选项指定文件的扩展名,这种方式sed命令会在你替换原始文件前对原始文件进行备份。

    例如,你可以指明‘-i.bak’,如下:

    [kennminn@bogon Script]$ sed -i.bak 's/:/;/' users 
    [kennminn@bogon Script]$ cat users
    pkrumings;hacker
    esr;guru
    rms;geek
    [kennminn@bogon Script]$ ls -l
    -rw-rw-r--. 1 kennminn kennminn   35 4月  19 13:32 users
    -rw-rw-r--. 1 kennminn kennminn   35 4月  19 13:21 users.bak
    

    sed命令会在你修改users文件内容之前生成users.bak备份文件。

    实际上,在我们观注保持缓冲之前,让我们先看一看地址和范围。地址允许你限制sed只对特定行或行的范围执行sed命令。

    最简单的地址是单独的一个数字,限制sed只对特定的行执行sed命令。

    sed '5s/foo/bar/'
    

    这将限制只对文件或输入流的第5行执行‘s/foo/boo/‘命令。所以如果在文件的第5行存在“foo”,它将被替换为“bar”,其他的行不会执行。

    这个地址可以用!号来执行取反的效果。匹配除了第5行的所有行(如1-4行,行6)操作如下:

    sed ‘5!s/foo/bar/‘
    

    取反操作可以应用到任意的行地址

    接下来,你也可以通过指定两个用逗号分隔的数字来限制sed命令只对一定范围的行执行。

    sed ‘5,10s/foo/bar/‘
    

    在上面这行程序,‘s/foo/bar/‘命令仅仅只对文件包含的5-10执行。这是一个快速,有用的指令。,假如你想打印这个文件的5-10行,首先可以用-n选项来禁用默认打印然后用-p命令来打印文件的5-10行。

    sed –n ‘5,10p‘
    

    这将在文件的5-10行执行p命令。5-10行以外的其他行将不会输出。相当整洁,不是吗?有一个特殊的地址符号“$”匹配文件的末尾行。这里有一个打印文件的最后一行的例子

    sed –n ‘$p’
    

    如你所见,p命令已经被限制到了$,也就是输入文件的最后一行。

    也有一种用单独的正则表达式匹配的地址,像/regex/这样。如果你在sed命令前指定一个正则,然后仅仅只有正则匹配的行才会执行sed命令。看一下这个:

    sed –n ‘/a\+b\+/p’
    

    这里,只有匹配正则表达a+b+的行才会执行p命令,a+\b+表示一个或多个a后紧接着一个或多个b。例如,它打印包含像”ab”,”aab“,“aaabbb“,”foo-123-ab”等等这样的行。记住”+“如何被转义。因为sed默认使用基本正则表达式。你可以过通-r选项来启用扩展的正则表达式语法。

    sed –rn ‘/a+b+/p’
    

    这种方式下你不需要像+,(,)这样去引用元字符。

    也可以用一个表达式去匹配两个正则之前的一个范围,例如:

    sed ‘/foo/,/bar/d‘
    

    这一行命令匹配正则表达式“/foo/“第一次匹配所在行到正则表达式”/bar/”第一次匹配所在行之间所有的行。d命令代表删除。换句话说就是,表达式“/foo/“第一次匹配所在行到正则表达式”/bar/”第一次匹配所在行之间所有的行都将被删除。

    现在,让我们来看看保持缓冲区。假如你有这样一个问题:您希望打印正则表达所匹配行之前的行。你如何来处理,如果没有保持缓冲区,事情将变得很复杂,但是利用保持缓冲区我们总是可以将当前行保存到保持缓冲区,然后让sed读入下一行,如果下一行匹配正则,我们将可以只打印保持缓冲区,这里仅仅保存着正则匹配之前的行,不是吗?

    拷贝当前模式空间内容到保持缓冲区的命令是h。将保持缓冲区的内容拷贝回模式空间的全集是g。交换保持缓冲区和模式空间内容的全集是x,我们只需要选择合适的命令来解决这个问题。解决方法如下:

    sed –n ‘/regex/{x;p;x};h‘
    

    它是这样起作用的-在脚本的末尾通过p命令每一行被复制到保持缓冲区,然而,对于匹配/regex/的每行,通过x命令我们交换保持缓冲区和模式空间的内容,用p命令打印它,然后将保持缓冲交换回来。所以,如果下一行再次匹配/regex/正则,我们可以打印当前行。

    同时请留意命令组,多条命令可以编组并仅对特定的行或地址范围执行。在上面程序中,命令的编组是{x;p;x},仅仅只有当前行匹配/regex/时才执行。

    注意输入文件的第一行如果匹配/regex/,那么上面的程序无法工作。为了修复它,我们可以用1!取反来使p命令仅对除第一行以外的所有行执行。

    sed –n ‘/regex/{x;1!p;x};h’
    

    注意1!p, 这是说对除了第一行以外的所有行执行p命令。这将阻止如果第一行匹配正则/regex/时生产任何输出。

    好了,就是这些。我认为这份介绍解释了sed中最重要的观点,包括各种命令行选项,四种空间和各种sed命令。
    如果你希望了解更多,我建议你获取一份我写的名叫“sed-one-liners Explained“的电子书。这本电子书包含 了100个解释良好的小例子。一旦你理解了他们,你将会让你的大脑以sed的方式来思考。换句话说。你将学会如何操作模式空间,保持缓冲区空间,同时你将知道什么时候打印数据以得到你想要的结果。

    原文地址:http://www.catonmat.net/blog/worlds-best-introduction-to-sed/

    本人英文水平有限,如果问题,请多多指教。谢谢

    20170419

  • 相关阅读:
    什么是动态链接库
    <<TCP/IP高效编程>>读书笔记
    C++ 函数
    我的vim配置
    FastReport4.6程序员手册_翻译
    DUnit研究初步
    ADO BUG之'无法为更新定位行....' 解决之道
    极限编程的集成测试工具Dunit
    总结
    项目管理检查清单项目启动
  • 原文地址:https://www.cnblogs.com/minn/p/6781305.html
Copyright © 2011-2022 走看看