Linux下命令行(三)之文本处理高级工具

【正则表达式】
正则表达式是用来描述一系列字符串的简洁的符号组合。构成一个正则表达式的基本元素有:
  普通字符:字母、数字、下划线、空格等等
  元字符:有特殊含义的字符或字符串

正则表达式元字符及其优先级:

元字符类别 作用 示例
圆括号 分组或捕获 (...)  (?:...)  (?<LABEL>...)
量词 用于修饰 a*  a+  a?  a{m,n}
锚位 用于定位 ^a  a$
序列 由普通字符组成 abc  d2
择一 选择一个序 a|(bc)|d
元素 构成正则表达式的元素 a  [abc]  \d  \s  \w  \1

注意:优先级从上到下依次减小,但其中锚位和序列的优先级是相同的。

【sed 基础
流式编辑器 sed 是作为 shell 程序的编辑器而开发的。它是流式化的,输入被读取后,在内部修改,修改后的内容被打印出来,而输入文件并没有被真正改变。它的语法格式如下:

sed 'script' files

其中,参数 script 是能够被 sed 理解的一些命令(可以是系统中的命令,也可以是自己写的脚本命令);参数 files 是输入文件。其中,参数 script 两边的单引号是为了防止 shell 进行通配符匹配或者额外的置换操作。
如果没有给出需要处理的文件,则 sed 将从标准输入中读取字符流。这使得 sed 可以用于文本过滤。sed 命令运行的执行的操作如下所示:
(1)从一个输入文件中读取一行;
(2)做一个这一行的拷贝;
(3)对这个拷贝行进行处理,即执行参数 script 指定的程序;
(4)到下一行,从第 1 步开始重复流程,直到文本结束;

参数 script 通常由下列形式的一行或多行组成:

/pattern/ action

其中, pattern 就是一个正则表达式,而 action 是 sed 遇到 pattern 时才去执行的操作。可以指定多重 pattern 和 action 对。当 script 被执行时,它对每个记录进行如下操作:
(1)每个 pattern 被持续地搜索,直到找到一个匹配或者到达记录结尾;
(2)当一个匹配被发现时,就对该记录执行相应的 action 动作;
(3)当 action 完成时,下一个 pattern 将会被使用并重复第 1 步;
(4)当所有的 pattern 都完成时,下一行将被读取,然后重复第 1 步;

常用的action动作如下:

操作 描述
p 打印行
d 删除行
s 用一个表达式置换另一个表达式

如果缺省了 pattern,则对每一行都执行 action 操作。
需要注意的是,在使用 p 动作时,默认的 sed 属性是把它处理的每一行都打印出来,可以使用选项 n 来禁止 sed 的这个动作。语法格式如下:

sed -n 'script' files

对于替换动作 s 的使用方式如下:

/pattern/s/pattern1/pattern2/

它 的含义是,对于每一个匹配 pattern 的行,将其中匹配 pattern1 的部分替换成 pattern2 代表的字符序列。但是,在替换操作的使用中,我们发现 pattern 与 pattern1 都用于检索匹配字符序列,所以通常会忽略 pattern ,更加常用的s动作的形式是:

s/pattern1/pattern2/g

它的含义就是将每一行中匹配 pattern1 的部分替换成 pattern2 代表的字符序列。其中,修饰符 g 告诉 sed 进行全局查找替换操作,默认行为是只替换一行中第一个出现匹配的字符序列。当然,也可以不使用这个修饰符。其它修饰符及其作用如下:
    g     全局查找替换
    i      匹配时忽略字母的大小写
    s     使得元字符.在匹配时可以匹配任意一个字符,包括换行符

另外,你可以通过选项 e 来多次执行 sed 操作,如下:

sed -e 'script1' ... -e 'scriptN' files

相当于执行了 N 次 sed 操作。


【awk 基础】
awk 是一个能让你按照匹配来搜索许多文件并有条件地修改文件的工具,实际上它还是一门完整的编程语言。它的基本语法如下:

awk 'script' files

其中,参数 files 是一个文件列表,表示需要处理的文件。参数 script 是如下形式的一个或多个命令的集合:

/pattern/ {actions}

