《Linux命令行与shell脚本编程大全》第十九章 初识sed和gawk
这两个工具能够极大简化需要进行的数据处理任务。
19.1 文本处理
能轻松实现自动格式化、插入、修改或删除文本元素的简单命令行编辑。
sed和gawk就具备上述功能
19.1.1 sed编辑器
被称为流编辑器。
流编辑器会在编辑器处理数据之前预先提供的一组规则来编辑数据流。
sed根据命令来处理数据流中的数据。命令可以从命令行输入,也可以存储在一个命令文本文件中。
sed编辑器会执行下列操作:
1)一次从输入中读取一行数据
2)根据所提供的编辑命令匹配数据
3)按照命令修改流中的数据
4)将新的数据输出到STDOUT
sed将所有命令与一行数据匹配完毕后,就读取下一行重复这个过程。
sed命令格式如下:
sed options script file
选项允许修改sed命令的行为,可以使用的选项在下表:
选项 | 描述
-e script | 在处理输入时,将script中指定的命令添加到已有的命令中
-f file | 在处理输入时,将file中指定的命令添加到已有的命令中
-n | 不产生命令输出,使用printf命令来完成输出
一般是单个命令,如果需要多个命令,加上-e选项,并用分号隔开,命令末尾和分号之间不能有空格。
1.在命令行定义编辑器命令
默认情况下,sed编辑器会将指定的命令应用到STDIN输入流上。这样可以直接将数据通过管道输入给sed命令处理
$echo “hahaha, I am xiaochongyong” | sed ‘s/xiaochongyong/Kobe Bryant/’
把xiaochongyong替换成了Kobe Bryant。
sed将结果发送到STDOUT
还可以这样修改指定文件中的数据:
$sed ‘s/dog/cat/’ my.txt
// 将my.txt的dog换成cat输出。这样并不会改变my.txt.而是输出到了STDOUT
2. 使用多个编辑命令
需要用-e选项;
$sed –e ‘s/dog/cat/; s/red/yellow/’ my.txt
sed命令会将指定的每条命令应用到文本文件中的每一行上。
3. 从文件中读取编辑命令
需要用-f选项来指定文件。
sed会读取指定文件中命令,并且应用到数据文件中的每一行
比如:
file.sed中有
s/dog/cat/
s/red/blue/
s/xiao/yang/
可以这么用:
$sed –f file.sed my.txt.
窍门:可以用.sed作为sed脚本文件的扩展名
19.1.2 gawk程序
它提供了一种编程语言而不只是编辑器命令,在gawk编程语言中,可以做:
1)定义变量保存数据
2)使用算术和字符串操作符来处理数据
3)使用结构化编程的概念来为数据处理增加处理逻辑
4)通过提取数据文件中的数据元素,将其重新排列或格式化,生成格式化报告。
gawk程序的报告生成能力通常用来从大文本文件中提取数据元素,并将它们格式化成可读的报告。比如格式化日志文件,找出日志文件中的错误行。
1.gawk命令格式
gawk options program file
下面是可用选项的说明:
-F fs 指定行中划分数据字段的字段分隔符
-f file 从指定的文件中读取程序
-v var=value 定义一个变量var并设置默认值
-mf N 指定要处理的数据文件中的最大字段数
-mr N 指定数据文件中的最大数据行数
-w keyword 指定gawk的兼容模式或警告等级
它的强大之处在于程序脚本,可以写脚本来读取文本行中的数据,然后处理并显示数据,创建任何类型的输出报告。
2. 从命令行读取程序脚本
gawk程序脚本用一对花括号来定义。必须将脚本命令放到两个花括号{}中间。
比如:
$gawk ‘{print “hello, shell”}’
因为没有指定文件名,所以这个gawk程序会从STDIN接收数据,运行时会一直等待从STDIN输入的文本。
Ctrl+D会在bash中产生一个EOF字符,可以终止该程序。
3. 使用字段字段变量
它会自动给一行中的每个数据元素分配一个变量。
比如:
$0 表示整个文本行
$1 表示文本行中的第1个数据字段
$2 表示文本行中的第2个数据字段
$n 表示文本行中的第n个数据字段
例子:
$gawk ‘{print $2}’ data.txt // 输出data.txt所有行的第2个数据字段
默认是用空格分隔的,也可以指定其他分隔符。
比如:
$gawk –F: ‘{print $1}’ /etc/passwd // 输出/etc/passwd第一个字段,用冒号分隔的。
4. 在程序脚本中使用多个命令
命令中间放个分号就好了
$echo “My name is xcy” | gawk ‘{%2 = “age”; $4 = 23; print $0}’
注意:age两边需要双引号, =前后可以有空格,也可没有空格。
5. 从文件中读取程序
比如有个脚本test.gawk内容如下:
{print $1 “’s home is ” $6}
用法:
$gawk –F: -f test.gawk /etc/passwd
test.gawk内容还可以是这样:这样相当于指定了多条命令,每条命令分行放开就好了。
{
text=”’s home is ”
print $1 text $6
}
6. 在处理数据前运行脚本
gawk还允许指定程序脚本何时运行。
默认gawk会从输入中读取一行文本,然后针对该行的数据执行程序脚本。
有时候会需要在处理数据前运行脚本,BEGIN就是用来做这个的。
比如:
$gawk ‘BEGIN {print “The test3 file:”} {print $0}‘ test3
高亮部分是命令,红字是BEGIN处理。BEGIN后面也是一段脚本,也需要用{}括起来。
7. 在处理数据后运行脚本
跟BEGIN蕾西,还可以指定在读取完数据后执行的脚本。
比如:
$gawk ‘BEGIN {print “The test3 file:”} {print $0} END {print “The file End”} ‘ test3
红色是END指定的脚本。
例子:
文件ga.gawk:
1 BEGIN {
2 print “The latest list of users and shells”
3 print “UserID \t Shell”
4 print “——— \t ———“
5 FS=”:”
6 }
7
8 {
9 print $1 ” \t” $7
10 }
11
12 END{
13 print “This concludes the listing”
14 }
用法:
$gawk –f ga.gawk /etc/passwd
运行一下效果,小惊喜哦。
19.2 sed编辑器基础
19.2.1 更多的替换选项
1. 替换命令语法:
s/pattern/replacement/flags
flags有四种选项:
数字:表明新文本将替换第几处模式匹配的地方。
g:替换所有匹配的文本
p:代表原先行的内容要打印出来
w file:将替换的结果写到文件中去
比如:
$sed ‘s/old/new/2’ data.txt 表示第2个old替换成new。
$sed ‘s/old/new/g’ data.txt 表示全部替换
$sed ‘s/old/new/p’ data.txt 会打印与替换命令中指定的模式匹配的行
$sed -n ‘s/old/new/p’ data.txt -n 会禁止sed编辑器输出
$sed ‘s/old/new/w data.bak’ data.txt w替换标记会产生同样的输出,不过会将输出保存到指定文件中。
sed编辑器的正常输出是在STDOUT中,而只有那些包含匹配模式的行才会保存在指定的输出文件中。(假如data.txt 有3行,第一行第三行有old,第二行没有,那么第二行不会保存在指定的输出文件中)。
2. 替换字符
有时会遇到不太方便在替换模式中使用的字符,比如/
比如,想用c shell替换/etc/passwd 中的bash shell,可以这么干:
$sed ‘s/\/bin\/bash/\/bin\/csh/’ /etc/passwd
// 大概就这格式: s/new/old/
解决方法:运行用其他字符来作为替换命令中的字符串分隔符,比如感叹号。
$ sed ‘s!/bin/bash!/bin/csh!’ /etc/passwd
用其他的符号也可以,比如逗号。这样路径名就更容易理解和阅读了。
19.2.2 使用地址
默认命令会应用于所有的行,但是也可以将命令作用于特定行。
解决方法:行寻址。
有两种行寻址的方法:
1)已数字形式表示行区间
2)用文本模式来过滤出行
命令格式:
[address] command
也可以将特定地址的多个命令分组
[address] {
command1
command2
command3
}
1. 数字方式的行寻址
指定地址可以是单个行号,比如:
$sed ‘2s/old/new/’ data.txt // 只替换第2行
也可以是起始行加逗号加结束行的一个区间内的行,比如:
$sed ‘2,4s/old/new/’ data.txt // 替换2 – 4行
$sed ‘2,$s/old/new/’ data.txt // 替换2 到结束行, $ 表示最后一行
2. 使用文本模式过滤器
允许指定文本模式来过滤出命令要作用的行。格式如下:
/pattern/command
必须用正斜线将要指定的pattern封起来。sed编辑会将该命令作用到包含指定文本模式的行上。
比如只修改包含xcy 的那一行:
$sed ‘/xcy/s/bash/csh/’ /etc/passed
红字相当于/pattern/,紫色字就是command。
sed编辑器在文本模式中采用了一种称为正则表达式的特性来帮助你创建匹配效果更好的模式。就是上面的 pattern。
3. 命令组合
还可以控制多条命令在指定行中运行。
比如:
$sed ‘2{s/old/new/; s/dog/cat/}’ data.txt
$sed ‘3,${s/old/new/; s/dog/cat/}’ data.txt
19.2.3 删除行
s命令是文本替换
d命令是删除行
比如:
$sed ‘d’ data.txt // 删除指定行
$sed ‘2d’ data.txt // 删除第2行
$sed ‘2,$d’ data.txt // 删除2到最后一行
模式匹配特性也适用于删除命令:
$sed ‘/xcy/d’ data.txt // 删除包含xcy 的行
不会真正在文件中删除,只是在sed命令输出中删除了。
19.2.4 插入和附加文本
sed编辑器允许向数据流插入和附加文本行
插入(insert):命令(i)会在指定行前增加一个新行
附加(append):命令(a)会在指定行后增加一个新行
它们不能在单个命令行上使用,你必须指定是要将行插入还是附加到另一行。
格式如下:
sed ‘[address]command\ new line’
比如:// 这里是插入到line 2的前一行
$echo “This is line 2” | sed ‘i\This is line 1’
或者: // 附加到 line 2的后一行
$echo “This is line 2” | sed ‘a\This is line 1’
要向数据流行内部插入或附加数据,必须要指明加在什么位置。
$sed ‘2a/this is append line’ data.txt
$sed ‘3i/this is append line’ data.txt
下面的例子是增加两行, this is insert line 2′ data.txt 后面按回车,运行命令。
增加多行必须要对cherub或附加的新文本中的每一行使用反斜线,就像下面的this is insert line 1\
xcy@xcy-virtual-machine:~/shell/19zhang$ sed ‘1i\
this is insert line 1\
this is insert line 2′ data.txt
this is insert line 1
this is insert line 2
This is line 1
This is line 2
This is line 3
This is line 4
xcy@xcy-virtual-machine:~/shell/19zhang$
19.2.5 修改行
修改(change)允许修改数据流中整行的内容,它跟插入附加的工作机制一样,必须在sed命令中单独指定新行
$sed ‘2c\This is change line.’ data.txt
$sed ‘2,3c\This is change line.’ data.txt // 这个会用一行把2 3行替换了。
还可以用文本模式来寻址: 对包含line 3的地方进行修改。这个会修改多行。如果匹配到多行的话。
$sed ‘/line 3/c\This is change line.’ data.txt
19.2.6 转换命令
转换(transform)命令(y)是唯一可以处理单个字符的sed命令编辑器命令。
格式如下:
[address]y/inchars/outchars/
转换命令会对inchars和outchars值进行一对一的映射。
inchars的第一个字符会被转换成outchars的第一个字符
inchars的第二个字符会被转换成outchars的第二个字符
以此类推。
inchars和outchars的长度必须一致,否则会报错。
例子:
$sed ‘y/123/abc/’ data.txt // 1->b 2->b 3->c
$sed ‘2,3y/123/abc/’ data.txt // 还可以指定行
转换命令是一个全局命令,它会在文本行中找到的所有指定字符自动进行转换,而不会考虑它们出现的位置
19.2.7 回顾打印
有3个命令也能用来打印数据流中的信息:
p命令用来打印文本行
等号(=)命令用来打印行号
l(小写的L)用来列出行
1.打印行
$echo “This is test” | sed ‘p’
打印文件中的行,-n选项用来禁止sed编辑器的输出,
$sed –n ‘2,3/p’ data.txt
$sed –n ‘/line 2/p’ data.txt // 匹配文本模式中的行
下面是一种复杂的用法,
xcy@xcy-virtual-machine:~/shell/19zhang$ sed -n ‘/3/{
> p
> s/line/new_line/p
> }’ data.txt
This is line 3
This is new_line 3
xcy@xcy-virtual-machine:~/shell/19zhang$
先找到包含数字3的行,再输出,再将指定行的line替换成new_line并输出。输出同时显示了原来的行文本和新的行文本。
2.打印行号
$sed ‘=’ data.txt
还可以打印包含指定文本的内容和行号:打印包含line 3的行号和内容
xcy@xcy-virtual-machine:~/shell/19zhang$ sed -n ‘/line 3/{
> =
> p
> }’ data.txt
3
This is line 3
xcy@xcy-virtual-machine:~/shell/19zhang$
3.列出行
l可以打印数据流中的文本和不可打印的ASCII字符。
$sed ‘l’ data.txt
行尾的换行符会用美元符代替。
19.2.8 使用sed处理文件
1.写入文件
w命令用来想文件写入行,格式如下:
[address]w filename
filename可以是相对路径,也可以是绝对路径,文件需要有写权限。
例子:
$sed ‘2,3w write.txt’ data.txt // 读取2 3行,写入write.txt
$cat write.txt
$sed ‘/xiaochongyong/w write.txt’ data.txt // 读取包含xiaochongyong的行,写入write.txt
$cat write.txt
2.从文件读取数据
读取(read)命令(r)允许你将一个独立文件中的数据插入到数据流中。
格式如下:
[address]f filename
在读取命令中使用地址区间,只能指定单独一个行号或文本模式地址,sed编辑器会将文件中的文本插入到指定地址后。
例子:
$sed ‘3r read.txt’ data.txt // 将read.txt的数据插入到data.txt的第三行中
$sed ‘$r read.txt’ data.txt // 在数据流的末尾添加文本
$sed ‘/xiaochongyong/r read.txt’ data.txt // 还可以用文本匹配
还可以这么用:
xcy@xcy-virtual-machine:~/shell/19zhang$ sed ‘/line 2/{
> r read.txt
> d
> }’ data.txt
This is line 1
This is read line 1
This is read line 2
This is read line 3
This is line 3
This is line 4
xcy@xcy-virtual-machine:~/shell/19zhang$
带下划线的是read.txt中的内容。
这个例子先找到包含line 2的行,然后读取read.txt中的内容,然后再删除原来包含line 2的那行。
19.3 小结
使用sed和gawk程序的关键在于如何使用正则表达式。正则表达式是为提取和处理文本文件中数据创建定制过滤器的关键。