流数据处理“三剑客

处理一定规模的数据,尤其是文本数据,是常见的任务需求。比如,检查日志文件、读取配置文件、处理指令的输出等等。这些任务中,都可以将待处理的文本数据整体看做一个数据流,需要对数据流进行各种操作处理。为方便操作,比较常见的方法是,以行为单位,对整个文本数据流进行切割,然后,再针对每一行中的文本,逐行进行各种操作。这也成为了许多文本流处理工具的基础。

在针对流文本数据的处理方面,linux 平台依旧卓绝群伦,提供了多个出色的处理工具,充分体现了分行处理的特点。

cut — 数据提取“剪刀”

cut 的功能简洁明确,就像其英文含义一样,就是“切”,即将一段选定的目标信息从一行文本中“切”出来,提取出来。

从每一行的数据流提取目标信息,又可以细分为几种处理思路,一种是以字符为单位进行处理;另一种是通过文本流数据中呈现的“某种模式”,对一行的数据流进行分段,每个分段为一个单元,以段为单位逐段进行处理,即行内分段处理。采用分段的处理方式,必须要明确的一个关键的问题就是“用什么切断文本流”,即流数据分段依据的确定。

(1) 以字符为单位处理

基本格式:

cut-c 字符范围输入的文本流

其中,字符范围用数字表示,指定了要获取的字符区间,如

  • 1-4 : 前4个字符
  • 12- : 第12个字符开始至行结尾的字符

    pic-1

指令格式中的“输入的文本流”形式多样,可以是从管道传过来的某个指令的输出结果,也可以是一个文件。

(2) 以分段为单位

基本格式:

cut-d ‘分段界定符’   -f 段编号输入的文本流

  • d — delimiter,即定界符,分隔符。用它对行内数据进行分段
  • f — field,即分段后的段编号,域编号

通过自主定义的“分段界定符”,将一行文本流划分为几个不同的段,利用“段编号”,指出提取信息的位置。

pic-2

sed — 流编辑器

sed 是 stream editor 的缩写,从名字上就不难看出,sed 是专门处理文本 “流数据” 的一种编辑器,用于对输入流进行基本的文本变换。作为一种编辑器,sed 与传统的交互式编辑器有着完全不同的特点。sed 没有一个可视化的交互式编辑环境,对用户而言,sed 可以看做一个“黑匣子”,这个“黑匣子”通过执行一组预先定义好的规则,对文本数据流进行处理,并将处理结果输出。而这些预先定义好的规则,通过 sed 编辑器提供的指令集来构建。

pic-4

sed 编辑器处理的核心是文本流。当文件作为 sed 的输入时,sed 处理的是文件转化成的文本流,而不是文件本身,因此,sed 编辑器不会对输入文件本身的原始内容做任何修改,除非明确将输入文件同时也作为输出文件。

sed 以行为单位处理文本流,其的基本格式如下,

pic-3

“外部参数” 和 “内部参数” 的确立是 sed 编辑器应用的关键。其中,外部参数确立 sed 编辑器的整体行为,同时也决定着内部参数的呈现形式。

(1) sed 编辑器外部参数

— 编辑器整体环境参数

这类参数可以调整整个编辑器的输出环境

参数 含义
-e script – – expression=script。
sed 的默认参数(隐性参数),也可在使用时明确写出。
表明后面的 sed 编辑器内部参数是 sed 编辑器的脚本指令集合。
-n – – silence。
输出沉默,即 sed 不会将输出结果自动打印到 stdout。
默认情况下,sed 处理后的输入为 stdout;使用 -n 参数,stdout 不显示 sed 的处理结果。
-f file – – file=script-file。
表明后面的 sed 编辑器内部参数是一个包含 sed 编辑器指令集合的文件。

(2) sed 编辑器内部参数

一般情况下,sed 编辑器内部参数包含在两个单引号(')之间,由 行选择参数sed 编辑器内部指令 两部分内容组成。sed 以行为单位进行编辑,首先,由行选择参数挑选出需要编辑的行,然后,通过编辑器指令,以选出的行为基准,进行特定的编辑。特殊情况是,当 sed 外部参数为 -f 时,sed 内部参数为一个文件。

— 行选择参数

也可称为行地址参数。sed 按行处理文本流。默认情况下,sed 逐行顺序执行设定好的编辑器指令。使用这类参数,可以打破逐行处理的顺序,选择特定的行跳跃进行处理。

行选择参数配置形式非常灵活,支持正则表达式形式,即可以通过数字方式进行行选择,也可以利用正则表达式文本模式匹配方式进行行选择;既可以选择某个特定的单行进行处理,也可以选择多行集合进行处理。

典型的行地址选择参数形式有,

地址 说明
num 行号为正整数 num 对应的那一行。
$ 最后一行。
/reg_exp/ 选择与表达式 reg_exp 匹配的行。
addr1, addr2 选择 addr1 到 addr2 之间的文本行。
addr1, +n 选择 addr1 和其随后的 n 个文本行。
addr! 选择除了 addr 以外的所有文本行。其中,addr 可以是上述任意的地址形式

— 编辑器内部基本指令

编辑器内部基本指令是 sed 编辑器高效运行的核心和关键,sed 利用这套内部指令集合,对选择好的行进行各种文本操作。完成文本替换、增删改行、读取写入打印等任务。

1) 行内操作指令