这里的 pattern 是一个正则表达式,actions 是后面将要提到的能被 awk 理解的命令。如果 pattern 被省略了,则 awk 将对输入的每一行进行处理。

awk 最有用的功能是把它的输入分成字段。一个字段是一个字符集合,被一个或多个字段按照分隔符分割开来。默认的字段分隔符是空白符(包括空格符和制表符)。
当 一行被读入时,awk 按照分隔符把这一行解析为多个字段,然后把第一个字段放在变量 1 中,第二个字段放在变量 2 中,以此类推,而变量 0 存储整个行的内容。你可以通过操作符 $ 来提取字段变量的值,如 $1 表示第一个字段的内容。所以,下面的命令让你打印 passwd 文件中的用户名及其 UID :

awk -F: '{print $1, $3}' /etc/passwd

在这个命令中,缺省了 pattern 模式匹配。

awk 作为一门编程语言,它有自己的语法元素:
比较操作符
在 awk 中比较操作符可以用于比较数字和字符串的值,当使用比较操作符时,awk 命令的形式如下所示:

awk 'expression {actions}' files

这里的 expression 由下列比较操作符构成:

操作符 含义
< 小于
<= 小于等于
> 大于
>= 大于等于
== 等于
!= 不等于
value ~ /pattern/ 如果 value 匹配模式 pattern ,则为真
value !~ /pattern/ 如果 value 不匹配模式 pattern ,则为真

正因为有比较操作符,才可以根据每一行中的某个字段的值进行操作。比如下面的命令:

awk -F: '$3 > 500 { print $1, $3 }' /etc/passwd

这里输出所有 UID 高于 500 的用户的用户名及其 UID 。

你可以在 expression 中使用混合表达式,如下所示:

(expr1) || (expr2)
(expr1) && (expr2)

分别表示或和与的含义。比如下面的语句:

awk -F: '($1 ~ /^[fF]lex$/) && ($3 > 500) { print $1, $3 }' /etc/passwd

将打印用户名 Flex 或者 flex 且 UID 大于 500 的用户的用户名和 UID 。

变量
awk 中的变量与 shell 中的变量非常类似:它们都是被赋有一个值的单词。基本的定义变量的语法如下:

name=value

其中,name 是变量名,value 是变量的值。就像 shell 中的变量一样,变量名只能包含字母、数字和下划线,且不能以数字开头。另外,在引用变量的值时,不需要使用 $ 符号,当然前面提到的字段变量是例外。如下:

fruit=peach
fruity=fruit

结果是,变量 fruit 和 fruity 的值都是 peach 。

如果变量的值是数字,你还可以对这些变量进行数值计算,采用的如下形式:

num1 operator num2

awk 中的数值操作符如下所示:

operator 描述
+
-
*
/
% 取模(求余)
^ 求幂

在数值计算中,如果操作数不是数值,而是字符串,则它们的值被 0 替代。例如下面的脚本:

#!/bin/sh
for i in $@
do
    if [ -f $i ] ; then
        echo $i
        awk '/^ *$/ { x=x+1; print x; }' $i        # x 一开始是空值,能够执行 x=x+1 操作的原因就是等号右边的x被0替代了
    else
        echo "ERROR: $i not a file" > &2
    fi
done

流程控制结构

if 语句的格式如下:

awk '{
    if (expr1) {
        action1
    } else if (expr2) {           # 这里是 else if,shell中是 elif,注意区别
        action2
    } else {
        action3
    }
}' files

通常,在 expr 中使用匹配判断。
类似,while 结构如下:

awk '{
    while (expr) {
        action
    }
}' files

另外,还有 do ... while 结构的循环:

awk '{
    do {
        action
    } while (expr)
}' files

最后,for 循环的结构如下:

awk '{
    for (init; test; incr) {
        action
    }
}' files

应该发现,awk 中使用的几种控制结构如 C 中的控制结构是完全相同的。
最后,需要补充的一点是,awk 中默认的字段分隔符是空白符,你可以通过选项 F 来改变字段分隔符,就像上面很多例子中用的那样。

posted @ 2013-02-19 20:06  hi_fly  阅读(847)  评论(0编辑  收藏  举报