Shell脚本高级编程 一 初识sed和gawk

到目前为止,shell脚本最常见的一个用途是处理文本文件。可以检查日志文件、可以读取配置文件以及处理数据元素,还可以帮助自动化处理文本文件中各种类型数据。但只用shell脚本命令处理文本文件内容有点勉为其难。现在介绍Linux中的sed和gawk工具。这两个工具能够极大地简化需要进行的数据处理任务。
(1)文本处理

  • sed编辑器

    • sed编辑器(流编辑器,stream editor),跟普通交互式文本编辑器恰好相反。流编辑器会使用预先提供的一组规则来编辑和处理数据流。
    • sed编辑器可以基于输入到命令行的或是存储在命令文本文件中的命令来处理数据流中的数据。它每次从待处理的数据中读取一行,用提供的编辑器命令匹配数据、按命令中指定的方式修改流中的数据,然后将生产的数据输出到STDOUT。处理完成后,编辑器将读取下一行数据并重复此过程,直至待处理数据的最后一行处理完成,它就会终止。
    • 由于命令都是一行一行顺序处理数据的,sed编辑器必须一次就完成对文本中的某一行的所有修改。这使得sed编辑器比交互式编辑器快得多,便能很快的完成对数据的自动修改。
    • sed命令的格式为
      • sed options script file
      • 选项参数允许你修改sed命令的行为,sed还包含多个选项:
        这里写图片描述
      • script参数指定了将作用在流数据上的单个命令。如需用多个命令,你必须用 -e 选项来在命令行上指定它们,或用 -f 选项来在单独的文件中指定它们。sed编辑器有大量的命令可以使用,后续将做详细介绍。
    • 在命令行定义编辑器命令

      • 默认情况下,sed编辑器会将指定的命令应用到STDIN输入流上。因此,我们可以直接将数据管道输出到sed编辑器上处理。如下:

        $echo "This is a test" | sed 's/test/big test/'
        This is a big test

        这个例子在sed编辑器中使用了 s 命令,该命令用斜线间指定的第二个字符串来替换第一个文本字符串。

      • 注意,sed编辑器自身不会修改文本文件的数据。它只会讲修改后的数据发送到STDOUT。
    • 在命令行使用多个编辑器命令

      • 用-e选项即可:

        $cat data1
        The quick brown fox jumps over the lazy dog.
        The quick brown fox jumps over the lazy dog.
        The quick brown fox jumps over the lazy dog.
        The quick brown fox jumps over the lazy dog.
        $sed -e 's/brown/green/;   s/dog/cat/' <  data1
        The quick green fox jumps over the lazy cat.
        The quick green fox jumps over the lazy cat.
        The quick green fox jumps over the lazy cat.
        The quick green fox jumps over the lazy cat.
        • 注意,两个命令都可以作用到文件中的每行数据上。命令之间必须用分号隔开,且在命令末尾和分号之间不能有空格。
        • 也可以用bash shell 中的次提示符来分隔命令,而不用分号。只要输入第一个单引号来开始编写,bash 会继续提示你输入更多命令,直到你输入了封尾的单引号:
          $sed -e '
          > s/brown/green/
          > s/fox/elephant/
          > s/dog/cat/' data1
          The quick green elephant jumps over the lazy cat.
          The quick green elephant jumps over the lazy cat.
          The quick green elephant jumps over the lazy cat.
          The quick green elephant jumps over the lazy cat.
      • 必须记住,要在封尾单引号所在行结束命令。bash shell 一旦发现了封尾的单引号,就会执行命令。开始后,sed命令就会将你指定的每条命令应用在文本文件中的每一行上。

    • 从文件中读取编辑器命令

      • 可以将大量要处理的sed命令,存放在一个文件中。然后在sed命令中用 -f 选项指定文件:
      $cat script1 
      s/brown/green/
      s/fox/elephant/
      s/dog/cat/
      sed -f script1 data1 
      The quick green elephant jumps over the lazy cat.
      The quick green elephant jumps over the lazy cat.
      The quick green elephant jumps over the lazy cat.
      The quick green elephant jumps over the lazy cat.

      此时,不用在每条命令后面放一个分号。sed编辑器直到每行都有一条单独的命令。跟在命令行输入命令一样,sed编辑器会从指定文件中读取命令,并将它们应用到数据文件中的每一行数据上。

  • gawk程序
    待续。。。

