IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    玩玩Sed

    果冻想发表于 2015-09-19 17:34:26
    love 0

    态度是“玩”

    当你看到这篇文章时,你也许应该知道什么是Sed了,不知道的请自行Google。为什么说要“玩”Sed,而并不是“认真”的去学习呢?

    • 首先,工作需要,我目前工作环境是Unix和Linux,使用Sed命令可以很快的解决一些问题;
    • 其次,这东西自己也不是很熟悉,看到别人用的很顺,很是羡慕啊;
    • 最后,这个Sed的知识点还是很多的,技巧也蛮多的,但是我选择“浅尝辄止”,会用就好,毕竟只是一个小工具。

    大家都知道,在Unix和Linux下,各种命令的各种奇特技巧是数不胜数,Sed也不例外,而我这里只“玩”一些最基本的使用,而那些“高深”的技巧,就留在日后慢慢“打怪升级”吧。接下来就来说说我是如何“玩”Sed的。

    Sed初印象

    现在需要将下列文本中的SZ换成SH,看看Sed如何来完成这项工作。

    测试文件addressList内容:

    LiuDong, 203 King Road, BJ
    WuHai, 220 ShenNan Road, SZ
    LiuMei, 210 ShenNan Road, SZ
    WuLi, 12 HouHai, BJ
    Jack Chen, 765 Huhhot Road, NM
    BaoZhuzi, 452 XinHua Road, NM
    FengZhen, 309 XinHua Road, NM
    YiXin, 405 XiAn Road, SZ
    

    使用Sed只需一行命令就可以搞定。

    sed 's/SZ/SH/' addressList
    

    输出:

    LuDong, 203 King Road, BJ
    WuHai, 220 ShenNan Road, SH
    LiuMei, 210 ShenNan Road, SH
    WuLi, 12 HouHai, BJ
    Jack Chen, 765 Huhhot Road, NM
    BaoZhuzi, 452 XinHua Road, NM
    FengZhen, 309 XinHua Road, NM
    YiXin, 405 XiAn Road, SH
    

    可以看到,一行简单的命令就可以将字符串“SZ”替换成“SH”。先简单的说说那一行命令。sed表示执行sed命令,s/SZ/SH中s在Sed表示替换的意思,也就是说将SZ替换为SH,最后的就是文件名了。运行以后,将会直接输出运行结果,而原文件并不会被修改,如果你想直接修改原文件,你可以这样,使用-i选项:

    sed -i 's/SZ/SH/' addressList
    

    好了,这就是Sed,怎么样?

    小试牛刀

    很多时候,我们的脚本不可能向上面那么短,也不可能就只有简简单单的一个脚本,这个时候就需要将创建脚本文件了,然后对目标文件执行脚本文件即可。

    sed -f scriptfile file
    

    接下来就写一个最简单的Sed脚本。

    vi sedReplace
    

    输入一下内容:

    s/BJ/HN/    #将每一行找到的第一个BJ替换为HN
    s/SZ/AH,AH/ #将每一行的第一个SZ替换为AH,AH
    s/AH/NM/g   #将每一行上找到的所有AH替换为NM
    

    在命令行上输入:

    sed -f sedReplace addressList
    

    输出结果为:

    LuDong, 203 King Road, HN
    WuHai, 220 ShenNan Road, NM,NM
    LiuMei, 210 ShenNan Road, NM,NM
    WuLi, 12 HouHai, HN
    Jack Chen, 765 Huhhot Road, NM
    BaoZhuzi, 452 XinHua Road, NM
    FengZhen, 309 XinHua Road, NM
    YiXin, 405 XiAn Road, NM,NM
    

    你能想清楚为什么输出是这样的吗?如果不明白,接着看Sed的基本工作原理。

    Sed基本原理

    学习东西,就要学习原理的东西,只有原理搞明白了,万变不离其宗。现在就对Sed最基本的原理进行分析。

    Sed是一个流编辑器,何为流编辑器呢?就是指Sed每次只从文件读入一行,然后对该行进行处理,然后输出;接着读入下一行,直至整个文件被读取完;在此过程中,整个文件就好比流水一样,逐行被读入处理,然后再逐行输出。

    下面就用一副图来说说Sed的基本工作原理。

    Sed工作原理

    由于Sed是在那个PC内存只有几兆的年代开发出来的,所以Sed不会将待处理文档的所有内容一次性的读入内存,而是每次从待处理文件中读取一行到pattern space,然后对pattern space中的内容依次执行每一个命令,最后输出pattern space中的内容并清空pattern space。由此可见,Sed并不会对原文件进行任何修改(在没有加-i选项的情况下)。

    在上图中还有一个hold space我没有具体的说。当涉及到hold space时,都会是Sed的一些高级用法了,所以此处我不做总结,如有兴趣,可以参见这篇文章《Sed高级用法》。

    巧妇难为无米之炊

    现在你知道了Sed的原理,但是你还是无法痛快的写出Sed脚本。这就好比你知道米饭是用米来做的,但是你却没法用米做出米饭。就算你知道了所有的“大道理”,却不知晓最简单的命令,你依然寸步难行——巧妇难为无米之炊;所以,这一节我将重点总结Sed中的基本命令。

    先看看使用Sed命令的两种最基本的格式。

    • 直接命令行使用
      sed [options] 'sed_command' file(s)
      
    • 使用Sed脚本文件
      sed [options] -f sed_script file(s)
      

    关于常用的options请参见文章最后的附录部分。再来看看Sed中address的概念。

    在使用Sed命令或脚本处理文件时,在默认情况下,Sed会扫描待处理文件的每一行,然后进行处理;当然了,我们可以改变这种情况,可以指定一个address,只对特定行进行处理;现在问题来了,我们如何指定这个address呢?下面表格详细的列举了常用的指定address的几种方式。

    书写格式 说明 举例
    number 直接指定行号,只匹配特定行号,只对特定行进行操作 将第二行的SH换成NM:sed ’2s/SH/NM/’ addressList
    first~step first为起始行,step为递增量 只输入奇数行:sed -n ’1~2p’ addressList
    $ 匹配文件最后一行 打印文件最后一行:sed -n ‘$p’ addressList
    /regexp/ 正则表达式匹配对应的行 输出包含NM的行:sed -n ‘/NM/p’ addressList
    addr1,+N 匹配从 addr1 的行开始,直到下面的 N 行 输出2~5行:sed -n ’2,+3p’ addressList

    Sed中地址概念说完以后,再来看看Sed中最基本的增、删、改、查等这些基本的命令。

    命令 说明 举例
    s(替换命令) 格式:[address1[,address2]]s/pattern/replacement/flag;将pattern匹配的内容使用replacement进行替换;flag取值请参见附录中的FLAG常用取值 sed -r “2,3s/TH|YD/JT/2″ 201509.log
    d(删除命令) 格式:[address1[,address2]]d sed ‘/TH/d’ 201509.log
    a(追加命令) 格式:[address]a text,在匹配行的下面追加一行 sed ‘a HG’ 201509.log
    i(插入命令) 格式:[address]i text,在匹配行的前面追加一行 sed ‘i HG’ 201509.log
    c(更改命令) 格式:[address1[,address2]]c text,用text来替代(改变)由地址选定的行。当指定的是一个行范围时,将所有这些行作为一个组并用text取代。 sed ’1,2c XG’ 201509.log

    总结

    你可以在吃早点的间隙、挤地铁的间隙、坐马桶的间隙、又或撸啊撸的间隙,拿起手机看看这篇文章。总之,这是一篇让你Get一项新技能,而又不费时的文章。最后奉上Sed的官方文档,你现在需要的是行动。

    2015年9月20日 于呼和浩特。

    附录

    常用命令选项总结

    选项 说明
    -i[suffix] 直接将修改写入原文件;如果提供了SUFFIX,则对原文件file先进行备份,例如:sed -i_bak.20150919 ‘cmd’ file1 会先生成file1_bak.20150919这个内容与文件file1一模一样的文件,然后再对file1文件进行更改
    -e 使用多个Sed指令;如果有多个Sed指令需要执行,而又不想写Sed脚本,就可以使用该选项。例如:sed -e ‘cmd1′ -e ‘cmd2′ … -e ‘cmdN’ file(s)
    -n 禁用默认输出;在默认情况下,Sed会将输入内容的每行都输出,-n可以禁用默认输出。通常和p 命令一起使用,只输出pattern space中改变了的行
    -r 可以使用GNU扩展的正则表达式,在一些古董机器上非常有用

    FLAG常用取值总结

    flag 说明
    n 1~512之间的一个数字,表示对匹配模式的每行中第n次出现的情况进行替换
    g 全局替换;没有g时,只对第一次出现的匹配进行替换
    p 打印pattern space中的命令,经常和-n搭配使用

    Pattern Space和Hold Space互相操作命令总结

    命令 说明
    h 将当前Pattern Space中的内容复制到Hold Space,Hold Space原来的内容被清除
    H 将一个换行符 + Pattern Space的内容追加到Hold Space,即使Hold Space为空,H命令也会添加换行符
    g 将Hold Space中的内容复制到Pattern Space,Pattern Space中原来的内容被清除
    G 将一个换行符 + Hold Space中的内容追加到Pattern Space,如果Hold Space 的内容为空,则相当于只追加了一个换行符


沪ICP备19023445号-2号
友情链接