zoukankan      html  css  js  c++  java
  • Sed与Awk

    Sed与Awk

    使用sed

    调用sed有两种方法:在命令行上指定编辑指令,或者将它们放到一个文件中并提供这个文件的名字。

    sed命令行选项

    选项 描述
    -e 编辑随后的指令
    -f 跟随脚本中的文件名
    -n 阻止输入行的自动输出

    指定简单的指令

    可以在命令行上指定简单的编辑命令。

    sed [-e] 'instruction' file
    

    只有在命令行上给出多个指令时才需要用-e选项。它告诉sed将一下参数解释为指令。当只有一个指令时,sed可以自己做决定。

    //文本list内容如下
    [root@yqh ~]# cat list
    
    John Daggett, 341 King Road, Plymouth MA
    Alice Ford, 22 East Broadway, Richmond VA
    Orville Thomas, 11345 Oak Bridge Road, Tulsa OK
    Terry Kalkas, 402 Lans Road, Beaver Falls PA
    Eric Adams, 20 Post ROad, Sudbury MA
    Hubert Sims, 328A Brook Road, Roanoke VA
    Amy Wilde, 334 Bayshore Pkwy, Mountain View CA
    Sal Carpenter, 73 6th Street, Boston MA
    
    //将MA替换成Massachusetts(展示效果,不更改文件)
    [root@yqh ~]# sed 's/MA/Massachusetts/' list
    
    John Daggett, 341 King Road, Plymouth Massachusetts
    Alice Ford, 22 East Broadway, Richmond VA
    Orville Thomas, 11345 Oak Bridge Road, Tulsa OK
    Terry Kalkas, 402 Lans Road, Beaver Falls PA
    Eric Adams, 20 Post ROad, Sudbury Massachusetts
    Hubert Sims, 328A Brook Road, Roanoke VA
    Amy Wilde, 334 Bayshore Pkwy, Mountain View CA
    Sal Carpenter, 73 6th Street, Boston Massachusetts
    

    该指令只影响了3行,但显示出了所有行。

    并不是在任何情况下都需要将指令用单引号包围起来,但是你应该养成这个习惯。使用单引号可以阻止 shell解释编辑指令中的特殊字符或空格(shell使用空格决定提交给程序独立参数,特殊的shell字符在调用之前被展开)。

    例如,以上例子可以不使用单引号,但下一个例子就需要使用单引号,因为替换命令中包含空格:

    //将 MA替换成, Massachusetts(展示效果,不更改文件)
    [root@yqh ~]# sed 's/ MA/, Massachusetts/' list
    
    John Daggett, 341 King Road, Plymouth, Massachusetts
    Alice Ford, 22 East Broadway, Richmond VA
    Orville Thomas, 11345 Oak Bridge Road, Tulsa OK
    Terry Kalkas, 402 Lans Road, Beaver Falls PA
    Eric Adams, 20 Post ROad, Sudbury, Massachusetts
    Hubert Sims, 328A Brook Road, Roanoke VA
    Amy Wilde, 334 Bayshore Pkwy, Mountain View CA
    Sal Carpenter, 73 6th Street, Boston, Massachusetts
    

    为了在城市(city)和(state)之间放置逗号,指令用一个逗号和一个空格取代两字母缩写词前面的空格。

    有3种方式可以指定命令行上的多重指令:

    //1.用分号分隔指令
    [root@yqh ~]# sed 's/ MA/, Massachusetts/;s/ PA/, Pennsylvania/' list
    
    John Daggett, 341 King Road, Plymouth, Massachusetts
    Alice Ford, 22 East Broadway, Richmond VA
    Orville Thomas, 11345 Oak Bridge Road, Tulsa OK
    Terry Kalkas, 402 Lans Road, Beaver Falls, Pennsylvania
    Eric Adams, 20 Post ROad, Sudbury, Massachusetts
    Hubert Sims, 328A Brook Road, Roanoke VA
    Amy Wilde, 334 Bayshore Pkwy, Mountain View CA
    Sal Carpenter, 73 6th Street, Boston, Massachusetts
    
    //2.在每个指令前放置-e
    [root@yqh ~]# sed -e 's/ MA/, Massachusetts/' -e 's/ PA/, Pennsylvania/' list
    
    John Daggett, 341 King Road, Plymouth, Massachusetts
    Alice Ford, 22 East Broadway, Richmond VA
    Orville Thomas, 11345 Oak Bridge Road, Tulsa OK
    Terry Kalkas, 402 Lans Road, Beaver Falls, Pennsylvania
    Eric Adams, 20 Post ROad, Sudbury, Massachusetts
    Hubert Sims, 328A Brook Road, Roanoke VA
    Amy Wilde, 334 Bayshore Pkwy, Mountain View CA
    Sal Carpenter, 73 6th Street, Boston, Massachusetts
    
    //3.使用Bourne shell的分行指令功能,在输入单引号后按回车键,就会出现多行输入的提示符(>)
    [root@yqh ~]# sed '
    > s/ MA/, Massachusetts/
    > s/ PA/, Pennsylvania/
    > s/ CA/, California/ ' list
    
    John Daggett, 341 King Road, Plymouth, Massachusetts
    Alice Ford, 22 East Broadway, Richmond VA
    Orville Thomas, 11345 Oak Bridge Road, Tulsa OK
    Terry Kalkas, 402 Lans Road, Beaver Falls, Pennsylvania
    Eric Adams, 20 Post ROad, Sudbury, Massachusetts
    Hubert Sims, 328A Brook Road, Roanoke VA
    Amy Wilde, 334 Bayshore Pkwy, Mountain View, California
    Sal Carpenter, 73 6th Street, Boston, Massachusetts
    

    脚本文件

    在命令行上输入较长的编辑脚本是不实际的。这就是通常最好创建包含编辑指令的脚本文件的原因。编辑脚本只是一系列要依次的简单的sed命令。这种形式使用-f选项来指定命令行上的脚本文件的名字,格式如下:

    sed -f scriptfile file
    

    将想要执行的所有编辑命令都放置在文件中。我们按照惯例创建临时脚本文件sedscr。

    [root@yqh ~]# vim sedscr
    
    s/ MA/, Massachusetts/
    s/ PA/, Pennsylvania/
    s/ CA/, California/
    s/ VA/, Virginia/
    s/ OK/, Oklahoma/
    

    下面的命令读取sedscr中的所有替换命令,并将这些命令应用于输入文件list中的每一行:

    [root@yqh ~]# sed -f sedscr list
    
    John Daggett, 341 King Road, Plymouth, Massachusetts
    Alice Ford, 22 East Broadway, Richmond, Virginia
    Orville Thomas, 11345 Oak Bridge Road, Tulsa, Oklahoma
    Terry Kalkas, 402 Lans Road, Beaver Falls, Pennsylvania
    Eric Adams, 20 Post ROad, Sudbury, Massachusetts
    Hubert Sims, 328A Brook Road, Roanoke, Virginia
    Amy Wilde, 334 Bayshore Pkwy, Mountain View, California
    Sal Carpenter, 73 6th Street, Boston, Massachusetts
    

    保存输出

    只有将sed的输出重定向到另一个程序中,才能够捕获文件中的输出。要完成这项工作需要在一个文件名后面指定一个shell 的I/0重定向符号。例如:

    [root@yqh ~]# sed -f sedscr list > newlist
    
    [root@yqh ~]# cat newlist 
    
    John Daggett, 341 King Road, Plymouth, Massachusetts
    Alice Ford, 22 East Broadway, Richmond, Virginia
    Orville Thomas, 11345 Oak Bridge Road, Tulsa, Oklahoma
    Terry Kalkas, 402 Lans Road, Beaver Falls, Pennsylvania
    Eric Adams, 20 Post ROad, Sudbury, Massachusetts
    Hubert Sims, 328A Brook Road, Roanoke, Virginia
    Amy Wilde, 334 Bayshore Pkwy, Mountain View, California
    Sal Carpenter, 73 6th Street, Boston, Massachusetts
    

    不要将输出重定向到正在编辑的文件中,否则就会使它变成乱码(“>”重定向操作符在shell做任何其他事情之前截取文件)。如果想用输出文件取代输入文件,那么可以采用mv命令并将它做为单独的步骤来处理。但是首先要确保编辑的脚本是正确的。

    阻止输入行的自动显示

    sed的默认操作是输出每个输入行。-n选项可以阻止自动输出。当指定该选项时,每个要生成输出的指令都必须包含打印命令p。请看下面的示例。

    [root@yqh ~]# sed -n -e 's/MA/Massachusetts/p' list
    
    John Daggett, 341 King Road, Plymouth Massachusetts
    Eric Adams, 20 Post ROad, Sudbury Massachusetts
    Sal Carpenter, 73 6th Street, Boston Massachusetts
    

    将这一输出与本节中的第一个示例进行比较。这里只会显示受命令影响的行。

    替换

    我们已经讨论了替换命令的许多用法。下面是它的详细的用法:

    [address]s/pattern/replacement/flags
    

    这里修饰替换的标志 flags 是:

    选项 描述
    n 1到512之间的一个数字,表示对文木模式中指定模式第n次出现的情况进行替换
    g 对模式空间的所有出现的情况进行全局更改。而没有g是通常只有第一次出现的情况被取代
    p 打印模式空间的内容
    w 将模式空间的内容写到文件file中

    替换命令应用于与address 匹配的行。如果没有指定地址,那么就应用于Pattern匹配的所有行。如果正则表达式作为地址来提供,并且没有指定模式,那么替换命令匹配由地址匹配的内容。当替换命令是应用于同一个地址上的多个命令之一时,这可能会非常有用。

    和地址不同的是,地址需要一个作为定界符的斜杠(/) ,而正则表达式可以用任意字符来分隔,只有换行符除外。因此,如果模式包含斜杠,那么可以选择另一个字符作为定界符,例如井号。

    s#/usr/mail#/usr2/mail#
    

    注意,定界符出现了3次而且在replacement之后是必需的。不管使用哪种定界符,如果它出现在正则表达式中,或者在替换文本中,那么就用反斜杠来转义它。


    使用awk

    与sed相似,awk为每个输入行执行一套指令。可以在命令行上指定指令或创建脚本文件。

    sed命令行选项

    选项 描述
    -f 跟随脚本的文本名
    -F 改变字段分隔符
    -v 跟随var=value

    运行awk

    命令行的语法是:

    awk 'instructions' files
    

    每次从一个或多个文件中读入一行或从标准输入中读入一行。指令必须包含在单引号中,从而与shell区别开(指令几乎总是包含大括号和/或美元符号,shell将它们解释为特殊符号)。可以用与sed相同的方式输入多重命令行:用分号分隔命令或使用Borune shell的多行输入功能。

    awk程序通常被放置在可以对它们进行测式和修改的文件中,用脚本文件调用awk 的语法如下:

    awk -f script files
    

    -f 选项的工作方式与在sed中相同。

    尽管awk指令与sed 指令的结构相同,都由模式和过程两部分组成,但过程本身有很大的不同。awk看上去不像编辑器而更像一种程序设计语言。语句和函数取代了使用一个或两二个字符组成的命令序列。例如,使用print 语句打印表达式的值或打印当前输入行的内容。

    在通常情况下,awk将每个输入行解释为一条记录而将一行上的每个单词(由空格或制表符分隔)解释为每一个字段(可以改变这些默认设置)。一个或多个连续的空格或制表符看做一个定界符。awk 允许在模式或过程中引用这些字段。"$0"代表整个记录。我们来看几个示例,使用样本输入文件list。

    第一个示例包含单个指令,用于打印输入文件中每行的第一个字段。

    [root@yqh ~]# awk '{print $1}' list
    John
    Alice
    Orville
    Terry
    Eric
    Hubert
    Amy
    Sal
    

    “$1”表示每个输入行上的第一个字段的值。因为这里没有指定模式,所以打印语句应用于所有的行。下一个示例指定了“/MA/”模式,但是其中没有过程。这个默认操作是打印匹配这种模式的每一行。

    [root@yqh ~]# awk '/MA/' list
    John Daggett, 341 King Road, Plymouth MA
    Eric Adams, 20 Post ROad, Sudbury MA
    Sal Carpenter, 73 6th Street, Boston MA
    

    本例打印了3行。正如在第一章所提到的那样,awk程序更像一种查询语言,从文件中提取有用的信息。可以认为惟上模式指定了一种条件,用于选择要包括在报表中的记录,也就是这些记录必须包含字符串“MA”。现在还可以指定记录的哪些部分要包括在报表中。下一个示例使用一条print语句精确到某一行的某一列。

    [root@yqh ~]# awk '/^Terry/{print $3}' list
    402
    

    在下一示例中,使用-F选项将字段分隔符改变为逗号。它使我们能够检索3个字段中的任一个:全称、街道地址或城市和州。

    [root@yqh ~]# awk -F','' '/MA/{print $1}' list
    John Daggett
    Eric Adams
    Sal Carpenter
    

    不要改变字段分隔符的F选项与指定脚本文件名的-f 选项弄混。

    下一个示例将每个字段单独打印在这一行上。多重命令由分号或逗号隔开。

    [root@yqh ~]# awk -F',' '/MA/{print $1;print $2;print $3}' list
    John Daggett
     341 King Road
     Plymouth MA
    Eric Adams
     20 Post ROad
     Sudbury MA
    Sal Carpenter
     73 6th Street
     Boston MA
     
    [root@yqh ~]# awk -F',' '/MA/{print $1,$2,$3}' list
    John Daggett  341 King Road  Plymouth MA
    Eric Adams  20 Post ROad  Sudbury MA
    Sal Carpenter  73 6th Street  Boston MA
    
    [root@yqh ~]# awk -F',' '/MA/{print $1"---"$2"---"$3}' list
    John Daggett--- 341 King Road--- Plymouth MA
    Eric Adams--- 20 Post ROad--- Sudbury MA
    Sal Carpenter--- 73 6th Street--- Boston MA
    

    传变量

    [root@yqh ~]# echo | awk -v a=10 '{print a}'
    10
    

    出错信息

    当遇到程序中的问题时,awk 的每个实现都会给出不同的出错信息。因此,这里不引用特殊版本的消息;当出现问题时它是显而易见的。下面任何一种情况都会产生消息:

    • 没有用大括号({})将过程括起来
    • 没有用单引号(‘’)将指令括起来
    • 没有用斜杠(//)中将正则表达式括起来

    同时使用sed和awk

    在unix中,管道可用于将一个程序的输出作为输入传递给另一个程序。参看几个综合使用sed和 awk来产生报表的示例。用州的全名代替邮政编码的sed 脚本通常已经足够,它可被再次用做名为nameState 的脚本文件:

    [root@yqh ~]# cat nameState 
    s/ MA/, Massachusetts/
    s/ PA/, Pennsylvania/
    s/ CA/, California/
    s/ VA/, Virginia/
    s/ OK/, Oklahoma/
    

    当然,要处理所有的州,而不只是这5个,并且如果是对文档而不是邮件列表执行这些命令,则要确保不会生成不必要的替换。

    该程序(使用输入文件list)的输出,与我们已经看到的相同。在下一个示例中,由nameState产生的输出被输送到一个awk程序中,这个awk程序用于从每条记录中提取州的名字。

    [root@yqh ~]# sed -f nameState list | awk -F',' '{print $4}'
     Massachusetts
     Virginia
     Oklahoma
     Pennsylvania
     Massachusetts
     Virginia
     California
     Massachusetts
    

    以上 awk程序处理由sed 脚本产生的输出。记住前面的sed脚本用逗号和州的全称代替缩写。实际上,它将包含城市和州的第三个字段拆分成二个字段。“$4”表示第4个字段。

    这里所做的事情可以完全由sed完成,但可能会有更多的困难和更少的通用性。而且,因为awk 允许替换匹配的字符串,所以可以完全用awk 脚本得到这个结果。
    本程序的结果不是非常有用,可以将它传递给sort | uniq -c ,它将州名按字母表排序,同量给出每个州名出现的资料。

    现在,我们要做一些更有趣的事情。按州的名字排序并列出州的名字,以及住在那个州的人的名字。下面的示例展示了byState程序:

    [root@yqh ~]# vim byState
    #!/bin/bash
    
    awk -F',' '{
        print $4 ", " $0
    }' $* | sort |
    awk -F',' '
        $1 == LastState{
            print "	" $2
        }
        $1 != LastState {
            LastState=$1
            print $1 
            print "	" $2
        }'
    

    这个shell脚本有3个部分,程序中调用awk以产生sort程序的输入,然后再次调用awk测式排好序的输入,并确定当前记录中的州的名字,是否与前一个记录中的名字相同。我们来看这个脚本的执行:

    [root@yqh ~]# sed -f nameState list | ./byState
     California
    	 Amy Wilde
     Massachusetts
    	 Eric Adams
    	 John Daggett
    	 Sal Carpenter
     Oklahoma
    	 Orville Thomas
     Pennsylvania
    	 Terry Kalkas
     Virginia
    	 Alice Ford
    	 Hubert Sims
    

    这些名字被按州排序,这是使用awk从结构化数据中生成报表的典型示例。

    为了检查byState程序是如何工作的,让我们分别看看每个部分。它被设计为从nameState程序读取输入并期待“$4”成为州的名字。查看由程序的第一行产生的输出:

    [root@yqh ~]# sed -f nameState list | awk -F',' '{print $4 "," $0}'
     Massachusetts,John Daggett, 341 King Road, Plymouth, Massachusetts
     Virginia,Alice Ford, 22 East Broadway, Richmond, Virginia
     Oklahoma,Orville Thomas, 11345 Oak Bridge Road, Tulsa, Oklahoma
     Pennsylvania,Terry Kalkas, 402 Lans Road, Beaver Falls, Pennsylvania
     Massachusetts,Eric Adams, 20 Post ROad, Sudbury, Massachusetts
     Virginia,Hubert Sims, 328A Brook Road, Roanoke, Virginia
     California,Amy Wilde, 334 Bayshore Pkwy, Mountain View, California
     Massachusetts,Sal Carpenter, 73 6th Street, Boston, Massachusetts
    

    默认情况下,sort程序按字母顺序排列行,从左到右查看字符。为了按州(而不是名字)对记录进行排序,我们将州作为排序的关键字插入到记录的开始处。现在,sort程序可以工作了(注意使用sort实用工具可以避免在awk 内部编写排序程序)。

    第二次调用awk时执行程序设计任务。脚本查看每条记录的第一个字段以决定它是否与前一条记录相同。如果不相同,则同时打印州的名字的人的名字。如果相同,则只打印人的名字。

    $1 == LastState{
        print "	" $2
    }
    $1 != LastState {
        LastState=$1
        print $1 
        print "	" $2
    }'
    

    这里还有几个重要的事情,包括给一个变量赋值,测式每个输入行的第一个字段来看它是否包含一个变量字符串,并且打印制符来调整输出数据的对齐。注意在使用某个变量之前不必对它先赋值(因为awk将变量初始化为空字符串)。这是较小的脚本,但是在更大的索引程序中,可以看到用于比较索引条目的类似的程序。然而,目前可以先不用过多的关心有关每条语句做什么事情,这里的目的是给你一个sed和awk能做什么的概述。

  • 相关阅读:
    PAT 1020 月饼 (25)(精简版代码+思路+推荐测试用例)
    PAT 1010 一元多项式求导 (25)(STL-map+思路)
    通过无线连接的方式来做 Appium 自动化
    Eclipse shift + ctrl + F 不好用
    Appium 出现 > error: com.test/.activity1 never started. Current: com.test/.activity2
    Appium 出现 > error: com.test/.activity1 never started. Current: com.test/.activity2
    从CSDN 来到博客园入驻——2015/1/28
    敏捷自动化测试(1)—— 我们的测试为什么不够敏捷?
    敏捷自动化测试(2)——像用户使用软件一样享受自动化测试
    Android自动化测试之Monkey工具
  • 原文地址:https://www.cnblogs.com/yuqinghao/p/14592807.html
Copyright © 2011-2022 走看看