(2)sed编辑器基础
成功使用sed编辑器的关键在于掌握它的各种文本编辑行为的命令和格式。
①更多的替换选项

  • 关于suitable 命令如何替换字符串中匹配的模式需要注意一点。问题引出:

    $cat data5
    This is a test of the test script.
    This is the second test of the test script.
    $sed 's/test/trial/' data5
    This is a trial of the test script.
    This is the second trial of the test script.
    • 由上面可以看出。suitable命令默认情况下,只替换了每行中出现的第一处。要解决这一问题,必须使用 替换标记(substitution flag)。替换标记在替换命令字符串之后设置:
    • s/pattern/replacement/flags
    • 有4中可用的替换标记:

      • 数字,表明新文本将替换第几处模式匹配的地方;
      • g,表明新文本将替换所有模式匹配的地方;
      • p,表明原来行的内容要打印出来;
      • w file,将替换结果写到文件中。

        's/test/trial/2' data5
        This is a test of the trial script.
        This is the second test of the trial script.

        -w 的例子:

        $cat data6
        This is a test line.
        This is a different line.
        $sed 's/test/trial/w test' data6
        This is a trial line.
        This is a different line.
        $cat test
        This is a trial line.
      • sed编辑器的正常是输出在STDOUT中,而只有那些包含匹配模式的行才会保存在指定的输出文件中(且保存的是替换后的内容)。

  • 替换字符

    • 有时会碰到一些文本字符串中的字符不方便在替换模式中使用的情况。例如,Linux中的正斜线。

      • 替换文件中的路径名会比较麻烦。比如,用cshell 替换 /etc/passwd文件中的bash shell,则:

        sed 's/\/bin\/bash/\/bin\/csh/' data7
        /xiaoyu/bin/csh
        /xiaoyu2/bin/csh

        由于/通常作为字符串的分隔符,因此如果它出现在模式文本中,必须使用\来转义。

      • 要解决这个问题,sed编辑器允许选择其他字符来作为substitute命令中的字符串分隔符:

        $sed 's!/bin/bash!/bin/csh!' data7
        /xiaoyu/bin/csh
        /xiaoyu2/bin/csh

②使用地址
默认情况下,sed编辑器中的命令会作用于文本数据的所有行。如果只想将命令作用于特定某行或某几行,可以用 行寻址(line addressing)。
在sed编辑器中有两种形式的行寻址:

  • 行的数字范围;
  • 用文本模式来过滤出某行。
    两种形式都是用相同的格式来指定地址:
    [address]command
    也可以为特定地址将多个命令放在一起:
    address {
    command1
    command2
    command3
    }
    sed 编辑器会将指定的每条命令只作用于匹配指定地址的行上。

  • 数字方式的行寻址
    使用数字方式的行寻址时,我们可以用它们在文本流中的行位置来引用行。sed编辑器会将文本流中的第一行分配为第一行,然后继续按顺序为新行分配行号。

    • 使用单个行号方式指定行:

      $sed '2s/dog/cat/' data1
      The quick brown fox jumps over the lazy dog.
      The quick brown fox jumps over the lazy cat.
      The quick brown fox jumps over the lazy dog.
      The quick brown fox jumps over the lazy dog.
    • 使用起始行、逗号及尾行指定一定范围内的行:

      $sed '2,3s/dog/cat/' data1
      The quick brown fox jumps over the lazy dog.
      The quick brown fox jumps over the lazy cat.
      The quick brown fox jumps over the lazy cat.
      The quick brown fox jumps over the lazy dog.
      • 注意,如果想要将一条命令作用到文本中某行开始到结尾的所有行,可以用特殊地址$表示文本文件的最后一行。
    • 使用文本模式过滤器
      sed编辑器允许指定文本模式来过滤出命令要作用的行。格式如下:
      /pattern/command
      必须用/将要指定的pattern封起来。sed编辑器会将该命令只作用到包含指定文本模式的行上。sed编辑器在文本模式中会采用 正则表达式(regular expression)的特性来帮助创建能很好地匹配的模式。

    • 组合命令
      如果需要在单行上执行多条命令,可以用花括号将多条命令组合起来。如下:

      $sed '2,3{                
      s/fox/elephant/
      s/dog/cat/
      }' data1
      The quick brown fox jumps over the lazy dog.
      The quick brown elephant jumps over the lazy cat.
      The quick brown elephant jumps over the lazy cat.
      The quick brown fox jumps over the lazy dog.

