• Shell通配符与正则表达式

    背景

    Shell的通配符与正则表达式渗透到我们日常的生活和工作当中,虽然简单,但是很重要。有时候我们忙于业务,不总结梳理的话容易连这些基础性的东西用错或概念模糊,所以这里简单梳理总结一下。

    个人总结,技术含量不高,老司机请绕道。

    通配符

    Shell通配符主要用于查找文件,是完全匹配。 比如我们在命令行常用的 find、ls 等基本命令,他们使用通配符来查找符合我们的预期的文件。

    通配符一共有三个: * ? []

    • * 代表任意多个字符
    • ? 代表任意一个字符
    • [] 代表中括号中的一个字符

    我们举些简单的实例看看:

    正则表达式

    正则表达式是一个字符匹配标准,它是包含匹配。如我们常用的 sed、grep、awk 等,各种语言也都支持自己的正则表达式。根据命令支持的匹配功能可分为基础正则表达式和扩展正则表达式。

    由于不同工具以及不同语言之间的正则表达式都略有差异,我们将会限定 POSIX 标准中描述的正则表达式(其包括了大多数的命令行工具)。

    在开始之前我们首先要搞清楚基础正则表达式和扩展正则表达式的区别:

    POSIX规范将正则表达式的实现方法分为了两种:基本正则表达式(BRE)和扩展正则表(ERE)。到目前为止,我们所讨论的正则表达式的所有特性,都得到了兼容POSIX的应用程序的支持,并且都是以BRE的方式实现。grep命令就 是这样的一个例子。

    BRE和ERE到底有什么区别?其实仅仅是元字符的不同!在BRE方式中,只承认^ 、$、 . 、[ 、] 、*这些是元字符,所有其他的字符都被识别为文字字符。而ERE中,则添加了(、 ) 、{ 、} 、?、 + |、等元字符(及其相关功能)。

    也就是说,基础正则表达式默认只识别如下元字符(有特殊含义,需要释义的):

    而扩展正则表达式在这个的基础上增加了几个元字符:

    顾名思义,他就是把基础正则表达式扩展了一下。 举个例子,如果我用基础正则表达式想要过滤出满足或条件的文本时可能很复杂,但是用扩展的 | 元字符就会方便很多:

    在了解了这些之后我们可以举两个常见的正则匹配例子来加深理解:

    到此呢,我们可能对正则表达式呢有了一些基础的概念性了解,也大概能根据需求写一些基本的正则表达式,但是正则表达式绝不会这么简单。 接下来我们进一步的了解一下正则表达式的一些其他知识:

    扩展正则表达式的Alternation功能

    Alternation,顾名思义是轮询的意思,即扩展正则表达式可以实现子表达式的轮询特性。其实我们前面说到的 | 元字符就是最典型的例子,有了 | 之后,我们可以轮流匹配 | 两边的字符pattern。

    但是这里会有问题,就是Alternation特性有时候在子表达式比较多的时候会出现歧义:

    如上,其实我们这样匹配的是以kobe开头的或者包含hello的行,因为他是从左向右匹配的。 那么怎么才能做到我们需求的那样呢 ? 为了把 alternation 和其它子表达式元素结合起来,我们可以使用()来分离子表达式。

    这样就可以了。

    但是也许你会问,为啥加了个()就可以了呢 ?  这个看起来好像我们小学时候学数学时的小括号用来提高优先级的一样: 3*(5-2) 和 3*5-2 的结果是不一样的。 你猜对了,其实加了()就是改变了这个正则式的优先级而已,那么还有哪些优先级限定呢 ?

    正则表达式的优先级

     

    正则表达式相同优先级的从左到右进行运算,不同优先级的运算先高后低。这与算术表达式非常类似。下表从最高到最低说明了各种正则表达式运算符的优先级顺序:

    运算符 描述
    \ 转义符
    (), (?:), (?=), [] 圆括号和方括号
    *, +, ?, {n}, {n,}, {n,m} 限定符
    ^, $, \任何元字符、任何字符 定位点和序列(即:位置和顺序)
    | 替换,”或”操作
    字符具有高于替换运算符的优先级,使得”m|food”匹配”m”或”food”。若要匹配”mood”或”food”,请使用括号创建子表达式,从而产生”(m|f)ood”。

    如上,我们的()优先级比 | 的高,所以现在明白之前那个例子为什么需要通过()来保持Alternation特性了吧 ?

    POSIX 字符集

    POSIX定义了一些字符集,让我们可以快速地指定字符集合的问题方面易于理解并且有效。

    字符集 说明
    [:alnum:] 字母数字字符。在 ASCII 中,等价于:[A-Za-z0-9]
    [:word:] 与[:alnum:]相同, 但增加了下划线字符。
    [:alpha:] 字母字符。在 ASCII 中,等价于:[A-Za-z]
    [:blank:] 包含空格和 tab 字符。
    [:cntrl:] ASCII 的控制码。包含了0到31,和127的 ASCII 字符。
    [:digit:] 数字0到9
    [:graph:] 可视字符。在 ASCII 中,它包含33到126的字符。
    [:lower:] 小写字母。
    [:punct:] 标点符号字符。在 ASCII 中,等价于:
    [:print:] 可打印的字符。在[:graph:]中的所有字符,再加上空格字符。
    [:space:] 空白字符,包括空格,tab,回车,换行,vertical tab, 和 form feed.在 ASCII 中, 等价于:[ \t\r\n\v\f]
    [:upper:] 大写字母。
    [:xdigit:] 用来表示十六进制数字的字符。在 ASCII 中,等价于:[0-9A-Fa-f]

    我们在日常使用中,完全可以通过上面的字符集来方便的表示一些范围,比如 [A-Za-z0-9] 就可以简单的写作 [:alnum:] ,很方便。

     

     

  • Shell 基本概念 —— sed 命令

    背景

    做运维一年了,突然发现自己python和php写了不少。基本的shell却一直搁置没有系统性的去学习总结。 其实在日常工作中,能合理高效的使用shell会提高不少效率。这也是运维工程师必备的基本素质。所以这里决定把一些简单的shell知识点写下来备忘。本博文并没有什么技术含量,主要是用来总结与备忘的,众位求知者可绕行

    内容

    sed 是一种在线编辑器,它一次处理一行内容。处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space),接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接着处理下一行,这样不断重复,直到文件末尾。文件内容并没有改变,除非你使用重定向存储输出。Sed主要用来自动编辑一个或多个文件;简化对文件的反复操作;编写转换程序等。

    option 代表sed的编辑参数,常用的有以下几种:

    command 主要包括 [ n1[,n2] ]  function 。

    n1, n2 :不见得会存在,一般代表(选择进行动作的行数),举例来说,如果我的动作是需要在 10 到 20 行之间进行的,则( 10,20[动作行为] )。

    function:

    典例:查看test.txt 文件中的第3行。

    接下来,我们逐个示范使用options来查看了解:

    1. sed的 a 新增

    典例1: 在第一行后面添加”add one”字符串

    $  sed ‘1a \add one’ test.txt

    典例2: 在第二行到第四行后面添加”add one”字符串

    sed ‘2,4a \add one’ test.txt

    sed ‘2,$a \add one’ test.txt

    典例3: 在含有first的行后面添加”add one” 字符串

    sed ‘/first/a \add one’ test.txt

    2. sed 的i插入

    i命令使用方法和a命令一样的,只不过是在匹配的行的前面插入字符串,所以直接将上面a命令的示例的a替换成i即可。

    3. sed 的c替换

    典例1: 将第2行的内容替换为”add one”字符串

    sed ‘2c \add one’ test.txt

    典例2:将第四行到最后一行的内容替换为”add one”字符串

    sed ‘2,$c \add one’ test.txt

    可以看出,其实还是和之前的a添加格式一模一样,只是功能变了而已。

    4. sed 的d删除

    典例1: 删除第二行到最后一行的内容。

    sed ‘2,$d ‘ test.txt

    典例2: 删除以ha开头,以day结尾的行。

    sed ‘/^ha.*day$/d’ test.txt

    5. sed 的s替换命令

    典例1: 将文件中的所有line替换成text。

    sed ‘s/line/text/g’ test.txt

    感觉和其他的都不太一样,s放在了前面,最后的g是global的意思,也就是全局替换,如果不加g,则只会替换本行的第一个line

    典例2:匹配以ha开始,以day结尾的行,然后再将该行中的happy替换成very happy。

    sed ‘/^ha.*day$/  s/happy/very happy/g’ test.txt

     

    参考:

    http://qifuguang.me/2015/09/21/sed命令详解/

    http://www.cnblogs.com/ggjucheng/archive/2013/01/13/2856901.html

     

     

  • Shell 基本概念 —— awk命令

    背景

    做运维一年了,突然发现自己python和php写了不少。基本的shell却一直搁置没有系统性的去学习总结。 其实在日常工作中,能合理高效的使用shell会提高不少效率。这也是运维工程师必备的基本素质。所以这里决定把一些简单的shell知识点写下来备忘。本博文并没有什么技术含量,主要是用来总结与备忘的,众位求知者可绕行

    内容

    一、 什么是awk?

    awk的主要功能是把文件逐行的读入,以指定的分隔符(默认为空格)将每行切片,切开的部分再进行各种分析处理。

    options 为awk的参数变量,主要常用的有如下三种:

    pattern 为数据中查找的内容,可以有如下方式:

    action 是在找到匹配内容时所执行的一系列命令,主要包括:

    filename 是目标文件。

    典例: 找出/etc/passwd 文件中以root开头的行,并且输出这行的用户名和使用的shell,以及匹配的总行数。

    如上,awk会先从/etc/passwd文件中找出符合pattern格式的行,然后再执行输出去操作。

    二、awk 内置变量

    典例1: 用awk 输出/etc/passwd 的文件名,每行的行号,每行的列数,对应的完整行内容。

    典例2:显示/etc/passwd的账户和账户对应的shell,而账户与shell之间以逗号分割,而且在所有行添加”this is begin”,在最后一行添加”this is end”。

    上面这个例子中,awk工作流程是这样的:先执行BEGIN,然后读取文件,读入有/n换行符分割的一条记录,然后将记录按指定的域分隔符划分域,填充域,$0则表示所有域,$1表示第一个域,$n表示第n个域,随后开始执行模式所对应的动作action。接着开始读入第二条记录······直到所有的记录都读完,最后执行END操作。

    三、awk编程

    awk的编程设计的东西很多,这里挑选几个常用的简单叙述一下:

    1. awk中的变量

    awk设置变量的方式有两种,一种是通过-v参数,在options里面声明。 另一种是直接在action里面定义。 如下:

    count是自定义变量,action{}可以有多个语句,以;号隔开。

    典例: 统计test文件夹下,所有文件的总大小(为字节数)

    2. awk 中的条件判断语句

    awk中的条件语句是从C语言中借鉴来的,见如下声明方式:

    典例2: 将test目录下面大于10k的文件都移到tmp目录下。

    3. awk中的循环语句

    awk中的循环语句同样借鉴于C语言,支持while、do/while、for、break、continue,这些关键字的语义和C语言中的语义完全相同。

    4. awk中的数组

    因为awk中数组的下标可以是数字和字母,数组的下标通常被称为关键字(key)。值和关键字都存储在内部的一张针对key/value应用hash的表格里。由于hash不是顺序存储,因此在显示数组内容时会发现,它们并不是按照你预料的顺序显示出来的。数组和变量一样,都是在使用时自动创建的,awk也同样会自动判断其存储的是数字还是字符串。一般而言,awk中的数组用来从记录中收集信息,可以用于计算总和、统计单词以及跟踪模板被匹配的次数等等。

    典例:显示/etc/passwd的账户,并在前面标上行数

     

    参考:

    http://www.gnu.org/software/gawk/manual/gawk.html

    http://www.cnblogs.com/ggjucheng/archive/2013/01/13/2858470.html

    http://www.cnblogs.com/azheng007/p/3037246.html