第二十一章 sed进阶

N:将数据流中的下一行加进来创建一个多行组(multiline group)来处理。

D:删除多行组中的第一行。

P:打印多行组中的第一行。

sed '/header/{n ; d}' data.txt

首先匹配有header的行,然后n表示移动到文本的下一行,然后进行删除。然后继续搜索data.txt中包含header的行,继续之前的流程。

加入有个文本的内容如下:

[root@localhost ~]# cat data.txt

On Tuesday, the Linux System

Administrator's group meeting will be held.

All System Administrators should attend.

Thank you for your attendance.

现在想把第一行和第二行的System Administrator进行替换成Desktop User,可以这么做:

[root@localhost ~]# sed 'N;s/System.Administrator/Desktop User/' data.txt

On Tuesday, the Linux Desktop User's group meeting will be held.

All Desktop Users should attend.

Thank you for your attendance.

这里使用(.)来匹配空格和换行符这两种情况,但当它匹配了换行符后,它就从字符串中删除了换行符,导致两行合并成一行。这里的N就是将下一行的文本添加到模式空间中已有的文本后。如果不想产生换行,可以这么做:

sed 'N;s/System\nAdministrator/Desktop\nUser/;s/System Administrator/Desktop User/' data.txt

又如文本:

[root@localhost ~]# cat data.txt

On Tuesday, the Linux System

Administrator's group meeting will be held.

All System Administrators should attend.

此时System Administrator在最后一行,如果使用N会错过它,因为没有其它行可读入到模式空间和这行合并,N命令会叫停,可以这么改:

sed 's/System Administrator/Desktop User/;N;s/System\nAdministrator/Desktop\nUser/' data.txt

有这样一个文本:

[root@localhost ~]# cat data.txt

This is the header line.

This is a data line.

This is the last line.

现在想删除第一行空白行:

sed '/^$/{N ; /header/D}' data.txt

首先sed会查找空白行(^$),然后用N命令来讲下一行文本行添加到模式空间。如果新的模式空间内容含有单词header,则D命令会删除模式空间中的第一行。

有个文本:

[root@localhost ~]# cat data.txt

This is the header

line.

This is a data line.

This is the last line.

[root@localhost ~]# sed -n 'N;/header\nline1/P' data.txt

This is the header

模式空间(pattern space)是一块活跃的缓冲区,在sed编辑器执行命令时它会保存待检查的文本,但它并不是sed编辑器保存文本的唯一空间。sed编辑器有另一块保持空间(hold space)的缓冲区域。

h,将模式空间复制到保持空间。

H,将模式空间附加到保持空间。

g,将保持空间复制到模式空间。

G,将保持空间附加到模式空间。

x,交换模式空间和保存空间的内容。

比如有个文本:

[root@localhost ~]# cat data.txt

This is the header

line1.

This is a data line.

This is the last line.

[root@localhost ~]# sed -n '/header/ {h;p;n;p;g;p}' data.txt

This is the header

line1.

This is the header

sed先取出匹配的header行,然后将这行复制到保持空间,然后把下一行放到模式空间并且打印出来,然后再从保持空间复制到模式空间,再打印出来。

[root@localhost ~]# sed -n '/header/!p' data.txt

line1.

This is a data line.

This is the last line.

!p是排除打印。

sed '$!N;s/System\nAdministrator/Desktop\nUser/;s/System Administrator/Desktop User/' data.txt

$!N表示最后一行不执行,匹配后把下一行加入到模式空间,但其余行都执行。

sed '{2,3b; s/This is/Is this/;s/line./test?/}' data.txt

跳过2-3行不进行过滤。

sed '{/first/b jump1;s/This is the/No jump on/;:jump1;s/This is the/Jump here on/}' data.txt

设定匹配first的行为jump1标签,标签匹配的地方使用特定的替换,其余行使用默认替换。

sed '{s/first/matched;t;/s/This is the/No match on/}' data.txt

这是一个if-then语句,首先匹配first,如果匹配替换成matched,然后t后的不执行,如果第一个替换失败,第二个替换会执行。

sed中,&符号可以用来代表替换命令中的匹配的模式:

[root@localhost ~]# echo "The cat sleeps in his hat." | sed 's/.at/"&"/g'

The "cat" sleeps in his "hat".

.at匹配了cat和hat,然后被替换成了"cat"和"hat"。

[root@localhost ~]# echo "The System Administrator manual" | sed 's/\(System\) Administrator/\1 User/'