③删除行
sed编辑器的删除(delete)命令,可以删除文本流中的特定行。
删除命令 d ,它会删除匹配指定寻址模式的所有行。如果没有添加一个寻址模式,流中的所有文本行都会被删除。

  • 删除命令和指定地址一起使用:

    $sed '2,3d' data1
    The quick brown fox jumps over the lazy dog.
    The quick brown fox jumps over the lazy dog.
  • sed编辑器的模式匹配特性也适用于删除命令:

    $sed '/number 1/d' data7
    This is line number 2.
    This is line number 3.
    This is line number 4.
  • 我们可以用删除两个文本模式来删除某个范围内的行。指定的第一个模式会“打开”行删除功能,第二个模式会“关闭”行删除功能。sed编辑器会删除两个指定行之间的所有行(包括指定行):

    
    #下面模式中的3,是一种模式,而非第3行的意思
    
    $sed '/1/,/3/d' data7 
    This is line number 4.
    • 使用这种方式需要注意:

      $cat data8
      This is line number 1.
      This is line number 2.
      This is line number 3.
      This is line number 4.
      This is line number 1 again.
      This is text you want to keep.
      This is the last line.
      $sed '/1/,/3/d' data8
      This is line number 4.
      • 第二次出现数字“1”的行再次触发了删除命令,删除了数据流中的剩余行,因为停止模式再没找到。

④插入和附加文本

  • 插入(insert),命令i会在指定行前增加一个新行;
  • 追加(append),命令a会在指定行后增加一个新行。
    命令的格式:
    sed ‘[address]command\
    new line

    • 在STDIN输入数据中使用插入命令:

      $echo "The LIne 2" | sed 'i\The Line 1'
      The Line 1
      The LIne 2
    • 从文本文件中读取数据再使用追加命令:

      $cat data9
      line 1.
      line 3.
      $sed '1a\line 2' data9
      line 1.
      line 2
      line 3.
      $sed '/3/a\line 4' data9
      line 1.
      line 3.
      line 4  
    • 如上例所示,要给数据流中插入或追加数据,必须用寻址来指定新数据的位置。可以匹配一个数字行号或文本模式,但不能用地址区间。因为,你只能将文本插入或附加到单个行的前面或后面,而不能是行区间的前面或后面。
      • 如需要插入或附加多行文本,则必须对新文本中的每一行使用\,直到要插入或附加的文本的最后一行:
        $sed '/3/a\
        > line 4\
        > line 5.' data9
        line 1.
        line 3.
        line 4
        line 5.

⑤修改行(c命令)
修改(change)命令,修改数据流中整行文本的内容。

  • 寻址方式,指定修改行

    $sed '2c\This is a changed line' data9
    line 1.
    This is a changed line
  • 文本模式,指定修改行

    $sed '/line/c\This is a changed line' data9
    This is a changed line
    This is a changed line
  • 地址区间寻址,但结果可能并不是你想要的:

    $sed '1,2c\This is a changed line' data9
    This is a changed line
    • sed编辑器会用这一行文本替换数据流中的两行文本,而非逐一修改那两行文本。

⑥转换命令(y命令)
转换(transform,y)命令是唯一一个可以处理单个字符的sed编辑器命令。格式如下:
[address]y/inchars/outchars/
转换命令会进行inchars和outchars值的一对一映射。inchars中的第一个字符会被替换成outchars的第一个字符,inchars中的第二个字符会被替换成outchars的第二个字符,以此类推。如果inchars 和 outchars长度不同,则sed编辑器会差生一条错误消息。

  • 可以使用所有的寻址方式(指定行寻址,区间寻址):

    $sed '2y/13/24/' data9
    line 1.
    line 4.
  • 不添加寻址方式,即为文本的全部行:
  • y命令是一个全局命令,它会自动替换文本行中找到的指定字符的所有实例,而不会考虑它们出现的位置:

    $echo "This 1 is a test of 1 try." | sed 'y/123/456/'
    This 4 is a test of 4 try.

    ⑦回顾打印(p命令)
    3中打印数据流中信息的命令:

  • p命令,打印文本行;
  • 等号(=),打印行号;
  • l(L的小写),列出行。

  • 打印行

    • 可以使用寻址方式指定要打印的行,如不指定,则默认打印文本所有行:

      $sed -n 'p' data9
      line 1.
      line 3.
    • 可以使用文本模式匹配,打印指定行:

      $sed -n '/3/p' data9
      line 3.

      修改之前查看行,使用打印命令:

      $sed -n '/3/{
      > p
      > s/line/test/p
      > }' data9
      line 3.
      test 3.

    sed编辑器命令首先查找包含数字“3”的行,然后执行两条命令。首先,脚本用p命令打印出原来的行,然后用s命令替换文本,并用p命令打印出替换后的文本。

  • 打印行号

    • 等号命令会打印在数据流中当前行的行号。行号由数据流中的换行符决定。每次数据流出现一个换行符,sed编辑器会认为它结束了一行文本:

      $sed '=' data9
      1
      line 1.
      2
      line 3.
    • 等号命令的在数据流中查找特定文本模式时,也很有用:

      $sed -n '/3/=' data9
      2
      
      $sed -n '/3/{
      > =
      > p
      > }' data9
      2
      line 3.
      
  • 列出行

    • 列出命令(l)允许打印数据流中的文本和不可通过p命令打印的ASCII字符。任何不可打印字符都用它们的八进制前加一个\,比如\t代表制表符:

      $sed -n 'l' data10
      This\tline\tcontains\ttabs.$
      
      • \t代表制表符。$代表换行符。