行内操作指令主要是针对文本流中选定的行内部的文本进行各种操作的指令。

  • s 指令 — substitue 指令

    字符串替换指令。在一行内,用一串文本替换另一串文本。基本格式为,

    s / be_replaced_string / replace_string / [ flags]

    s 指令最基本的任务就是用 replace_string 代替 be_replaced_string。

    flags 是可选标记,利用它可以在这种替换的基础上扩展出额外的功能。flags 有 4 种可用标记,

    flags 标记 说明
    g 即 global,全局替换。
    在默认情况下,s 指令只对本行中第一处匹配的文本进行替换。使用 g 标记,新字符串将替换本行中所有匹配的文本。
    num 定点替换。
    使用 num 标记,新字符串将替换本行中第 num 个匹配的文本。
    p 即 print。
    将完成替换操作的行打印出来。
    标记 p 经常与编辑器整体参数 -n 联合使用,形成替换操作行的特定输出的功能。用 -n 参数先禁止默认的到 stdout 的输出,再利用标记 p 输出进行了替换操作的行。
    w file 即 write,写入文件 file。
    将完成替换操作的行写到文件中。
  • y 指令

    集合替换指令,也可称为字符转换操作。用一个集合的字符替换另一个集合的字符。基本格式为,

    y / be_replaced_set / replace_set /

    将前者 be_replaced_set 中的元素与后者 replace_set 中的元素构建 一一映射,用后者 replace_set 中的字符一对一的替换前者 be_replaced_set 中的字符。

    y 指令本质是集合替换指令。通过构建一个一一映射的函数,完成后面集合对前面集合的替换。既然是集合替换,就要求两个集合中的元素个数相等,即两个字符集合具有相同的长度。两个集合长度不同,sed 编辑器会报错。

    类似字体大小写转换等集合替换任务,使用 y 指令都有良好效果。

2) 行间操作指令

行间操作指令主要是在整个文本流各个行之间进行增删改等操作的各种指令。

  • i 指令 — insert 指令
    • 在指定的行前增加一个新行;
  • a 指令 — append 指令
    • 在指定的行后增加一个新行;
  • d 指令 — delete 指令
    • 删除指定的行;
  • c 指令 — change 指令
    • 修改指定行的内容;

3) 输入输出指令

  • r 指令 — read 文件指令

    [address] r filename

    在选定的行后读入文件内容

  • w 指令 — write 文件指令

    [address] w filename

    将选定的行写入文件

  • p 指令 — print 指令

    [address] p

    将选定的行打印出来

  • = 指令

    打印出选定的行的行号

  • l 指令 — list 指令

    将文本流中可打印的字符、不可打印的字符都 “列(list)” 出来

— 编辑器内部基本指令的组合

sed 编辑器中的各种基本指令,可以通过组合形式完成更为复杂的任务。

1) 显示指令组合

显示指令组合是在命令行直接写出指令组合并执行,基本格式如下,

pic-5

组合指令的应用思路和基本指令一致。首先开展行选择,选定行以后,执行一些列基本指令的集合。在同一个行地址下,执行的多个基本指令,构成一个“指令序列”。不同行选择的指令序列也可以组合到一起,形成更大的指令组合。

指令序列本身的使用格式上,每个指令序列中的指令集合两边用大括号({})包括起来,

  • 当基本指令集合在同一行输入时,基本指令与基本指令之间用分号()分开。
  • 当基本指令集合在不同的行输入时,指令之间可以不使用分号,但行地址参数必须和大括号在同一行输入。
    • 当指令集合中只有一个指令时,可以省略大括号

指令序列组合的使用格式上,可以视作单个指令序列本身格式的更宏观扩展,

  • 当指令序列的集合在同一行输入时,指令序列与指令序列之间用分号()分开。
  • 当指令序列的集合在不同的行输入时,指令序列之间可以不使用分号。

2) 指令文件形式

也可以将多个指令写到一个文件中,利用 sed 编辑器读取外部指令文件的形式实现指令的组合。这种形式就要利用前述编辑器外部参数 -f

基本格式如下,

sed   -f   sed_command_file

一般情况下,sed 指令文件以 .sed 后缀命名。

Reference

  1. 鸟哥的私房菜
  2. Linux Command Line and Shell Scripting Bibll, 3e.
  3. The Linux Command Line.

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注