The System User manual

sed加倍行间距(在每一行已有行之后加入空行)

sed 'G' data.txt

如果最后一行不需要空行:

sed '$!G' data.txt

对可能含有空白行的文本加倍行间距:

sed '/^$/d;$!G' data.txt

给文件中添加行编号:

sed '=' data.txt

打印末尾行:

sed -n '$p' data.txt

第二十二章 gawk进阶

gawk支持两种变量:

内建变量

自定义变量

$1,$2这种是一种内建变量类型---数据字段变量。

gawk数据字段和记录变量:

FIELDWIDTHS,由空格分隔的一列数字,定义了每个数据字段确切宽度

FS,输入字段分隔符

RS,输入记录分隔符

OFS,输出字段分隔符

ORS,输出记录分隔符

比如:

gawk 'BEGIN{FS=",";OFS="-"} {print $1,$2,$3}' data.txt

一旦设置了FIELDWIDTHS,就会忽略FS,并根据提供的字段宽度来计算字段。

gawk 'BEGIN{FIELDWIDTHS="3 5 2 5"} {print $1,$2,$3,$4}' data.txt

输出3位,5位,2位,5位。

默认RS和ORS设为换行符。记录分隔符就是到了这个分隔符算作一个记录。

gawk内建变量:

ARGC,当前命令行参数个数

ARGIND,当前文件在ARGV中的位置

ARGV,包含命令行参数的数组

CONVFMT,数字的转换格式(参见printf语句),默认值为%.6 g

ENVIRON,当前Shell环境变量和期值组成的关联数组

ERRNO,当读取或者关闭输入文件发生错误时的系统错误号

FILENAME,用作gawk输入数据的数据文件的文件名

FNR,当前数据文件中的数据行数

IGNORECASE,设成非零值时,忽略gawk命令中出现的字符出纳的字符大小写

NF,数据文件中的字段总数

NR,已处理的输入记录数

OPMT,数字的输出格式,默认值为%.6 g

RLENGTH,由match函数所匹配的子字符串的长度

RSTART,由match函数所匹配的子字符串的起始位置

NF变量可以在不知道具体位置的情况下指定记录中的最后一个数据字段:

gawk 'BEGIN{FS=":'; OFS=":"} {print $1,$NF}' /etc/passwd

gawk高级用法:

gawk 'BEGIN{var["a"] = 1;var["g"] = 2; for (test in var) { print "Index:" test," - Value:",var[test]}}'

gawk 'BEGIN{FS="," /11/{print $1}' data.txt

匹配11进行输出。

gawk 'BEGIN{FS=","} $2 ~ /^data2/{print $0}' data.txt

第二个字段匹配以data2开头,则打印整个行。

排除:

$1 !~ /expression/

gawk -F: '$4 == 0 {print $1}' /etc/passwd

第四个数据字段尾0,则打印第一个数据字段。

==,等于

<=,小于等于

<,小于

>=,大于等于

>,大于

gawk '{if ($1 > 20) print $1}' data.txt

判断方式。

gawk '{if ($1 >20) { x= $1 * 2; print x} else { x = $1 / 2;print x}}' data.txt

if-else方式。

gawk '{total = 0;i = 1;while (i<4) { total+=$i;i++} avg = total / 3;print avg}' data.txt

gawk '{total = 0;i = 1; do { total += $i;i++} while (total < 150) print total}' data.txt

gawk '{total =0; for (i = 1;i < 4; i++) { total += $i } avg = total / 3;print avg}' data.txt

第二十三章 使用其它Shell

可以尝试学习使用zsh,支持模块化。

第二十四章 编写简单的脚本实用工具

第二十五章 创建于数据库、Web以及电子邮件相关的脚本

对MySQL写脚本的方可用:

mysql mytest -u test <<EOF

show tables;

select * from employees where salary > 40000;

EOF

echo "this is a text message." | mail -s "subject" alex@outlook.com -b johnny@outlook.com -c ruifeng@autolook.com

-s指定主体,-b是bcc,-c是cc。

第二十六章 一些有意思的小脚本

wget -o log.log -O x.html $url

把$url地址的页面存成x.html,输出保存成日志log.log。

wget -nv --spider $url

测试$url是否有效,-nv精简输出。

curl能用来发消息:

[root@localhost ~]# curl http://textbelt.com/intl -d number="15601857483" -d "message=text"

{

 "success": true

}