⑧用sed和文件一起工作
sed编辑器的另外一些命令也允许你修改文本内容:

  • 向文件写入

    • w 命令用来向文件写入行。其格式如下:

      • [address]w filename
      • filename可以是相对或绝对路径名,但运行sed编辑器命令的用户必须有文件的写权限。地址可以是sed中支持的任意类型的寻址方式,单个行号、文本模式等。

        $sed '1w test' data9
        line 1.
        line 3.

        上例,将data9中的第一行写入test中。如果不想让行显示到STDOUT上,可以使用-n选项。

  • 从文件读取数据

    • 读取命令(r)运行你将读取一个独立文件中的数据插入到数据流中。读取格式如下:[address]r filename

      • filename 参数指定了数据文件的绝对或相对路径名。sed编辑器会将文本文件中读取到的数据插入到地址之后。寻址方式可以是,单个行号或文本模式。
        $sed '1r data12' data9
        line 1.
        This is an added line.
        This is the second added line.
        line 3.
    • 读取命令的另一个常用方式,结合删除命令使用来替换某个文件中的数据。例如,

      $cat letter 
      Would the fllowing pepole:
      LIST
      please report to the office.
      
      $cat data11
      xiaoyu  xiaoyu1
      
      $sed '/LIST/{
      > r data11
      > d
      > }' letter
      

      首先,读取data11中的数据到letter中,此时,占位符LIST仍存在,然后使用d命令删除。
      (3)小结
      掌握sed编辑器的关键在于,掌握各种命令的格式和适用场景。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Shell脚本高级编程教程,希望对你有所帮助。 Example 10-23. Using continue N in an actual task: 1 # Albert Reiner gives an example of how to use "continue N": 2 # --------------------------------------------------------- 3 4 # Suppose I have a large number of jobs that need to be run, with 5 #+ any data that is to be treated in files of a given name pattern in a 6 #+ directory. There are several machines that access this directory, and 7 #+ I want to distribute the work over these different boxen. Then I 8 #+ usually nohup something like the following on every box: 9 10 while true 11 do 12 for n in .iso.* 13 do 14 [ "$n" = ".iso.opts" ] && continue 15 beta=${n#.iso.} 16 [ -r .Iso.$beta ] && continue 17 [ -r .lock.$beta ] && sleep 10 && continue 18 lockfile -r0 .lock.$beta || continue 19 echo -n "$beta: " `date` 20 run-isotherm $beta 21 date 22 ls -alF .Iso.$beta 23 [ -r .Iso.$beta ] && rm -f .lock.$beta 24 continue 2 25 done 26 break 27 done 28 29 # The details, in particular the sleep N, are particular to my 30 #+ application, but the general pattern is: 31 32 while true 33 do 34 for job in {pattern} 35 do 36 {job already done or running} && continue 37 {mark job as running, do job, mark job as done} 38 continue 2 39 done 40 break # Or something like `sleep 600' to avoid termination. 41 done 42 43 # This way the script will stop only when there are no more jobs to do 44 #+ (including jobs that were added during runtime). Through the use 45 #+ of appropriate lockfiles it can be run on several machines 46 #+ concurrently without duplication of calculations [which run a couple 47 #+ of hours in my case, so I really want to avoid this]. Also, as search 48 #+ always starts again from the beginning, one can encode priorities in 49 #+ the file names. Of course, one could also do this without `continue 2', 50 #+ but then one would have to actually check whether or not some job 51 #+ was done (so that we should immediately look for the next job) or not 52 #+ (in which case we terminate or sleep for a long time before checking 53 #+ for a new job).
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值