zoukankan      html  css  js  c++  java
  • 【引用】整理Sed与Awk学习笔记(一)

    一、前言

      开卷有益,在it领域有很多学习的途径,个人认为最好的学习教材是原版图书,但由于语言上的问题,大多数人只能望书兴叹!这个文档是根据我自学时的实际情况整理的,和大多数的实际需要情况所写。 其中示例大部分参考了《O'Reilly.SED and AWK》(我有电子版中文PDF,假若有需要请留下邮箱!) ,每篇文章中所带的小练习或来自工作或来自网络,希望读者能够多加练习,实践才是王道。
      ——>这是我学习过程中,发现一个比较好的教材,所以特意整理下作者的笔记!非原创。

    二、基本概念

      1、Sed是一个“非交互式”的面向字符流的编辑器,而这个面向字符流就像是我去餐厅点了一道菜让厨师做,菜都是字符,厨师做好后直接送到我面前,所以我只要下达命令就可以了。
      Sed的优点是可以在一个地方指定所有的编辑指令,然后通过文件传递一次来执行他们,但是它在每次多于一行的处理能力方面有限制。

      2、Awk的典型应用是将数据转换成格式化的报表,增强可读性,因此当数据有某种结构时就能最好的体现awk的好处。Awk的功能是非常强大的,甚至可以说成是程序设计语言,类似Python、c/c++等。

    三、基本操作

      命令的框架:

        命令 选项 工作内容 文件名

      Sed和awk的输出都不允许送到向程序提供输入的同一个文件,否则会使它变成乱码,如果工作内容中包含shell可执行的字符如“$和*”,那么必须用单引号引起。Sed和awk都可以用-f来指定工作内容,这通常就是脚本存放的位置,使用过程中,短的脚本可以在命令行上指定,长的脚本通常放在容易被修改和测试的文件中。

      在sed和awk中,每个指令都包含两个部分——>模式和语句 : 模式是由/分隔的正则,语句指定一个或多个将被执行的动作。

      Awk不自动输出行,脚本中的指令控制awk最终所做的事情

      Awk的语句由程序设计语句和函数组成,语句必须用大括号括起 

      Sed的语句由类似于行编辑器中使用的那些编辑命令组成,大部分命令由单个字母组成 

    四、初识sed

      1、最常见的s ——>替换字符串 
    $ sed 's/MA/Massachusetts/' list
      ——>找出MA并替换成Massachusetts,并列出内容(并不是在任何情况下都要将指令用单引号包围起来,但你应该养成这个习惯,如果不加单引号,那么你就可能会得到一个错误提示  sed: -e expression #1, char 2: unterminated `s' command

      2、关闭自动输出,只打印被修改行 ——>这里用了参数-n(关闭自动输出)和p(打印被修改行)
    $ sed -n -e 's/MA/Massachusetts/p' list
      ——>在命令行上编写多个语句时, 使用 分隔或使用 -e
    如:sed 's/ MA/, Massachusetts/; s/ PA/, Pennsylvania/' list
      sed -e 's/ MA/, Massachusetts/' -e 's/ PA/, Pennsylvania/' list 

    五、初识awk

      注:为了能和shell区分开,awk的指令都必须包括单引号,因为$这类符号在shell中是有特殊意义的,虽然awk与sed指令的结构相同,但awk中用语句和函数取代了使用一个或两个字符组成的命令。

      Awk将每个输入行识别成一条记录,而将那一行上的每个单词识别成一个字段
    如:

    $ awk '{ print $1 }' list       ——>列出第一列字段 
    $ awk '/MA/' list         ——>打印含有MA的行
    $ awk '/MA/ { print $1 }'    ——>list 打印含有MA的行的第一个字段

      使用-F指定字段分隔符为逗号。意思是说逗号前的字段是$1或者$其他。这就使得原来可能是$1 $2的内容都合并成了$1。
    如:

    $ awk -F, '{ print $1; print $2; print $3 }' list

      ——>新手常见错误:没有用大括号{}、没有用单引号’’、没有用斜杠将正则括起来// 

    六、正则表达式

      引语:Grep、sed、awk都使用正则,然而这3个程序并不能完全使用正则表达式语法中的所有元字符,所谓元字符就是指那些在正则表达式中具有特殊意义的专用字符,可以用来规定其前导字符(即位于元字符前面的字符)在目标对象中的出现形式。
      注:本篇比较简陋,想深入学习正则可以找一本《精通正则表达式》来自学。

    1、表达式

      表达式告诉计算机如何产生结果,但和加减乘除一样,在式子中也存在着优先级的问题,需要注意的一点是——>正则是区分大小写的!

    那么正则是如何工作的呢,可以看下图

              图中描述abe是如何进行匹配

     

    2、元字符汇总----“.

    # grep --color -n 'r..t' /etc/passwd

    1:root:x:0:0:root:/root:/bin/bash

    12:operator:x:11:0:operator:/root:/sbin/nologin

    15:ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin

      大部分情况下这个“.” 匹配除换行符外的任意一个字符,但在awk中也能匹配换行符,这里使用--color可以非常方便地查看

     

    3、grep 具体匹配了哪些字符串,使用-n标出行数----“*

    # grep -n 'ooo*' regular_express.txt

    1:"Open Source" is a good mechanism to develop programs.

    2:apple is my favorite food.

    3:Football game is not use feet only.

    9:Oh! The soup taste good.

    18:google is the best tools for search keyword.

    19:goooooogle yes!

      例子来自鸟哥的网页,表达式为了匹配至少两个“o”以上的字符串,从本例应该能够理解“*”是匹配任意一个在它前面的字符

      思考题, *ooo与o.*o匹配的结果有什么不同?

      答:前者表示,所有以“ooo”结尾的,而后者是表示前缀有“o.”和结尾有“o”的。

     

    4、[...] 中的几种字符表义

    ——>“\”表转义,在awk中使用

    ——>“-”表示范围,例如[0-9]包含任何数字  

    ——>“^”取反,例如[^0-9]不匹配数字,注意在grep中是使用grep –v来取反

    如命令:

        grep '^[0-9]' /etc/inittab            ——)查出以数字开头的行
        grep '[a-Z]' /etc/inittab             ——)查出有字母(大小通用)的行
        grep '^[^0-9]'    /etc/inittab        ——)^[^ ]取反的
        grep 'x:[0-9][0-9]:' /etc/passwd         ——)取出UID为0-99的用户
        ls -l /dev |grep 'tty[0-9]*$'         ——)多个或0个前面的字符

     

    5、^ 的字符表义

    ——>“^ n”    以n开头的行

    ——>“$”     从行尾开始任务。

      注:在sed和grep中 和 并不一定总保持着自己的个性,当使用 ab^c 或者是 ab$c 匹配时,它们就确实代表着字面意思,没有任何别的含义。但在awk中则不同,^ 和 $ 永远保持着自己的个性,所以在awk中如果要匹配它俩时都需要使用 "\" 来转义。

     

    6、\{n,m\} 过滤使用

    例子:

    101

    1001

    10001

    100001

    10000001

    100000001

    有这么一个数据,想把1001,10001,100001 从中过滤出来,方法如下

    # grep "10\{2,4\}1" file

    1001

    10001

    100001 

    ——>因为1001中有2个0,100001中有4个0

     

    7、\ 转义符使用

    ——>作用,转义符或取消字符的特殊效果

      比如我要匹配文件中的5.6,这时候我需要这样写

    # grep '5\.6' file

    5.6

      如果写成

    #grep '5.6' file

    5.6

    506

      则列出了5.6和506

     

    8、拓展的元字符(egrep和awk)

    +

        命令:egrep 'o+'    /etc/passwd

    ?

    | 或运算

    egrep '^mysql|^root'    /etc/passwd

    ()  指定单词的单复数compan(y|ies),用于对正则进行分组并设置优先级

     

    9、基础识记

      ls -l /dev |grep '^b'

        grep -v '^#' /etc/httpd/conf/httpd.conf      (-v    取反)

        grep 'bash$' /etc/passwd               找出可以登录的用户

        grep -c 'bash$' /etc/passwd            (-c 统计行数)

        ls -lR /etc/ |grep 'conf$'            (查找/etc/下的以conf结尾的文件)

      grep -v '^$' /etc/httpd/conf/httpd.conf |grep -v '^#'    ——>找出httpd.conf文件的有效行
       [^a-Z]                  +单词分割符

        在vim编辑器下使用正则:
        1,$s/^\([a-z] [a-z]*\).*/\1/        显示第一个单词

        1,$s/^\([a-z] [a-z]*\)\([^a-z].*[^a-z]\)\([a-z]*[a-z]\)$/\3\2\1/    ——>第一个单词与最后一个单词互换

        1,$s/[0-9]//g                 把数字替换为空    g全局

        1,$s#:/[a-z] [a-z]*/[a-z] [a-z]*$##    删掉passwd后面的字段

        1,$s#.*:##                   只留路径

     

    10、练习

      a.找出passwd文件中的uid为三位数的能登录的用户

    #grep 'x:[0-9][0-9][0-9]*:..*bash$' /etc/passwd

      b.匹配否定句式

    I can do it

    I cannot do it

    I can not do it

    I can't do it

    I cant do it

    答案

    # grep "can[n 'o]*t" file

      c.匹配单词 book

    This file tests for book in various places, such as

    book at the beginning of a line or

    at the end of a line book

    答案

    # egrep -n "^book |[ \"]book[ \!\?\"\,s)]| book$" bookwords

      d.匹配结尾处有一个或多个空格的行

    被括起来的是空格(  )*$

      e.统计空格数

    $ grep -c '^$' ch04

      f.匹配空行 ^ *$

      g.匹配整个行 ^.*$

      h.英文中的常用标点 ? . , ! ; : '

     

    七、详解sed

    引语:本篇主要是让大家对sed的脚本编写有一个整体的了解,在大脑中能有个框架

      写脚本前一定要:

        (1) 具体的分析清楚自己想做什么

        (2) 明确处理的过程

        (3) 在应用于生产环境前要反复测试

    下面图中的示例是sed如何匹配字符串并替换

     

     

      从图中可以看出sed首先将整个编辑脚本应用于第一个输入行,然后在读取第二个输入行并对其应用整个脚本,这种做法的优点显而易见。如同少食多餐一个性质,一顿饭吃一百个馒头恐怕你的胃就爆了,这就是内存溢出。

    Sed脚本的3种用途

      1、对同一文件的编辑

    ——>热身,包含了以前章节中的知识点

                      HORSEFEATHERS SOFTWARE PRODUCT BULLETIN DESCRIPTION+   ___________

        BigOne Computer  offers three  software packages from the  suite of Horsefeathers  software products  --  Horsefeathers  Business BASIC, BASIC  Librarian,  and LIDO.  These software products can fill  your    requirements    for    powerful,    sophisticated,general-purpose business  software providing you with a base for software customization or development.

        Horsefeathers  BASIC is  BASIC optimized for use on  the  BigOne machine with UNIX  or MS-DOS operating systems.  BASIC Librarian is a full screen program editor, which also provides the ability

    要求

    (1)用sea取代所有空行

    $s/^$/sea/g

    (2)删除每行前面的空格

    $s/^  *//g

    (3)删除+后的___

    $/^+  *___*/d

    (4)删除在两个单词之间的多个空格

    $s/  */ /g

    (5)保留.号后的多个空格

    $s/\. */\.  /g

    (6)干掉,号后的空格

    $s/\,  */\,/g

     

    2、改变一组文件

    类似于这样

      sed -i -e '74 s/^/#/' -i -e '76 s/^/#/' $ssh_cf

      sed -i "s/#UseDNS yes/UseDNS no/" $ssh_cf

      sed -i -e '44 s/^/#/' -i -e '48 s/^/#/' $ssh_cf

      sed -i '/expose_php/s/On/Off/' $fcgi_cf

      sed -i '/display_errors/s/On/Off/' $fcgi_cf

      sed -i 's#extension_dir = "./"#extension_dir = "/usr/local/php-fcgi/lib/php/extensions/no-debug-non-zts-20060613/"\nextension

      ——>这样的脚本可以节省大量的时间,但如果写的不好造成的错误恐怕会让你花更多的时间去解决,所以制作这种脚本时最好多做测试以免以后出乱子。

    注:这种脚本通常出现在安装程序脚本的制作上,如果经常看文档,应该对此不会陌生

     

    3、提取文件的内容

      例:提取C 源文件中的 main() 函数

    $ sed -n -e '/main[[:space:]]*(/,/^}/p' sourcefile.c | more

      ——>注:这里的[[:space:]] 只是一个特殊的关键字,它告诉 sed 与 TAB 或空格匹配

     

    八、基本sed命令

      ——>想要用好sed首先就要了解它的框架,知道每一段都是干什么的!

    Sed框架

      [address]s/pattern/replacement/flags

    1、Flags段,这个可以看做是古代打仗作战时的令旗

    以下是该段可能出现的参数

    n   ——>1-512间的一个数字,指定对第n次出现的情况进行替换

    g   ——>全局替换

    p   ——>打印

    w   ——>将样本写入到某个文件中

      注:替换指令应用于与address匹配的行,如果没有指定地址,那么就应用于与pattern匹配的所有行,Flag段中的指令可组合使用

     

    2、replacement段可能出现的参数

    &   ——>表示用正则表达式匹配的内容进行替换

      例如:一篇文章里面有很多关键字,如:社会主义,现在我想在每个社会主义后面都加一个好并且用括号括起来

     

    $s/社会主义/(&好)/g    ——>(生产环境估计是没有中文,这里主要是为了大家好理解,而这样写的)

     

    \n   ——>匹配第n个子串(n是一个数字),这个子串需要在pattern中用 “\(\)” 包围

      例:现在文章中的关键字有司马光,小李,猴子,现在想变成司马光砸缸子,小李飞刀,猴子偷桃

    $s/\(司马光\)\(小李\)\(猴子\)/\1砸缸子\2飞刀\3偷桃/

     

    \   ——>转义特殊符号,在相关文档中提到 "\" 也可以当作换行符来用

      注:The backslash is generally used to escape the other metacharacters but it is also used to include a newline in a replacement string(反斜杠通常用来逃避其他元字符,但也可以使用它包括一个换行符字符串替换).

     

    追加,插入和更改  ——>这些命令的语法在sed中不常用,因为它们必须在多行上来指定,语法如下:

    追加 [line-address]a\
    text
    插入 [line-address]i\
    text
    修改 [address]c\
    text

     

    替换文件中不可正常输出的字符   ——>曾经使用过man 查看文档,并把文档重定向的朋友一定知道用firefox或者gedit这类工具打开重定向的文档时会出现很多小方块,那些小方块是用来调节格式的,而ff和gedit不认识而已

      查看不可见字符,如换行:

    $Sed –n –e “l” file

    这时便可以看见了,针对文档拿掉那些符号即可

     

    读和写文件    ——>语法如下:

    [line-address]r file
    [address]w file

    ——>这些是非常实用的功能

      例如在代码中结尾处有 “;” 的地方给予提示

    代码如下

    #/;$/r file

    执行效果

    sed -f scr index.php
    <?php
    /**
     * Front to the WordPress application. This file doesn't do anything, but loads
     * wp-blog-header.php which does and tells WordPress to load the theme.
     *
     * @package WordPress
     */
    /**
     * Tells WordPress to load the WordPress theme and output it.
     *
     * @var bool
     */
    define('WP_USE_THEMES', true)
    this is (;)
    /** Loads the WordPress Environment and Template */
    require('./wp-blog-header.php');
    this is (;)

     

     现在来看看如何写文件脚本

    有一份人员清单,里面包括必要的信息,现在按地理位置进行划分。

      清单如下

    Adams, Henrietta        Northeast

    Banks, Freda            South

    Dennis, Jim             Midwest

    Garvey, Bill            Northeast

    Jeffries, Jane          West

    Madison, Sylvia         Midwest

    Sommes, Tom             South

      代码如下

    /Northeast$/{
    s///
    w region.northeast
    }
    /South$/{
    s///
    w region.south
    }
    /Midwest$/{
    s///
    w region.midwest
    }
    /West$/{
    s///
    w region.west
    }

     

    字符串的转换   ——>同样是使用比较多的一种

       如:将abc中的每个字符都转换成xyz中的等价字符。

    y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/

     

    打印行号

      ——>想知道require都在哪几行出现,实现这个功能需要用到 “=” 

    代码如下

    /require/{
    =
    p
    }

    执行效果

    # sed -n -f scr index.php

    17

    require('./wp-blog-header.php');

     

    打印n行后退出

    Sed '10q' file      ——>打印10行后退出

     

    九、Sed中的高级命令

      引用作者的一句话: You can consider yourself a true sed-master once you understand the commands presented here(当你把这些命令玩明白,你就可以说精通sed了)

     

    1、改变不连贯的语句

    本例中要用的是N命令,N通过读取新的输入行,并将它添加到pattern段的现有内容之后来创建多行replacement空间,通过语言实在很难描述清楚,大家来看底下的例子

    文章:Consult Section 3.1 in the Owner and Operator 

      Guide for a description of the tape drives,available on your system.

      Look in the Owner and Operator Guide shipped with your system.

      Two manuals are provided including the Owner and Operator Guide and the User Guide.The Owner and 

      Operator Guide is shipped with your system.

      在这篇文中中我想把 Owner and Operator Guide 都变为 just do it ,这里我用橙色标出了最难解决的部分,N就是用来解决他们的

    现在来编写脚本:

    s/Owner and Operator Guide/just do it

      ——>用这行语句先把比较简单的两行解决掉

    /Owner/{

    N

    s/Owner and Operator\nGuide/just do it\

      ——>找到Owner and Operator就给我结束,然后去下一行找Guide

    /

    }  ——>注:\n是换行符,在这里起到分隔的作用。

      实例中Owner and Operator共出现4次,所以下面我将用1,2,3,4来代替,这样也比较清楚,重新执行脚本,可以发现1,2,4都已经被替换了,但是3还是没有变化,问题出在哪里呢?查看:s/Owner and Operator\nGuide/just do it\  对!问题就是着色的部分,那如何解决呢?用 来解决

    s/((Owner and Operator|Owner and)|(\nGuide|\nOperator Guide))/just do it\

      全部代码如下

    s/Owner and Operator Guide/just do it/
    /Owner/{
    N
    s/Owner and Operator\nGuide/just do it\
    /
    }
    /Owner and/{
    N
    s/Owner and\nOperator Guide/just do it\
    /
    }

      代码改良后

    s/Owner and Operator Guide/just do it/
    /Owner/{
    N
    s/\n/ /      ——>精华(实际上是偷梁换柱把换行符给弄成空格)
    s/Owner and Operator Guide/just do it\
    /
    }

     

  • 相关阅读:
    PHP面向对象----- 类的自动加载
    PHP基础知识------页面静态化
    Laravel 开发环境搭建
    jenkins相关学习
    markdown语法学习强化
    bind 使用和配置记录
    关于整形和浮点型的格式输出
    函数体中定义的结构体和类型
    Volatile & Memory Barrier
    各种简单排序算法模版
  • 原文地址:https://www.cnblogs.com/sbaicl/p/2725414.html
Copyright © 2011-2022 走看看