您的位置:首页 > 其它

sed & gawk

2016-01-01 11:58 405 查看
#################################################################################
#                                 sed命令学习                                   #
#################################################################################

1.sed编辑器被称作流编辑器,跟普通交互文本编辑恰好相反。

2.sed编辑器可以基于输入到命令或是存储在命令文本文件中的命令来处理数据流中的数据。

它每次从输入中读取一行,用提供的编辑器命令匹配数据,按命令中指定的方式修改流中

数据,然后将生成的数据输出到STDOUT。

3.使用sed命令格式:

sed options sccipt file

选项            描述

-e script       在处理输入时,指script中指定的命令添加到运行命令中

-f file         在处理输入时,将file中指定的命令添加到运行的命令中

-n              不要为每个命令生成输出,等待print命令输出

1.1在命令行定义编辑命令

echo "This is a test"|sed 's/test/Laomeng/'   #//替换命令 's/test/text/'
This is a  Laomeng

vi data1

The quick brown jumps over the lazy log.
The quick brown jumps over the lazy log.
The quick brown jumps over the lazy log.
The quick brown jumps over the lazy log.

sed 's/log/cat/' data1  #//将log替换成cat
The quick brown jumps over the lazy cat.
The quick brown jumps over the lazy cat.
The quick brown jumps over the lazy cat.
The quick brown jumps over the lazy cat.

sed -e 's/brown/green/; s/log/cat/' data1  #//多处替换,将log替换成cat,将brown替换green

The quick green jumps over the lazy cat.
The quick green jumps over the lazy cat.
The quick green jumps over the lazy cat.
The quick green jumps over the lazy cat.

备注:必须记住,要在封尾单引号所在行结束命令。bash shell一旦发现在了封尾的单引号,就会

执行命令。

1.2从文件中读取编辑命令

cat data1

The quick brown jumps over the lazy log.
The quick brown jumps over the lazy log.
The quick brown jumps over the lazy log.
The quick brown jumps over the lazy log.

vi script1
s/brown/green/
s/log/cat/

sed -f script1 data1    #//-f指定文件

The quick green jumps over the lazy cat.
The quick green jumps over the lazy cat.
The quick green jumps over the lazy cat.
The quick green jumps over the lazy cat.

#################################################################################
#                                gawk命令学习                                   #
#################################################################################

gawk功能:

-.定义变量来保存数据

-.使用算术和字符串操作来处理数据

-.使用结构化编程概念,比如if-then语句和循环,来为处理数据加强逻辑

-.提取数据文件的数据元素并将它们按照一定的顺序或格式来重新放置,从而生成格式化报告。

1.gawk命令格式:

gawk options program file

gawk选项:

-F fs     指定行中分隔数据字段的字段分隔符

-f file   指定读取程序的文件名

-v var=value 定义gawk程序中的一个变量及其默认值

mf N       指定要处理的数据文件中的最大字段数

-W keyword 指定gawk的兼容模式或警告等级

1.1 从命令中读取程序脚本

gawk '{print "Hello john"}'

hello
Hello john
hello
Hello john
this is test
Hello john

1.2使用数据字段变量

-.$0代表整个文本行

-.$1代表文件行中的第一个数据字段

-.$2代表文件行中的第二个数据字段

-.$n代表文本行中的第n个数据字段

cat data3

One line of test text.
Two line of test text.
Three line of test text.

gawk '{print $1}' data3   #//打印每行文本的第一列

One
Two
Three

gawk -F: '{print $1}' /etc/passwd   #//-F指定分隔":"为判断,取每行文本的第一个字段

root
bin
daemon
adm
lp
sync
shutdown
halt
.....

1.3在程序脚本中使用多个命令

echo " MY name is test " |gawk '{$4="Laomeng" ; print $0}' #//将文本行的第四个字体test替换成 laomeng,并打印整个文本行
" MY name is  Laomeng "

1.4从文件中读取程序

vi script2

{print $1 "'s home is directory is " $6}

gawk -F: -f script2 /etc/passwd   #//script2脚本程序会再次使用print命令打印/etc/passwd文件的主目录数据字段(字段变量$6),以及uesrid数据字段(字段变量$1)

root's home is directory is /root
bin's home is directory is /bin
daemon's home is directory is /sbin
adm's home is directory is /var/adm
lp's home is directory is /var/spool/lpd
sync's home is directory is /sbin
shutdown's home is directory is /sbin
halt's home is directory is /sbin
mail's home is directory is /var/spool/mail
uucp's home is directory is /var/spool/uucp
......

vi script3  #//script3定义了一变量来保存print命令中用到文本字符串。

{
text = "'s home directory is "
print $1 text $6
}

gawk -F: -f script3 /etc/passwd

root's home directory is /root
bin's home directory is /bin
daemon's home directory is /sbin
adm's home directory is /var/adm
lp's home directory is /var/spool/lpd
sync's home directory is /sbin
shutdown's home directory is /sbin
halt's home directory is /sbin
mail's home directory is /var/spool/mail
.........

1.5在处理数据前运行脚本

gawk还允许指定程序脚本何时运行。默认情况下,gawk会从输入中读取一行文本,然后针对文本行的数据执行程序脚本。

gawk 'BEGIN{print "Hello world!!"}'
Hello world!!

cat laomeng4

Line 1
Line 2
Line 3

gawk 'BEGIN{print "The Laomeng4 File Contents:"} {print $0}' laomeng4  #//gawk执行BEGIN脚本后,它会用第二段脚本来处理文件数据
The Laomeng4 File Contents:
2b42d
Line 1
Line 2
Line 3

1.6在处理数据后运行脚本

跟BEGIN关键字类似,END关键字允许你指定一个程序脚本,gawk会读完数据后执行它:

gawk 'BEGIN{print "The Laomeng4 File Contents:"} {print $0} END{print "End of file"}' laomeng4
The Laomeng4 File Contents:
Line 1
Line 2
Line 3
End of file

vi script4

BEGIN {
print "The lalast list of usrs and shells"
print " UserID            Shell"
print "-------           -------"
FS=":"
}

{
print $1"                "$7
}

END {
print "The concludes the listing"
}

gawk -f script4 /etc/passwd
The lalast list of usrs and shells
UserID            Shell
-------           -------
root               /bin/bash
bin                /sbin/nologin
daemon             /sbin/nologin
adm                /sbin/nologin
lp                 /sbin/nologin
sync               /bin/sync
shutdown           /sbin/shutdown
halt               /sbin/halt
........
The concludes the listing

#################################################################################
#                                sed编辑器基础                                  #
#################################################################################

1.替换标记

vi laomeng5

This is a test of the test script.
This is the second test of the test script.

sed 's/test/laomeng/' laomeng5  #//substitute命令在替换多行中的文本时能正常工作,但默认情况下它能替换第行出现的第一处。
#//要让替换命令对一行中不同地方出现的文本都起作用,必须使用替换标记(substitution flas).

This is a laomeng of the test script.
This is the second laomeng of the test script.

多处替换
s/pattern/replement/flags

有四种可用的替换标记:

-1.数字, 表明新文本将替换第几处模式匹配的地方;

-2.g,  表明新文本将会替换所有已有文本出现地方;

-3.p,  表明原来行的内容要打印出来;

-4.w file, 将替换的结果写到文件中;

sed 's/test/laomeng/2' laomeng5  #//将每行第二处的test替换成laomeng
This is a test of the laomeng script.
This is the second test of the laomeng script.

sed 's/test/laomeng/g' laomeng5   #//g将文本行每处的test替换成 laomeng
This is a laomeng of the laomeng script.
This is the second laomeng of the laomeng script.

p替换标记会打印包含与substitute命令中指定的模式匹配的行。通常会和sed的 -n一起使用

vi laomeng6

This is a test line.
This is a different line.

sed -n 's/test/laomeng/p' laomeng6 #//-n选项将禁止sed编辑器输出。但p替换标记会输出修改过的行。将二才配合使用则会只输出被substitute命令修改过的行。
This is a laomeng line.

w替换标记产生同样的输出,不过将输出保存指定到文件中:

sed 's/test/laomeng/w 123.txt' laomeng6  #//将替换结果写到123.txt文件中
This is a laomeng line.
This is a different line.

2.替换字符

sed 's!/bin/bash!/bin/csh!' /etc/passwd   #//感叹号被用作字符串分隔符,使得路径很容易被读取和理解
root:x:0:0:root:/root:/bin/csh
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt

3.使用地址

默认情况下,在sed编辑中使用命令会作用文本数据的所有行。如果你只想将命令作用于特定某行或某些行,

必须使用行寻址(line addressing)

在sed编辑中有两种形式的行寻址:

-1.行的数字范围

-2.用文本模式过滤出某行

格式:

[address]command

address {
command1
command2
command3
}

3.1数字方式的寻址

当使用数字方式的行寻址时,你可以用它们所在文本流中的行位置来引用行,

sed编辑器会将文本流中的第一行分配为第一行,然后继续按顺序为新行分配行号。

在命令中指定的地址可以是单个行号,或是用起始行号,逗号及结尾行号指定的一定范围内的行。

vi laomeng1

The quick brown fox jumps over the lazy dog
The quick brown fox jumps over the lazy dog
The quick brown fox jumps over the lazy dog
The quick brown fox jumps over the lazy dog

sed '2s/dog/cat/' laomeng1  #//将第2行的dog替换cat
The quick brown fox jumps over the lazy dog
The quick brown fox jumps over the lazy cat
The quick brown fox jumps over the lazy dog
The quick brown fox jumps over the lazy dog

sed '2,3s/dog/cat/' laomeng1  #//将第二到三行的dog替换成cat
The quick brown fox jumps over the lazy dog
The quick brown fox jumps over the lazy cat
The quick brown fox jumps over the lazy cat
The quick brown fox jumps over the lazy dog

备注:可能你不知道文本中到底有多少行数据,所以美元符用起来很方便($)

3.2使用文件模式的过滤器

格式:

/pattern/command

grep laomeng /etc/passwd
laomeng:x:505:505::/home/laomeng:/bin/bash

sed '/laomeng/s/bash/csh/' /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
.....
laomeng:x:505:505::/home/laomeng:/bin/csh

3.3组合命令

sed '2{
s/fox/elexplhant/
s/dog/cat/
}' laomeng1
The quick brown fox jumps over the lazy dog
The quick brown elexplhant jumps over the lazy cat
The quick brown fox jumps over the lazy dog
The quick brown fox jumps over the lazy dog

sed '3,${
s/brown/green/
s/lazy/active/
}' laomeng1
The quick brown fox jumps over the lazy dog
The quick brown fox jumps over the lazy dog
The quick green fox jumps over the active dog
The quick green fox jumps over the active dog

4.删除行

可以用delete

删除命令d名副其实,它会删除匹配指定寻址模式的所有行。使用删除命令时要特别小心,

因为你忘记了加一个寻址模式的话,流中的所有文本行都会被删除:

cat laomeng1

The quick brown fox jumps over the lazy dog
The quick brown fox jumps over the lazy dog
The quick brown fox jumps over the lazy dog
The quick brown fox jumps over the lazy dog

sed 'd' laomeng1

vi laomeng7

This is line number1.
This is line number2.
This is line number3.
This is line number4.

sed '3d' laomeng7 #//删除文本行中的第3行数据
This is line number1.
This is line number2.
This is line number4.

sed '2,3d' laomeng7  #//删除文本行中的第2到3行的数据
This is line number1.
This is line number4.

sed '3,$d' laomeng7  #//删除文本行中的第3行至尾部的数据
This is line number1.
This is line number2.

sed '/number1/d' laomeng7  #//文本匹配模式删除相关行的数据
This is line number2.
This is line number3.
This is line number4.

你可以删除用两个文本模式来删除某个范围内的行,操作要小心。指定第一个模式会 "打开" 行删除功能,

第二个模式会 "关闭" 行删除功能。

sed '/1/,/3/d' laomeng7  #//删除文本中的第1行到第3行数据

This is line number4.

vi laomeng8

This is line number 1.
This is line number 2.
This is line number 3.
This is line number 4.
This is line number 1 agin.
This is text you want to keep.
This is the last line in the file.

sed '/1/,/3/d' laomeng8

This is line number 4.

第二个出现数字"1"的行再次触发了删除命令,删除了数据流中的剩余行,因为停止模式再没找到。

当然,如果你指定一个从未在文本中出现的停止模式,会现在另一个问题:

sed '/1/,/5/d' laomeng8

因为删除功能在匹配到第一个模式的时候打开了,但一直没有匹配到结束模式,所以整个数据流都被删除了。

5.插入和附加文件

sed编辑器允许你向数据流插入和附加文本行。        -----------------(标记)

-1.插入(insert)命令i会在指定行前增加一个新行;

-2.追加(append)命令a会在指定行后增加一个新行;

sed '[address]command\
new line'

echo "Test line 2"|sed 'i\Test line 1'
Test line 1
Test line 2

echo "Test line 2"|sed 'a\Test line 1'
Test line 2
Test line 1

要给数据流中插入或附加数据,你必须用寻址来告诉sed编辑器你想数据出现在什么位置。

可以用这些命令时只能指定一个行地址。可以匹配一个数字行号或文本行号,但不能地址区间。

cat laomeng7

This is line number1.
This is line number2.
This is line number3.
This is line number4.

sed '3i\This is an insered line.' laomeng7  #//在文本行中第三行之前插入一行新的数据。
This is line number1.
This is line number2.
This is an insered line.
This is line number3.
This is line number4.

sed '3a\This is an appened line.' laomeng7 #//在文本中第3行后附加一行新的数据
This is line number1.
This is line number2.
This is line number3.
This is an appened line.
This is line number4.

sed '$a\This is a new line of text.' laomeng7  #//在文本行中末尾附加一行新的数据
This is line number1.
This is line number2.
This is line number3.
This is line number4.
This is a new line of text.

6.修改行

修改(change)命令允许修改数据流中整行文本内容,它跟插入和附加命令的工作机制一样,你必须

在sed命令中单独指定新行:

cat laomeng7

This is line number1.
This is line number2.
This is line number3.
This is line number4.

sed '3c\This is a changed line of test.' laomeng7  #//修改文本行中第3行的内容
This is line number1.
This is line number2.
This is a changed line of test.
This is line number4.

sed '/number3/c\This is a changed line of test.' laomeng7  #//文本模式匹修改文本行的某一行的内容
This is line number1.
This is line number2.
This is a changed line of test.
This is line number4.

sed '2,3c\This is a new line of text.' laomeng7 #//将文本行中第2到3行中内容替换成....
This is line number1.
This is a new line of text.
This is line number4.

7.转换命令

转换(transfrom, y)命令是唯一可以处理单个字符的sed编辑器命令,命令格式如下:

[address]y/inchars/outchars/

转换命令进行inchar和outchar值的一对一映射。

inchar中的第一字符会被转换为outchar中的第一个字符,第二个字符也被转换成outchars中的第二字符。

这个映射会一直持续处理完成指定字符。如果inchar和outchar的长度不同,则sed编辑器会产生一个错误消息。

cat laomeng8

This is line number 1.
This is line number 2.
This is line number 3.
This is line number 4.
This is line number 1 agin.
This is text you want to keep.
This is the last line in the file.

sed 'y/123/789/' laomeng8
This is line number 7.
This is line number 8.
This is line number 9.
This is line number 4.
This is line number 7 agin.
This is text you want to keep.
This is the last line in the file.

echo "This 1 is a test of 1 try." |sed 'y/123/789/'
This 7 is a test of 7 try.

sed编辑器替换在文本行中匹配到字符"1"的两个实例,你无法限定只更改字符出现的特定某个地方。

8.回顾打印

-1.小字p命令用来打印文本行;

-2.等号(=)命令来打印行号;

-3.l(L的小写)命令用来列出行。

8.1打印行

echo "This is a test"|sed 'p'
This is a test
This is a test

cat laomeng7
This is line number1.
This is line number2.
This is line number3.
This is line number4.

sed -n '/number3/p' laomeng7  #//-n选项,禁止其他行,只打印包含匹配的文本模式
This is line number3.

sed -n '2,3p' laomeng7
This is line number2.
This is line number3.

sed -n '/3/{p; s/line/laomeng/p}' laomeng7 #//sed编辑器命令会查找包含数字“3”的行,然后执行两条命令。
#//首先,脚本用p命令来打印出该原来的;然后它用s命令替换原版本。
#//输出同时显示了原来的文本和新的文本。

This is line number3.
This is laomeng number3.

8.2打印行号

等号命令会打印行在数据流中的当前行号。行号由数据流中的换行符决定。

每次出现一个先行符,sed编辑器会认为它结束了一行文本。

sed '=' laomeng1
1
The quick brown fox jumps over the lazy dog
2
The quick brown fox jumps over the lazy dog
3
The quick brown fox jumps over the lazy dog
4
The quick brown fox jumps over the lazy dog

sed '=' laomeng7
1
This is line number1.
2
This is line number2.
3
This is line number3.
4
This is line number4.

sed -n '/number4/{p; =}' laomeng7
This is line number4.
4

8.3列出行

列出命令(l)允许打印数据流中的文本和不可打印的ACSII字符。任何不可打印字符都用它们的八进制值前加

一个反斜线或标准C风格的命名法,比如\t来代表制表符;

cat laomeng9

This  line  contains   tabs.

sed -n 'l' laomeng9
This  line  contains   tabs.$

9.用sed和文件一起工作

替换命令包含允许你和文件一起工作的标记。

9.1向文件写入,格式:

[address]w file   #//file可以指定文件的相对路径或绝对路径

sed '1,2w jack.txt' laomeng7  #//将文本行中的1,2行数据写入到jack.txt文件中去
This is line number1.
This is line number2.
This is line number3.
This is line number4.

cat laomeng11

Blum, Kate  Chicago, IL
Mullen, Riley West Lafayette, IN
Snell, Haley Ft.Wayne, IN
Woneker, Matthew    Springfield, IL
Wiseccarrver, Emma  Grant Park, IL

sed -n '/IN/w INcustomers' laomeng11

cat INcustomers
Mullen, Riley West Lafayette, IN
Snell, Haley Ft.Wayne, IN

9.2从文件读取数据

读取命令(r)允许你将一个独立文件中的数据插入到数据流中。

读取命令的格式如下:

[address]r filename

filename参数指定数据文件的绝对或相对路径名。

vi laomeng12

This is an added line.
This is the second added line.

sed '3r laomeng12' laomeng7 #//读取laomeng12文件附加到文件laomeng7的第3行后面
This is line number1.
This is line number2.
This is line number3.
This is an added line.
This is the second added line.
This is line number4.

sed '/number2/r laomeng12' laomeng7
This is line number1.
This is line number2.
This is an added line.
This is the second added line.
This is line number3.
This is line number4.

sed '$r laomeng12' laomeng7
This is line number1.
This is line number2.
This is line number3.
This is line number4.
This is an added line.
This is the second added line.

vi latter

Would the following people:
LIST
please report to the office.

cat laomeng11

Blum, Kate  Chicago, IL
Mullen, Riley West Lafayette, IN
Snell, Haley Ft.Wayne, IN
Woneker, Matthew    Springfield, IL
Wiseccarrver, Emma  Grant Park, IL

sed '/LIST/{
r laomeng11
d
}' latter
Would the following people:
Blum, Kate  Chicago, IL
Mullen, Riley West Lafayette, IN
Snell, Haley Ft.Wayne, IN
Woneker, Matthew    Springfield, IL
Wiseccarrver, Emma  Grant Park, IL
please report to the office.

#################################################################################
#                                正则表达式                                     #
#################################################################################

正则表达式是你定义的,linux工具用来过滤文本的模式模板。

数据流----------------->正则表达式--------------------->匹配的数据
|
|
|
|
|
|
|
|
|过滤掉的数据
|
|
|
|
|
|

正则表达式是用正则表达式引擎(regular expression engine)实现的。

正则表达式引擎是解释正表达式模式并使用这些模式进行文本匹配的底层软件。

在linux,有两种流行的正则表达式引擎:

-1.POSIX基本正则表达式(BRE)引擎

-2.POSIX扩展正则表达式(ERE)引擎

sed使用 BRE引擎

gawk使用ERE引擎

1.定义BRE模式

最基本的BRE模式是匹配数据流中的文本字符。

1.1纯文本

echo "This is a test"|sed -n '/test/p'
This is a test

echo "This is a test" |sed -n '/trial/p'

echo "This is a test" |gawk '{print $0}'
This is a test

echo "This is a test" |gawk '/test/{print $0}'
This is a test

echo "This is a test"|gawk '/trial/{print $0}'

备注:第一条原则是下达表达式模式都区分大小写。

echo "This is a test" |sed -n '/this/p'

echo "This is a test"|sed -n '/This/p'
This is a test

echo "The books are expensive"|sed -n '/books/p'
The books are expensive

echo "The book are is expensive" |sed -n '/books/p'

echo "This is line number 1" |sed -n '/ber 1/p'
This is line number 1

echo "This is line number1" |sed -n '/ber 1/p'

1.2特殊字符

正则表达式识别的的特殊字符包括:

*[]^$\+?|()

vi laomeng2

The cost is $4.00

sed -n '/\$/p' laomeng2
The cost is $4.00

由于反斜线是特殊字符,如果你要在正达表达式模式中使用它,你必须转义,这样就产生了两个反斜线:

echo "\ is a special character" |sed -n '/\\/p'
\ is a special character

echo "3 / 2" |sed -n '///p'
sed: -e expression #1, char 3: unknown command: `/'

echo "3 / 2" |sed -n '/\//p'
3 / 2

2.锚字符

当你指定一个正达表达式模式时,只要模式出现在数据流中的任务地方,它都会匹配。

有两个特殊字符可以用来将模式锁在数据流中的行首或行尾

2.1锁定在行首

脱字符(caret character, ^)定义从数据流中文本行的行首开始的模式。如果模式位于其他位置而不是

文本行的行首,正则表达式会不成立。

echo "The book store" |sed -n '/^book/p'

echo "Books are great" |sed -n '/^Book/p'
Books are great

备注:区分大小写字母

脱字符会在每个由换行符决定的新数据行的行首检查模式:

vi laomeng3

This is a test line.
this is another test line.
A line tha tests this feature.
Yet more testing of this.

sed -n '/^this/p' laomeng3
this is another test line.

echo "This ^ is a test"|sed -n '/s ^/p'
This ^ is a test

echo "This ^ is a test"|sed -n '/\^/p'
This ^ is a test

如果指定正则表达式模式只用了脱字符,你不需要用反斜线来转义。

但如果你在模式先指定了脱字符,后跟一些额的文本,那么你必须在脱字符前用转义字符。

2.2锁定在行尾

跟在行首查找模式相对的就是在行尾查找。美元($)特殊字符定义了行尾锚点。

将这个特殊的字符加在文本模式之后来指明数据行必须以该文本模式结尾:

echo "This is a good book" |sed -n '/book$/p'
This is a good book

echo "The book is good" |sed -n '/book$/p'

echo "There are a lot of good books" |sed -n '/book$/p'

将尾部的单词book改成复数形式,就意味着它不在匹配下达表达式模式了,尽管book仍然在数据流中。

文本模式必须是模式匹配的行最后的部分。

2.3组合锚点

vi laomeng10

this is a test of using both anchors
I said this is a test
this is a test
I'm sure this is a test.

sed -n '/^this is a test$/p' laomeng10
this is a test

vi laomeng13

This is one test line.

This is another test line.

sed '/^$/d' laomeng13
This is one test line.
This is another test line.

定义的正则表达式模式会查找行首和行尾之间什么都没有的那些行。由于空白行在两个行符之间没有文本,

他们刚好匹配了下达表达式模式,sed编辑器用删除命令d来删除匹配该正则表达式模式的行,因此删除文件中

的所有空白行。

2.4点字符

点字符用来匹配任意的单字符,除了换行符。

但点字符必须匹配一个字符,如果点字符的位置没字符,那么模式就不成立。

vi laomeng14

This is a test of a line.
The cat is sleeping.
That is a very nice hat.
This test is at line four.
at ten o'clock we'll go home.

sed -n '/.at/p' laomeng14
The cat is sleeping.
That is a very nice hat.
This test is at line four.

2.5字符组

点特殊字符在任意字符来匹配某个位置时很有用。但如果你限定匹配哪些字符呢?

在正则表达式中,这些称为字符组(character class)

vi laomeng14

This is a test of a line.
The cat is sleeping.
That is a very nice hat.
This test is at line four.
at ten o'clock we'll go home.

sed -n '/[ch]at/p' laomeng14  #//匹配文本行中有包含[ch]at的单词
The cat is sleeping.
That is a very nice hat.

echo "Yes"|sed -n '/[Yes]/p'
Yes

echo "yEs"|sed -n '/y[Ee]s/p'
yEs

echo "Yes"|sed -n '/[Yy]es/p'
Yes

echo "yeS"|sed -n '/ye[Ss]/p'
yeS

echo "Yes"|sed -n '/[Yy][Ee][Ss]/p'
Yes

echo "yEs"|sed -n '/[Yy][Ee][sS]/p'
yEs

echo "YeS"|sed -n '/[Yy][Ee][Ss]/p'
YeS

vi laomeng16

4353
60633
46201
223001
4353
22203

sed -n '/[0-9][0-9][0-9][0-9][0-9]/p' laomeng16    #//成功过滤了过短的数字,因为最后一个字符组没有字符可匹配,打印出六位数
60633
46201
223001
22203

sed -n '/^[0-9][0-9][0-9][0-9][0-9]$/p' laomeng16  #//加上行首和行尾来界定,成功过滤出5位数
60633
46201
22203

字符组的一个极其常见的用法就是解析拼错的单词,比如用户输入的数据。

可能用创建正则表达式来接受数据中常见的拼写错误。

vi laomeng17

I need to have some maintenance done on my car.
I'll pay that in a seperate invoice.
After I pay for the maintenance my car will be as good as new.

sed -n '/mainten[ae]nce/p ; /sep[ea]r[ea]te/p' laomeng17
I need to have some maintenance done on my car.
I'll pay that in a seperate invoice.
After I pay for the maintenance my car will be as good as new.

2.5排除字符组

在正则表达式模式中,可以反转字符组。可以寻找组中没有的任意字符,而不是寻找组中含有的字符

只要在字符组的开头加个脱字符:

vi data6

the cat is a hat.
This test at line two.

sed -n '/[^ch]at/p' data6  #//通过排除字符组,正则表达模式会匹配c或h之后的任何字符,以及文本模式。
#//由于空格字符也在这类字符中,它通过了模式、
This test at line two.

2.6使用区间

你可以用单破折线符号来在字符组中使用字符区间。

[0-9][a-z][A-Z][a-zA-Z][a-zA-Z0-9]

echo "a8239"|sed -n '/[a-z][0-9]/p'
a8239

echo "a8239"|sed -n '/[0-9][0-9][0-9][0-9][0-9]/p'

echo "a8239"|sed -n '/[a-z0-9][0-9][0-9][0-9][0-9]/p'
a8239

echo "8239a"|sed -n '/^[0-9][0-9][0-9][0-9][0-9]$/p'

cat laomeng14

This is a test of a line.
The cat is sleeping.
That is a very nice hat.
This test is at line four.

sed -n '/[a-ch-m]at/p'  laomeng14
The cat is sleeping.
That is a very nice hat.

cho "I'am getting too fat."|sed -n '/[^a-ch-m]at/p'
I'am getting too fat.

echo "I'am getting too fat."|sed -n '/[a-ch-m]at/p'

2.7特殊字符组

BRE包含了可用来匹配特殊字符类型的特殊字符组。

[[:alpha:]]    匹配任意字母字符,不管是大写还是小写

[[:alnum:]]    匹配任意字母数字字符0-9,A-Z或a-z

[[:blank:]]    匹配空格或制表符

[[:digit:]]    匹配0~9之间的数字

[[:lower:]]    匹配小写字母字符a-z

[[:print:]]    匹配任意可打印字符

[[:punct:]]    匹配标点符号

[[:space:]]    匹配任意空白字符:空格,制表符,NL ,FF , VT 和 CR

[[:upper:]]    匹配任意大写字母字符A-Z

echo "abc" |sed -n '/[[:digit:]]/p'

echo "abc"|sed -n '/[[:alpha:]]/p'
abc

echo "abc123"|sed -n '/[[:digit:]]/p'
abc123

echo "abc123"|sed -n '/[[:alnum:]]/p'
abc123

echo "This is, a test"|sed -n '/[[:punct:]]/p'
This is, a test

echo "This is a test"|sed -n '/[[:punct:]]/p'

2.8星号(*)

在字符后面放置星号(*)说明该字符将会在匹配模式的文本中出现0或多次:

这个模式广泛应用于处理常见拼写错误或在不同语言中有拼写变种的单词。

echo "ik" |sed -n '/ie*k/p'
ik

echo "iek"|sed -n '/ie*k/p'
iek

echo "ieek"|sed -n '/ie*k/p'
ieek

echo "ieeeek"|sed -n '/ie*k/p'
ieeeek

echo "ieeek"|sed -n '/ie*k/p'
ieeek

echo "I'm getting a color TV" |sed -n '/colou*r/p'  #//u*表明字母可能出现或不出现在匹配模式文本中。
I'm getting a color TV

echo "I'm getting a colour TV"|sed -n '/colou*r/p'
I'm getting a colour TV

echo "I ate a potatoe with my lunch."|sed -n '/potatoe*/p'
I ate a potatoe with my lunch.

echo "I ate a potato with my lunch."|sed -n '/potatoe*/p'
I ate a potato with my lunch.

另一个方面的特性是将点(.)特殊字符和星号(*)特殊字符结合起来。这个组合提供了匹配了任意多个

任意字符的模式。通常用在数据流中两个可能相邻或不相邻的文本字符串之间:

echo "this is a reular pattern expression"|sed -n '/reular.*expression/p'
this is a reular pattern expression

它允许指定可能在文本中出现多次的一组字符或一个字符区间:

echo "bt"|sed -n '/b[et]*t/p'
bt

echo "bat"|sed -n '/b[ae]*/p'
bat

echo "bet"|sed -n '/b[ae]*t/p'
bet

echo "btt"|sed -n '/b[ae]*t/p'
btt

echo "baat"|sed -n '/b[ae]*t/p'
baat

echo "baaeet"|sed -n '/b[ae]*t/p'
baaeet

echo "baeeaeeat"|sed -n '/b[ae]*t/p'
baeeaeeat

echo "beakeet"|sed -n '/b[ae]*t/p'

只要a and e出现在b and t字符中的任意组合中(包括根本不出现的情况),模式就匹配了。

如果有任何不在定义的字符组内的其他字符出现,该模式匹配就会不成立。

#################################################################################
#                              扩展正则表达式                                   #
#################################################################################

POSIX ERE模式包括供一些LINUX应用和工具使用的若干额外符号。

gawk程序能够识别ERE模式,但sed不能。

备注:记住sed编辑器和gawk程序的正则表达式引擎之间是有区别的。

gawk程序可以使用大多扩展正则表达式模式匹配符号,并且能提供一些额外的sed编辑器没的额外

过滤功能。但正因为如此,它通常在处理数据流时更慢。

1.1问号(?)

问号类似于星号,不过有点细微的不同。问表明前面的字符可以出现0或1次,但只限于些。

它不会匹配多次出现的该字符:

echo "bt" |gawk '/be?t/{print $0}'
bt

echo "bet"|gawk '/be?t/{print $0}'
bet

echo "beet"|gawk '/be?t/{print $0}'

echo "beeet"|gawk '/be?t/{print $0}'

如果e字符并未在文本中出现,或者它只在文本中出现了一次,那么模式会匹配。

跟星号一样,可以将?问号符和字符组一起使用:

echo "bt"|gawk '/b[ae]?t/{print $0}'
bt

echo "bat"|gawk '/b[ae]?t/{print $0}'
bat

echo "bot"|gawk '/b[ae]?t/{print $0}'

echo "bet"|gawk '/b[ae]?t/{print $0}'
bet

echo "baet"|gawk '/b[ae]?t/{print $0}'

echo "beat"|gawk '/b[ea]?t/{print $0}'

echo "beet"|gawk '/b[ae]?t/{print $0}'

如果字符组中的字符出现了0次或1,模式匹配就成立。如果两字符都出现了,或者如果其中一个字符

出现了两次,模式匹配都不成立。

2.加号(+)

加号类似于星号另一个模式符号,但跟问号也有不同。加号表明前面的字符可以出现1次或多次,

但必须至少出现1次。如果该字符没有出,那么模式就不会匹配:

echo "beet" |gawk '/be+t/{print $0}'
beet

echo "beeet"|gawk '/be+t/{print $0}'
beeet

echo "bet"|gawk '/be+t/{print $0}'
bet

echo "bt"|gawk '/be+t/{print $0}'

加号同样适用于字符组,跟星号和问号的使用方式相同:

echo "bt"|gawk '/b[ae]+t/{print $0}'

echo "bat"|gawk '/b[ae]+t/{print $0 }'
bat

echo "baet"|gawk '/b[ae]+t/{print $0 }'
baet

echo "bet"|gawk '/b[ae]+t/{print $0}'
bet

echo "beat"|gawk '/b[ae]+t/{print $0}'
beat

echo "beet"|gawk '/b[ae]+t/{print $0}'
beet

echo "beeat"|gawk '/b[ae]+t/{print $0}'
beeat

3.使用花括号

ERE中的花括号允许你为可重复的正则表达式指定一个上限。这通常称为区间(interval).

可以用个格式来指定区间:

-1.m----正则表达式准确出现m次;

-2.m, n----正则表达式至少出现m次,至多n次;

备注:默认情况下,gawk程序不会识别正则表达式区间。你必须为gawk程序指定--re-interval命令

选项来识别正则表达式区间。

echo "bt"|gawk --re-interval '/be{1}t/{print $0}'

echo "bet"|gawk --re-interval '/be{1}t/{print $0}'
bet

echo "beet"|gawk '/be{1}t/{print $0}'

通过指定区间为1,你限定了该字符在匹配模式的字符串出现的次数。

如果该字符出现了多次,模式匹配就不成立。

echo "beet"|gawk --re-interval  '/be{2}t/{print $0}'
beet

指定上限和下限:

echo "bt"|gawk --re-interval '/be{1,2}t/{print $0}'

echo "bet"|gawk --re-interval '/be{1,2}t/{print $0}'
bet

echo "beet"|gawk --re-interval '/be{1,2}t/{print $0}'
beet

echo "beeet"|gawk --re-interval '/be{1,2}t/{print $0}'

字符e可以出现一次或两次,这样模式匹配就能成立;否则,模式

匹配就不会成立。

区间匹配同样适用于字符组:

echo "bt" |gawk --re-interval '/b[ae]{1,2}t/{print $0}'

echo "bet"|gawk --re-interval '/b[ae]{1,2}t/{print $0}'
bet

echo "beat"|gawk --re-interval '/b[ae]{1,2}t/{print $0}'
beat

echo "beet"|gawk --re-interval '/b[ae]{1,2}t/{print $0}'
beet

echo "beeat"|gawk --re-interval '/b[ae]{1,2}t/{print $0}'

echo "baeet"|gawk --re-interval '/b[ae]{1,2}t/{print $0}'

echo "baeaet"|gawk --re-interval '/b[ae]{1,2}t/{print $0}'

如果在文件模式中有字母a或e的一到两个实例,这个正则表达式就会匹配。如果

在任何组合中有多于两个出现,它就不会匹配了。

4.管道符号

管道符号允许你在检查数据时,用逻辑OR方式指定正则表达式引擎要用两个或多个模式。

如果任何一个模式匹配了数据流文本,文本就通过了。如果没有模式匹配,数据流文本

匹配就不成立。

格式:expr|expr2|expr3

echo "The cat is asleep" |gawk '/cat|dog/{print $0}'
The cat is asleep

echo "The dog is asleept"|gawk '/cat|dog/{print $0}'
The dog is asleept

echo "The sheep is asleep"|gawk '/cat|dog/{print $0}'

这个例子会在数据流中查找正则表达式cat或dog。正则表达式和管道符号之间不能空格,

否则它们也会加到正则表达式模式中。

管道符号两侧的正则表达式都可用任何正则表达式模式(包括字符组)来定义模式:

echo "He has a hat."|gawk '/[ch]at|dog/{print $0}'
He has a hat.

5.聚合表达式(())

正则表达式模式可以用圆括号聚合起来。当你聚合正则表达模式时,该组就会被成标准字符。

echo "Sat"|gawk '/Sat(urday)?/{print $0}'
Sat

cho "Saturday"|gawk '/Sat(urday)?/{print $0}'
Saturday

聚合和管道符号组:

echo "cat"|gawk '/(c|b)a(b|t)/{print $0}'
cat

echo "cab"|gawk '/(c|b)a|(b|t)/{print $0}'
cab

echo "bat"|gawk '/(c|b)a(b|t)/{print $0}'
bat

echo "bab"|gawk '/(c|b)a(b|t)/{print $0}'
bab

echo "tab"|gawk '/(c|b)a(b|t)/{print $0}'

echo "tac"|gawk '/(c|b)a(b|t)/{print $0}'

模式(c|b)a(b|t)会匹配第一组字母的任意组合以及第二组中字母的任意组合。

#################################################################################
#                             实用中的正则表达式                                #
#################################################################################

1.目录文件计数

echo $PATH |sed 's/:/ /g'
/usr/lib64/qt-3.3/bin /usr/local/sbin /usr/local/bin /sbin /bin /usr/sbin /usr/bin /root/bin

vi countfiles

#!/bin/bash
#count number of file in your PATH

mypath=`echo $PATH |sed 's/:/ /g'`
count=0
for laomeng in $mypath
do
check=`ls $laomeng`
for item in $check
do
count=$[ $count + 1 ]
done
echo "$laomeng - $count"
count=0
done

sh countfiles
/usr/lib64/qt-3.3/bin - 0
/usr/local/sbin - 1
/usr/local/bin - 0
/sbin - 284
/bin - 113
/usr/sbin - 339
/usr/bin - 1584
ls: cannot access /root/bin: No such file or directory
/root/bin - 0

2.验证电话号码

(123)456-7890
(123) 456-7890
123-456-7890
123.456.7890

'/^\(?[2-9][0-9]{2}\)(| |\.)?[0-9]{3}( |-|\.)[0-9]{4}$/'

#!/bin/bash
#script to filter out bad phone numbers
gawk --re-interval '/^\(?[2-9][0-9]{2}\)?(| |-|\.)[0-9]{3}( |-|\.)[0-9]{4}/{print $0}'

echo "317-555-1234"|gawk --re-interval '/^\(?[2-9][0-9]{2}\)?(| |-|\.)[0-9]{3}( |-|\.)[0-9]{4}/{print $0}'
317-555-1234

echo "000-555-1234"|./isphone

vi phonelist

000-000-0000
123-456-7890
212-555-1234
(317)555-1234
(202) 555-9876
33520
123456789
234.123.4567

cat phonelist | ./isphone
212-555-1234
(317)555-1234
(202) 555-9876
234.123.4567

3.解析邮件地址

usrename@hostname

username值可用字母字符以及以下特殊字符:

点号
单破折线
加号
下划线

gawk --re-interval '/^([a-zA-Z0-9_\-\.\+]+)@([a-zA-Z0-9_\-\.]+)([a-zA-Z]{2,5})$/{print $0}'

vi isEmail

#!/bin/bash
gawk --re-interval '/^([a-zA-Z0-9_\-\.\+]+)@([a-zA-Z0-9_\-\.]+)([a-zA-Z]{2,5})$/{print $0}'

echo "rich@here.now"| ./isEmail
rich@here.now

echo "rich@here.now."| ./isEmail

echo "rich@here.n" |./isEmail

echo "rich@here-now"| ./isEmail

echo "rich.hlum@here.now"|./isEmail
rich.hlum@here.now

echo "rich_blum@here.now"|./isEmail
rich_blum@here.now

echo "rich/blum@here.now"|./isEmail

echo "rich#blum@here.now"|./isEmail

echo "rich*blum@here.now"|./isEmail

#################################################################################
#                               sed进阶                                         #
#################################################################################

sed编辑器包含了3个可用来处理多行文本的特殊命令:

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

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

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

1.单行的next命令

小写的n命令会告诉sed编辑器移动到数据流中的下一文本行,而不用重新回到命令的最开始

再重新执行一遍。记住,通常sed编辑器会在移动到数据流中的下一行文本前在这个行上执行

所有定义好的命令。单行next命令改变了这个流程。

vi gm1

This is the header line.

This is data line.

This is the last line.

sed '/^$/d' gm1     #//删除全部空白行
This is the header line.
This is data line.
This is the last line.

sed '/header/{n;d}' gm1  #//删除匹配header行下的空白行
This is the header line.
This is data line.

This is the last line.

2.合并文本行

单行next命令会将数据流中的下一文本行移动到sed编辑器的工作空间(称为模式空间)。

多行版本的next命令(用大写N)会将一文本行加到已经在模式空间的文本上。

这样的作用是将数据流中的两个文本行合并到同一个模式空间。

vi gm2

This is the header line.
This is the first data line.
This is the second data line.
This is the last line.

sed '/first/{N ; s/\n/ / }' gm2
This is the header line.
This is the first data line. This is the second data line.
This is the last line.

sed编辑器会查找含有单词first的那行文本。当它找到了该行,它会用N命令将下行合并到那行,

然后用替换命令s将换行符替换成空格。结果是文本文件中的两行中的两行在sed编辑器的输出中成了一行

vi gm3

The first meeting of the Linux System
Administrator's group will be held on Tuesday.
All System Administrators should atted this meeting.
Thank you for your attendance.

sed  's/System Administrator/Destop User/' gm3
The first meeting of the Linux System
Administrator's group will be held on Tuesday.
All Destop Users should atted this meeting.
Thank you for your attendance.

替换命令会在文本中查找特定的双词短语System Administrator.短语在一行中的话,

事情很好处理,替换命令可以直接替换文本。但是如果短语被分成了两行,替换命令

就无法识别匹配的模式了。

sed 'N; s/System.Administrator/Desktop User/' gm3
The first meeting of the Linux Desktop User's group will be held on Tuesday.
All Desktop Users should atted this meeting.
Thank you for your attendance.

用N命令将下一行和发现第一个单词的那行合并后,即使短语内出现了换行,你仍然可以找到它

注意:替换命令在System和Administrator之间用了通配符模式(.)来匹配空格和换行这两种情况

但当它匹配了换行时,它就从字符串串删除了换行符,导致两行合并成一行。

sed 'N; s/System\nAdministrator/Desktop\nUser/; s/System Administrator/Desktop User/' gm3
The first meeting of the Linux Desktop
User's group will be held on Tuesday.
All Desktop Users should atted this meeting.
Thank you for your attendance.

第一个替换命令专门查找这两个要查找的单词间的换行,并将它放在了替换字符串中。

vi gm4

The first meeting of the Linux System
Administrator's group will be held on Tuesday.
All System Administrators should attend this meeting.

sed 'N ; s/System\nAdministrator/Desktop\nUser/ ; s/System Administrator/Desktop User/' gm4
The first meeting of the Linux Desktop
User's group will be held on Tuesday.
All System Administrators should attend this meeting.

由于System Administator文本出现在了数据流中的最后一行,N命令会错过它,因为没有其他

行可读入到模式空间跟这行合并了。

可以将单行命令N放到命令前面,并将多行命令放到N命令后面:

sed 's/System Administrator/Desktop User/; N; s/System\nAdministrator/Desktop\nUser/' gm4
The first meeting of the Linux Desktop
User's group will be held on Tuesday.
All Desktop Users should attend this meeting.

删除数据流中出现在第一行前的空白行:

cat gm5

This is the header line.
This is a data line.

This is the last line.

sed '/^$/{N; /header/D}' gm5
This is the header line.
This is a data line.

This is the last line.

sed编辑器脚本会查找空白行,然后利用N命令来将下一文本行添加到模式空间。

如果新的模式空间内容含有header单词,则D命令会删除模式空间的第一行。

如果不组合使用N命令和D命令,几乎不可能只删除第一个空白行而不删除其他他空白行。

3.多行删除命令

多行打印(print)命令p沿用了同样的方法,它只打印多行模式空间的第一行。这包括了

模式空间中直到换行符的所有字符。当你用-n选项来阻止脚本输出时,它和显示文本的

单行p命令的用法大同小异:

cat gm3
The first meeting of the Linux System
Administrator's group will be held on Tuesday.
All System Administrators should atted this meeting.
Thank you for your attendance.

sed -n 'N; /System\nAdministrator/P' gm3
The first meeting of the Linux System

当多行匹配出现时,P命令只会打印模式空间中的第一行。多行P命令的强大之处在和N

命令及D命令组合使用才显示出来。

D命令有个特性是会强制sed编辑返回到脚本的起始处,在同一模式空间重复执行这些命令

(它不会从数据流中读取新的文本行)。在命令脚本中加入N命令,你能单步扫过整个模式

空间,将多行一起匹配。

下一步,用P命令,你能打印出第一行,然后用D命令你能删除第一行并回环到脚本的起

处。一旦你回到了脚本的起始处,N命令会读取下一行文本并重新开始这个过程。这个循环

会一直继续下去直到数据流的结尾。

************************************************************
保持空间
************************************************************

模式空间(pattern space)是一块活动缓冲区,在sed编辑执行命令时它会保存sed编辑器

要校验的文本。

sed编辑器还利用了另一块缓冲区,称作保持空间(hold space)你可以在处理模式空间中

其他行时用保持空间来临时保存一些行。

sed编辑的保持空间命令:

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

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

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

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

x                交换模式空间和保持空间的内容

通常,在使用h或H命令将字符移动到保持空间后,最终你要用g,G或x命令将保存的字符串

移回到模式空间。

cat gm2
This is the header line.
This is the first data line.
This is the second data line.
This is the last line.

sed -n '/first/{
h
p
n
p
g
p
}' gm2
This is the first data line.
This is the second data line.
This is the first data line.

(1)sed脚本在地址中用正则表达式过滤出含有单词first的行;

(2)当有含有单词first的行出现时,h命令将该行放到保持空间;

(3)p命令打印模式空间也是就一个数据行的内容;

(4)n命令提取数据中的下一行(This is the second line),并将它放到模式空间;

(5)p命令打印模式空间的内容,现在是第二个数据行;

(6)g命令将保持空间的内容(This is the first data line)放回到模式空间,替换当前文本;

(7)p命令打印空间的当前内容,现在变回一个数据行了.

如果丢掉了一个p,打印顺序相反:

sed -n '/first/{
h
n
p
g
p
}' gm2
This is the second data line.
This is the first data line.

2.排除命令

感叹命令(!)用来排除(negate)命令,也就是让原本起用的命令不起作用。

cat gm2
This is the header line.
This is the first data line.
This is the second data line.
This is the last line.

sed -n '/header/!p' gm2
This is the first data line.
This is the second data line.
This is the last line.

cat gm4
The first meeting of the Linux System
Administrator's group will be held on Tuesday.
All System Administrators should attend this meeting.

sed 'N; s/System.Administrator/Desktop User/' gm4
The first meeting of the Linux Desktop User's group will be held on Tuesday.
All System Administrators should attend this meeting.

sed  '$!N; s/System.Administrator/Desktop User/' gm4
The first meeting of the Linux Desktop User's group will be held on Tuesday.
All Desktop Users should attend this meeting.

反转数据流中的文本顺序。

(1)在模式空间中旋转第一行;

(2)将模式空间中行放到保持空间中;

(3)在模式空间中放入一下行;

(4)将保持空间附加到模式空间后;

(5)将模式空间中的所有内容放到保持空间中;

(6)~(9)重复执行(3)~(5)步,直到所有行都反序放到保持空间中;

(10)提取并打印行。

在使用这种方法时,你不想在处理时打印行。这意味着使用sed的-n命令选项。

下一步决定如何将保持空间文本附加到模式空间文本后面。这可以用G命令完成。唯一

的问题是你不想将保持空间附加到要处理的第一行文本后面。这可以用感叹命令解决:

1!G

下一步就是将新的模式空间(带附加反转的行的行)放到保持空间。需要用h命令

cat gm2
This is the header line.
This is the first data line.
This is the second data line.
This is the last line.

sed -n '{1!G; h; $p}' gm2
This is the last line.
This is the second data line.
This is the first data line.
This is the header line.

************************************************************
改变流
************************************************************

通常,sed编辑器会从脚本的顶部开始执行命令一直到处理脚本尾部(D命令是个例外,它

会强制sed编辑器返回到脚本顶部,而不是读取新的行)。sed编辑器提供了一个方法来改

变命令脚本的流,生成的结果类似于结构化编程环境的结果。

1.跳转

对数据流中的特定行执行一组命令:

跳转(branch)命令b格式如下:

[address]b [label]

address参数决定了哪些行或哪些行的数据会触发跳转命令。

label参数定义了要跳转到的位置。

如果没有加label参数,跳转命令会跳转到脚本的结尾:

cat gm2
This is the header line.
This is the first data line.
This is the second data line.
This is the last line.

sed '{2,3b; s/This is/Is this/; s/line/test?/}' gm2
Is this the header test?.
This is the first data line.
This is the second data line.
Is this the last test?.

跳转命令为数据流中的第2行和第3行跳过了那两个替换命令。

可以为跳转命令定义一个跳转到的会签,而不用直接跳转到脚本的尾部。

标签以冒号开始,最多可以有7个字符:

:label2

要指定标签,将它加到b命令就行。使用标签允许你在匹配的跳转地址跳过一些命令,

但仍然执行脚本中的其他命令:

cat gm2
This is the header line.
This is the first data line.
This is the second data line.
This is the last line.

sed '{/first/b jumb1; s/This is the/No jumb on/
:jumb1
s/This is the/Jumb here on/
}' gm2
No jumb on header line.
Jumb here on first data line.
No jumb on second data line.
No jumb on last line.

跳转命令指定如果匹配文本first出现在该行了,程序应该跳转到标签为jumb1的脚本行。

如果跳转命令模式没有匹配,sed编辑器会继续执行脚本中的命令,包括跳转标签后的命令

(所以,3个替换命令都会在不匹配跳转模式的行上执行)

echo "This, is, a, test, to, remove, commas." |sed -n '{:start; s/,//1p;b start}'
This is, a, test, to, remove, commas.
This is a, test, to, remove, commas.
This is a test, to, remove, commas.
This is a test to, remove, commas.
This is a test to remove, commas.
This is a test to remove commas.

脚本的每次迭代都会删除文本中的第第一个逗号,并打印字符串。

这个脚本有个问题:它永远不会结束。这就创建了一个无穷循环,会一直查找逗号,

直到最后你用crtl+c组合来给它发送一个信号,手动停止它。

#cho "This, is, a, to, remove, commas."|sed -n '{:start;s/,//1p;/,/b start}'
This is, a, to, remove, commas.
This is a, to, remove, commas.
This is a to, remove, commas.
This is a to remove, commas.
This is a to remove commas.
#

现在在跳转命令只会在行中有逗号的情况下跳转。在最后一个逗号被删除后,跳转命令

不会再执行,脚本也能自己正常停止了。

2.测试

类似于跳转命令,测试(test)命令t也用来改sed编辑器脚本的流。测试命令会基于替换

命令的输出跳转到一个标签,而不是基于地址跳转到一个标签。

如果替换命令成功匹配并替换了一个模式,测试命令就会跳转到指定的标签。如果替换

命令未能匹配指定的模式,测试命令就不会跳转。

格式:

[address]t [label]

跟跳转命令一样,在没有指定标签的情况下,如果测试成功,sed会跳转到脚本的结尾。

cat gm2
This is the header line.
This is the first data line.
This is the second data line.
This is the last line.

sed '{
s/first/matched/
t
s/This is the/No match on/
}' gm2
No match on header line.
This is the matched data line.
No match on second data line.
No match on last line.

第一个替换命令会查找模式文本first.如果它匹配了行中的模式,它会替换文本,而且

测试命令跳过后面的替换命令。如果第一个替换未能匹配模式,第二个命令会被执行。

使用测试命令,结束之前用跳转命令未能结束的循环:

echo "This, is, a, test, to, remove, commas." |sed -n '{:start s/,//1p; t start}'
This is, a, test, to, remove, commas.
This is a, test, to, remove, commas.
This is a test, to, remove, commas.
This is a test to, remove, commas.
This is a test to remove, commas.
This is a test to remove commas.

3.模式替代

echo "The cat sleeps in his hat." |sed 's/cat/"cat"/'
The "cat" sleeps in his hat.

在模式中使用通配符(.)来匹配多个单词
echo "The cat sleeps in his hat."|sed 's/.at/".at"/g'
The ".at" sleeps in his ".at".

替换字符串能点通配符号来匹配at前的一个字母。遗憾的是,替换字符字符串未能

匹配要匹配的单词的通配符。

4.and符号

sed 编辑器提供了一个解决方法。and符号(&)用来替换命令中的匹配模式。

不管匹配预定义模式是什么文本,你都能用and符号来在替代模式中调用它。

这让你可以操作匹配预定义模式的任何单词:

echo "The cat sleeps in his cat." |sed 's/.at/"&"/g'
The "cat" sleeps in his "cat".

当模式匹配了单词cat,"cat"出现了替换后的单词里。

当它匹配了单词hat, "hat"就出现了在替换后的单词中。

5.替换单独的单词

and符号会提取匹配替换命令中的指定模式的整个字符串。有时你只想提取这个字符串

的一部分。

sed编辑器用圆括号来定义替换模式的子字符串。然后你可以用替换模式中的特殊字符

来引用每个子字符串。替换字符由反斜线和数字组成。数字表明子字符串模块的位置。

sed编辑器会第一个模块分配字符\1,给第二模块分配字符\2。依此类推。

备注:当你在替换命令中使用圆括号时,你必须用转义字符来将它们识别为聚合字符而

不是普通的圆括号。

echo "The System Administrator manual"|sed 's/\(System\) Administrator/\1 User/'
The System User manual

这个替换命令用一对圆括号将单词System括起来,从而将它识别字符串模块。然后它在替代

模式中使用\1来调用第一个识别的模块。

echo "That furry cat is pretty"|sed 's/furry \(.at\)/\1/'
That cat is pretty

echo "That furry hat is pretty"|sed 's/furry \(.at\)/\1/'
That hat is pretty

echo "1234567"|sed '{
:start
s/\(.*[0-9]\)\([0-9]\{3\}\)/\1,\2/
t start
}'
1,234,567

脚本匹配的模式分成了两个部分:

*[0-9]
[0-9]{3}

这个模式会查找两个子字符串。第一个子字符串是以数字结尾的任意长度的字符。

第二个字符串是一系列三位数字组成的块。如果这个模式在文本中找到了,替代文本

会在两个模块之间加一个逗号,每个模块都会通过其模块位置识别。

************************************************************
在脚本中使用sed
************************************************************

1.使用包装脚本

#!/bin/bash
#shell wrapper for sed editor script to reveres lines

sed -n '{
1!G
h
$p
}' $1

./reverse gm2
This is the last line.
This is the second data line.
This is the first data line.
This is the header line.

2.重定向sed输出
cat fact
#!/bin/bash
#add commas to numbers in factorial answer

factorial=1
counter=1
number=$1

while [ $counter -le $number ]
do
factorial=$[ $factorial * $counter ]
counter=$[ $counter + 1 ]
done
reslut=`echo "$factorial" |sed '{ :start; s/\(.*[0-9]\)\([0-9]\{3\}\)/\1,\2/; t start}'`

echo "Result is $reslut"

./fact 20
Result is 2,432,902,008,176,640,000

3.创建sed实用工具

3.1加倍行距

cat gm2
This is the header line.
This is the first data line.
This is the second data line.
This is the last line.

#sed 'G' gm2
This is the header line.

This is the first data line.

This is the second data line.

This is the last line.

#

G会简单地将保持空间空间附加到模式空间内容后。当你启动sed编辑器时,保持空间只有一个空行。

将它附加到已有行后面。

这个脚本在数据流的最后一行后面也加了一行空白行,使得文件末尾也产生一个行空白行。

如果你不想要这个空白行,你可以使用排除符号(!)和尾行符号($)来确保脚本不会将空白行

加到数据流的最后一行后:

#sed '$!G' gm2
This is the header line.

This is the first data line.

This is the second data line.

This is the last line.
#

3.2对可能含有空白行的文件加倍行间距

vi gm6

This is line one.
This is line two.

This is line three.
this is line four.

#sed '$!G' gm6
This is line one.

This is line two.

This is line three.

this is line four.
#

现在在原来的空白行的位置有3个空白行。这个问题解决办法是,首先删除数据中的所有空白行,然

后G命令在所有行后插入新的空白行。 需要将d和一个匹配空白行的模式一起使用:

/^$/d

#sed '/^$/d;$!G' gm6
This is line one.

This is line two.

This is line three.

this is line four.
#

3.3给文件中的行编号

"="显示数据流中行的行号:

sed '/^$/d;$!G;=' gm6
1
This is line one.

2
This is line two.

5
This is line three.

6
this is line four.

cat gm2
This is the header line.
This is the first data line.
This is the second data line.
This is the last line.

sed '=' gm2
1
This is the header line.
2
This is the first data line.
3
This is the second data line.
4
This is the last line.

解决办法:是将行号和文本放在同一行。

一旦你有了等号命令输出,你可以将输出管道输出给另一个sed编辑脚本,它会用N命令来合并这两行。

sed '=' gm2 |sed 'N; s/\n/ /'
1 This is the header line.
2 This is the first data line.
3 This is the second data line.
4 This is the last line.

3.4打印末尾行

用p命令来打印数据流中所有的行号或匹配某个特定模式的行。

如果你要处理一个长输出(比如日志文件)中的末尾几行,怎么办?

美元符($)代表数据流中最后一行。

cat gm2
This is the header line.
This is the first data line.
This is the second data line.
This is the last line.

sed -n '$p' gm2
This is the last line.

那么,如何用美元符来显示数据流末尾的若干行呢?答案是创建滚动窗口(rolling windows)

滚动窗口是查验模式空间中文本行组成的块常用方法,它会用N命令将它们合并起来。

N命令会将下一行文本附加到已在模式中的文本行后面。一旦你在模式空间有了一块10行的文本

你可以用美元符来检查你是否在数据的尾部。如果你不在结尾,就继续向模式空间增加行,并删除

原来的行(记住D命令,它会删除模式空间的第一行)。

通过N命令循环和D命令,你向模式空间的文本行块增加了新行,同时也删除了旧行。跳转命令会完美

适用于这个循环。要结束循环,只要识别最一些并用Q命令退出就可以。

sed '{
:start
$q
N
11,$D
b start
}' /etc/passwd
ntp:x:38:38::/etc/ntp:/sbin/nologin
apache:x:48:48:Apache:/var/www:/sbin/nologin
saslauth:x:498:76:"Saslauthd user":/var/empty/saslauth:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
pulse:x:497:496:PulseAudio System Daemon:/var/run/pulse:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
tcpdump:x:72:72::/:/sbin/nologin
mockbuild:x:504:504::/home/mockbuild:/bin/bash
laomeng:x:505:505::/home/laomeng:/bin/bash
qemu:x:107:107:qemu user:/:/sbin/nologin

这个脚本首先检查这行是不是数据流中最后一行。如果是,退出(quit)命令就停止循环。

N命令会将下一行附加到模式空间的当前行后。如果当前行在10后面,11,$D会删除模式空间中的

第一行。

************************************************************
删除行
************************************************************

1.删除连续的空白行

删除连续的空白行最简单的方法是用地址区来检查数据流。

/./,/^$/!d

区间是/./到/^$/。区间的开始地址会匹配任何含有至少一个字符的行。区间的

结束地址会匹配一个空行。

cat gm6
This is line one.
This is line two.

This is line three.
this is line four.

sed '/./,/^$/!d' gm6
This is line one.
This is line two.

This is line three.
this is line four.

2.删除开头的空白行

/./,$!d

这个脚本用地址区间来决定哪行删掉,这个区间从含有字符的行开始,一直到数据流结束。

#vi gm7

This is the first line.

This is the second line.
#

sed '/./,$!d' gm7
This is the first line.

This is the second line.

3.删除结尾的空白行

删除结尾的空白行并像删除开头空白行那么容易。就跟打印数据流的结尾一样,

sed '{
:start
/^\n*$/{$d; N; b start}
}'

#vi gm8

This is the first line.
This is the second line.

~
#

sed '{
> :start
> /^\n*$/{$d; N; b start}
> }' gm8
This is the first line.
This is the second line.

4.删除html标签

vi gm9

<html>
<head>
<title> This is the page title</titl>
</head>
<body>
<p>
This is teh <b>first</b> line in the web page. This should provide
some <i>useful</i> information for us to use in our shell script
</body>
<html>

#sed 's/<.*>//g' gm9

This is teh  line in the web page. This should provide
some  information for us to use in our shell script

[root@Jackm Laomeng]#

#sed 's/<[^>]*>//g' gm9

This is the page title

This is teh first line in the web page. This should provide
some useful information for us to use in our shell script

[root@Jackm Laomeng]#

sed 's/<[^>]*>//g; /^$/d' gm9
This is the page title
This is teh first line in the web page. This should provide
some useful information for us to use in our shell script
[root@Jackm Laomeng]#

#################################################################################
#                               gawk进阶                                        #
#################################################################################

gawk支持两种变量:

1.内建变量
2.自定义变量

1.1字和数据行分隔符变量

数据字段变量允许你使用美元符号($)和数据字段行中位置对应的数值来引用该数据中的字段。

变量$1;引用第二个变量$2,依次类推

字段是由分隔符来划定的。字段分隔符是一个空白符,也就是空格或制表符(table)

gawk数据字段和数据行变量

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

FS               输入字段分隔符

RS               输入数据行分隔符

OFS              输出字体分隔符

ORS              输出数据行分隔符

变量FS和OFS定义了gawk如何处理数据流中的数据字段。

print $1 ,$2 ,$3

cat gm1
data11,data12,data13,data14,data15
data21,data22,data23,data24,data25
data31,data32,data33,data34,data35

gawk 'BEGIN{FS=","}{print $1,$2,$3}' gm1
data11 data12 data13
data21 data22 data23
data31 data32 data33

gawk 'BEGIN{FS=","; OFS="-"}{print $1,$2,$3}' gm1
data11-data12-data13
data21-data22-data23
data31-data32-data33

gawk 'BEGIN{FS=","; OFS="---"}{print $1,$2,$3}' gm1
data11---data12---data13
data21---data22---data23
data31---data32---data33

gawk 'BEGIN{FS=","; OFS="<-->"}{print $1,$2,$3}' gm1
data11<-->data12<-->data13
data21<-->data22<-->data23
data31<-->data32<-->data33

vi gm1b

1005.324756.37
115-2.349194.00
05810.1298100.1

gawk 'BEGIN{FIELDWIDTHS="3 5 2 5"}{print $1,$2,$3,$4}' gm1b
100 5.324 75 6.37
115 -2.34 91 94.00
058 10.12 98 100.1

cat laomeng2
Riley Mullen
123 Main Street
Chicago, IL 6061
(312)555-1234

Frank Williams
456 Oak Street
Indianapolis, IN 46201
(317)555-9876

Heley Snell
4231 Elm Street
Detroit, MI 48201
(313)555-4938

gawk 'BEGIN{FS="\n" ; RS=""}{print $1,$4}' laomeng2
Riley Mullen (312)555-1234
Frank Williams (317)555-9876
Heley Snell (313)555-4938

2.数据变量

ARGC           当前命令行参数个数

ARGIND         当前文件在ARGV中的位置

ARGV           包含命令行参数的数组

CONVFMT        数字的转换格式;默认值为:%.6 g

ENVIRON        当前shell环境变量及其值组成的关联数组

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

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

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

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

NF             数据文件中的字段总数

NR             已处理的输入数据行数目

OFMT           数字的输出格式;默认值为%.6 g

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

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

gawk 'BEGIN{print  ARGC,ARGV[1]}' gm1
2 gm1

ARGC变量表明命令行上两个参数。这个包括gawk命令和guamei1参数(记住,程序脚本不算参数

)。ARGV数组从代表该命令的索引0开始,第一个数组值是gawk命令后的第一个命令行参数。

ENVIRON变量它使用关联数组来提取shell环境变量。关联数组用作文本作为数组的索引值,而不可用数值。

gawk 'BEGIN{
> print ENVIRON["HOME"]
> print ENVIRON["PATH"]
> }' /home/laomeng
/home/laomeng
/usr/lib64/qt-3.3/bin:/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/home/laomeng/bin

ENVIRON["HOME"]变量从shell中提取HOME环境变量的值。类似地,ENVIRON["PATH"]提取了PATH环境变量的值。

你可以用这种方法从shell中提取任何环境变量的值来在gawk程序中使用。

当你要在gawk程序中记录数据字段和数据行时,FNR,NF和NR就能可以使用上。

有时你不知道数据行中到底有多少个字段。NF变量允许你指定数据行的中最后一个数据字段,而不用知道它的具体位置:

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

gawk 'BEGIN{FS=":"; OFS=":"}{print $1,$NF}' /etc/passwd
root:/bin/bash
bin:/sbin/nologin
daemon:/sbin/nologin
adm:/sbin/nologin
.................
pulse:/sbin/nologin
sshd:/sbin/nologin
tcpdump:/sbin/nologin
mockbuild:/bin/bash
qemu:/sbin/nologin
laomeng:/bin/bash

NF变量含有数据文件中最后一个数据字段的数据值。

FNR和NR变量彼此类似,但略有不同。FNR变量含有处理过的当前数据文件中的数据行总数,

NF变量则含有处理过数据文件数据行总数:

cat gm1
data11,data12,data13,data14,data15
data21,data22,data23,data24,data25
data31,data32,data33,data34,data35

gawk  'BEGIN{FS=","}{print $1,"FNR="FNR}' gm1 gm1
data11 FNR=1
data21 FNR=2
data31 FNR=3
data11 FNR=1
data21 FNR=2
data31 FNR=3

gawk  'BEGIN{FS=","}{print $1,"NR="NR}' gm1 gm1
data11 NR=1
data21 NR=2
data31 NR=3
data11 NR=4
data21 NR=5
data31 NR=6

gawk '
BEGIN{FS=","}
{print $1, "FNR="FNR, "NR="NR}
END{print "There wre ",NR," records processed"}' gm1 gm1

gawk '
> BEGIN{FS=","}
> {print $1, "FNR="FNR, "NR="NR}
> END{print "There wre ",NR," records processed"}' gm1 gm1
data11 FNR=1 NR=1
data21 FNR=2 NR=2
data31 FNR=3 NR=3
data11 FNR=1 NR=4
data21 FNR=2 NR=5
data31 FNR=3 NR=6
There wre  6  records processed

FNR变量的值在gawk处理第二个数据文件时被重置了,而NR变量则在进入第二个数据文件后

继续计数。结果是,如果只用使用一个数据文件时作为输入,那么FNR和NR的值将会相同。

如果使用多个数据文件作为输入,那么FNR的值会在处理每个数据文件时被重置,而NR值则会

继续计数直到处理完成所有的数据文件。

2.1.1自定义变量

gawk自定义变量可以是任意数目的字母,数字和下划线,但不能以数字开关。

gawk变量名区分大小写。

(1)在脚本中给变量赋值

gawk '
BEGIN{
testing="This is a test"
print testing
}'

gawk '
> BEGIN{
> testing="This is a test"
> print testing
> }'
This is a tes

print语句的输出是testing变量的当前值。

gawk变量可以保存数值和文件值:

gawk '
BEGIN{
testing="This is a test"
print testing
testing=45
print testing
}'

gawk '
> BEGIN{
> testing="This is a test"
> print testing
> testing=45
> print testing
> }'
This is a test
45

赋值语句还可以包含数学表达式来处理数字值:

gawk 'BEGIN{x=4; x= x + 2; print x }'

gawk 'BEGIN{x=4; x= x + 2; print x }'
6

(2)在命令行上给变量赋值

vi script1

BEGIN{FS=","}
{print $n}

gawk -f script1 n=2 gm1
data12
data22
data32

gawk -f script1 n=3 gm1
data13
data23
data33

vi script2

BEGIN{print "The starting value is" ,n; FS=","}
{print $2}

gawk -f script2 n=3 gm1
The starting value is
data12
data22
data32

gawk -v n=3 -f script2 gm1
The starting value is 3
data12
data22
data32

2.1.2处理数组

关联数组跟数字数组不同之处在于它的索引值可以是任意文本字符串。

你不需要用连续数字来标识数组中的数据元素。相反关联数组用各种字符串来引用值。

每个索引都必须是唯一的,并唯一地标识给它赋给它的数据元素。

(1)定义数组变量

格式:var[index] = element

其中var是变量名,index是关联数组的索引值,elemnt是数据元素。

capital["Illinois"] = "Springfield"
capital["Indiana"] =  "Indianpolis"
capital["Ohio"] = "Columbus"

在引用数组变量时,必须包含索引值来提取相应的数据元素值:

gawk 'BEGIN{
capital["Illionios"] = "Springfield"
print capital["Illionios"]
}'

gawk 'BEGIN{
> capital["Illionios"] = "Springfield"
> print capital["Illionios"]
> }'
Springfield

在引用数组变量时,数据元素的值会出现。数据元素值是数字值时也一样:

gawk 'BEGIN{
var[1] = 34
var[2] = 3
total = var[1] + var[2]
print total
}'

gawk 'BEGIN{
> var[1] = 34
> var[2] = 3
> total = var[1] + var[2]
> print total
> }'
37

2.1.3遍历数组变量

关联数组变量的问题在于你可能无法知晓索引值是什么。跟使用连续数字作为索引值的

数字数组不同,关联数组的索引可以是任何东西。

在gawk中遍历一个关联数组:

for ( var in array)
{
statements
}

这个for语句会在每次将关联数组array的下一个索引值赋给变量var时,执行一遍statements。

重要的是记住这个变量是索引值而不是数组元素值。

gawk 'BEGIN{
var["a"] = 1
var["g"] = 2
var["m"] = 3
var["u"] = 4
for ( laomeng in var)
{
print "Index:" ,laomeng, "- Value:",var[laomeng]
}
}' |sort -n

gawk 'BEGIN{
>   var["a"] = 1
>   var["g"] = 2
>   var["m"] = 3
>   var["u"] = 4
>   for ( laomeng in var)
>   {
>     print "Index:" ,laomeng, "- Value:",var[laomeng]
>   }
>   }'
Index: u - Value: 4
Index: m - Value: 3
Index: a - Value: 1
Index: g - Value: 2

索引值不会按任何特定的顺序返回,但它们每个都会有个对应的数据元素值。

gawk 'BEGIN{
>   var["a"] = 1
>   var["g"] = 2
>   var["m"] = 3
>   var["u"] = 4
>   for ( laomeng in var)
>   {
>     print "Index:" ,laomeng, "- Value:",var[laomeng]
>   }
>   }' |sort -n
Index: a - Value: 1
Index: g - Value: 2
Index: m - Value: 3
Index: u - Value: 4

2.1.4删除数组变量

从关联数组中删除数组索引要用一个特别的命令:

delete array[index] #删除命令会从数组中删除关联索引值和相关元素值。

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

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

一旦关联数组中删除了索引值,你就无法再提取它了。

3.1使用模式

BGEGIN
END

3.1.1正则表达工

cat gm1
data11,data12,data13,data14,data15
data21,data22,data23,data24,data25
data31,data32,data33,data34,data35

gawk 'BEGIN{FS=","} /11/{print $1}' gm1

gawk 'BEGIN{FS=","} /11/{print $1}' gm1
data11

gawk 'BEGIN{FS=","} /.d/{print $1}' gm1
data11
data21
data31

3.1.2匹配操作符

匹配操作符(mathing operator)允许将正则表达限定在数据行中的特定数据字段。

匹配操作符是波浪线(~)。你要一起指定匹配操作符中,数据字段变量及要匹配的正则表达式:

$1 ~ /^date/

$1变量代表数据行中的第一个数据字段。这个表达式会过滤出第一个字段以文本data开头的

所有数据行。

gawk 'BEGIN{FS=","} $2 ~ /^data2/{print $0}' gm1
data21,data22,data23,data24,data25

匹配操作符会正则表达式/^data2/来匹配第二个数据字段,该正则表达指明字符串要以

文本data2开头。

gawk -F: '$1 ~ /laomeng/{print $0,$NF}' /etc/passwd
laomeng:x:505:0::/home/laomeng:/bin/bash /bin/bash

第一个数据字段中查找文本laomeng。当它在数据行找到了这个模式时,

它会打印数据行的第一个和最后一个数据字段值。

可以用!符号来排除正则表达式的匹配:

$1 !~ /expression/

gawk -F: '$1 !~ /laomeng/{print $1,$NF}' /etc/passwd
root /bin/bash
bin /sbin/nologin
daemon /sbin/nologin
adm /sbin/nologin
lp /sbin/nologin
sync /bin/sync
shutdown /sbin/shutdown
.............
sshd /sbin/nologin
tcpdump /sbin/nologin
mockbuild /bin/bash
qemu /sbin/nologin

3.1.3数学表达式

gawk -F: '$4 == 0{print $1}' /etc/passwd
root
sync
shutdown
halt
operator
laomeng  #//前5系统默认用户

该脚本会查看第4个字段含有值0的数据行。在linux系统中,有5个用户的账户属于root
用户组。

数学表达式:

x == y: 值x等于y.

x <= y: 值x小于等于y.

x < y:  值x小于y.

x >= y: 值x大于等于y.

x > y:  值x大于y.

cat gm1
data11,data12,data13,data14,data15
data21,data22,data23,data24,data25
data31,data32,data33,data34,data35

gawk -F, '$1 == "data"{print $1}' gm1   #无匹配输出结果

gawk -F, '$1 == "data11"{print $1}' gm1
data11

3.1结构化命令

3.1.1 if语句

gawk编程语句语言支持标准的if-then-else格式的if语句。你必须为if语句定义一个评估条件,

并将其用圆括号括起来。如果条件评估为TRUE,紧跟在if语句后的语句会执行。如果条件评估

FALSE,那这条语句就会被跳过。格式:

if (condition)
statement1

或
if (conditon) statement1

cat gm4
10
5
13
50
34

gawk '{if ($1 > 20) print $1}' gm4 #文件行第一个字段大于20输出
50
34

gawk '{
if ( $1 > 20)
{
x = $1 * 2
print x
}
}' gm4

gawk '{
> if ( $1 > 20)
> {
>   x = $1 * 2
>   print x
> }
> }' gm4
100
68

gawk的if语句也支持else语句,允许在if语句条件不成立的情况下执行一条或多条语句。

gawk '{
if ( $1 > 20 )
{
x = $1 *2
print x
}
else
{
x = $1 /2
print x
}
}'  gm4

gawk '{
> if ( $1 > 20 )
> {
>    x = $1 *2
>    print x
> }
> else
> {
>   x = $1 /2
>   print x
> }
> }' gm4
5
2.5
6.5
100
68

可以在单行上使用else子句,但必须在if语句部分之后使用分号:

if (condition) statement1; else statement2

cat gm4
10
5
13
50
34

gawk '{if ($1 > 20) print $1 * 2;else print $1 /2}' gm4
5
2.5
6.5
100
68

3.1.2 while语句

while语句为gawk程序提供了一个基本的的循环功能。格式:

while (condition)
{
statements
}

while循环允许遍历一组数组,并检查结果结束的迭代的条件。在计算中必须使用每个数据行中的

多个数值时,它能帮得上忙:

cat gm5
130 120 135
160 113 140
145 170 215

gawk '{
total = 0
i = 1
while (i < 4)
{
total += $i
i++
}
avg = total / 3
print "Avarager:",avg
}' gm5

gawk编程语言支持在while循环中使用break和continue语句,允许从循环中跳出:

cat gm5
130 120 135
160 113 140
145 170 215

gawk '{
total = 0
i =  1
while ( i < 4 )
{
total += $i
if ( i == 2 )
break
i++
}
avg = total / 2
print "The average of the first two date elments is:",avg
}' gm5

gawk '{
> total = 0
> i =  1
> while ( i < 4 )
> {
>    total += $i
>    if ( i == 2 )
>       break
>     i++
> }
> avg = total / 2
> print "The average of the first two date elments is:",avg
> }' gm5
The average of the first two date elments is: 125
The average of the first two date elments is: 136.5
The average of the first two date elments is: 157.5

break语句用来在i变量的值为2时从while循环中跳出。

3.1.3 do-whlie语句

do-while语句类似while语句,但会在检查条件语句之前执行命令。格式:

do
{
statements
}while (condition)

cat gm5
130 120 135
160 113 140
145 170 215

gawk '{
total = 0
i = 1
do
{
total += $i
i++
}while (total < 150)
print "The total value is:",total
}' gm5

gawk '{
> total = 0
> i = 1
> do
> {
>   total += $i
>   i++
> }while (total < 150)
> print "The total value is:",total
> }' gm5
The total value is: 250
The total value is: 160
The total value is: 315

4.1 for语句

for语句是许多编程语言用来做循环的常见方法。gawk程序支持C风格的for循环:

for (variable assignment; condition; iteration process)

cat gm5
130 120 135
160 113 140
145 170 215

gawk '{
total = 0
for (i = 1; i < 4; i++)
{
total += $i

}
avg = total / 3
print "Average:",avg
}' gm5

[root@Jackm Laomeng]# gawk '{
> total = 0
> for (i = 1; i < 4; i++)
> {
>     total += $i
>
> }
> avg = total / 3
> print "Average:",avg
> }' gm5
Average: 128.333
Average: 137.667
Average: 176.667

5.1 格式化打印

使用格式化打印命令,称为printf。

gawk中的printf格式:

printf "format string",var1,var2...

format string是格式化输出的关键。它会用文本元素和格式化指定符来具体指定如何呈现

格式输出。格式化指定符是一种特殊的代码,它会指明什么类型变量可以显示以及如何显示。

gawk程序会将每个格式化指定符作为命令中列出的每个变量的占符使用。第一个格式化指定

符会匹配列出的第一个变量,第二个会匹配第二个变量,依次类推.

格式 :

%[modifier]control-letter

其中control-letter是指明显法什么类型的数据值的单字符码,而modifier定义了另一个可

选择格式化特性。

控制字母     描述

c          将一个数作为ASCII字符显示

d           显示一个整数值

i           显示一个整数值(跟d一样)

e           用科学计数法显示一个数

f           显示一个浮点值

g           用科学计数法或浮点数中较短的显示

o           显示一个八进制值

s           显示一个文本字符串

x           显示一个十六进制值

X           显示一个十六进制值,但用大写字母A~F

gawk 'BEGIN{
x = 10 * 100
printf "The answer is: %e\n",x
}'

gawk 'BEGIN{
>     x = 10 * 100
>     print "The answer is: %e\n",x
>     }'
The answer is: %e
1000

gawk 'BEGIN{
> x = 10 * 100
> printf "The answer is: %e\n",x
> }'
The answer is: 1.000000e+03

width: 指定了输出字段最小宽带的数字值。如果输出短于这个值,printf会向右对齐,

并用空格来填充这段空间。如果输出比指定的宽度还要长,它就会覆盖width值。

prec:指定了浮点数中小数点后面位数的数字值,或者文本字符串显示的最大字符数。

-(减号):减号指明在向格式化空间中放入数据时采用左对齐而不是右对齐。

cat data2
Riley Mullen
123 Main Street
Chicago, IL 6061
(312)555-1234

Frank Williams
456 Oak Street
Indianapolis, IN 46201
(317)555-9876

Heley Snell
4231 Elm Street
Detroit, MI 48201
(313)555-4938

gawk 'BEGIN{FS="\n"; RS=""} {print $1,$4}' data2
Riley Mullen (312)555-1234
Frank Williams (317)555-9876
Heley Snell (313)555-4938

gawk 'BEGIN{FS="\n";RS=""}{printf "%s %s\n",$1,$4}' data2
Riley Mullen (312)555-1234
Frank Williams (317)555-9876
Heley Snell (313)555-4938

cat gm1
data11,data12,data13,data14,data15
data21,data22,data23,data24,data25
data31,data32,data33,data34,data35

gawk 'BEGIN{FS=","}{printf "%s ",$1}END{printf "\n"}' gm1
data11 data21 data31

gawk 'BEGIN{FS="\n";RS=""}{printf "%16s %s\n",$1,$4}' data2
Riley Mullen (312)555-1234
Frank Williams (317)555-9876
Heley Snell (313)555-4938

gawk 'BEGIN{FS="\n"; RS=""}{printf  "%-16s %s\n",$1,$4}' data2
Riley Mullen     (312)555-1234
Frank Williams   (317)555-9876
Heley Snell      (313)555-4938

cat gm5
130 120 135
160 113 140
145 170 215

gawk '{
total = 0
for ( i = 1; i < 4; i++)
{
total += $i
}
avg = total / 3
printf "Average: %5.1f\n",avg
}' gm5

gawk '{
> total = 0
> for ( i = 1; i < 4; i++)
> {
>   total += $i
> }
> avg = total / 3
> printf "Average: %5.1f\n",avg
> }' gm5
Average: 128.3
Average: 137.7
Average: 176.7

6.1 内建函数

6.1.1 数学函数

gawk数学函数

函数               描述

atan2(x,y)         x/y反正切,x和y以弧度为单位

cos(x)             x的余弦,x以弧度为单位

exp(x)             x的指数函数

init(x)            x的整数部分,取靠近零一侧的值

log(x)             x的自然对数

rang()             比0大比1小的随机浮点值

sin(x)             x的正弦,以x以弧度为单位

sqrt(x)            x的平方根

srand(x)           为计算随机数指定一个种子

gawk还支持一些按位操作数据的函数

and(var1,var2):执行行v1和v2的按位与运算。

compl(val):执行val的补运算。

lshift(val,count):将值val左移count位

or(v1,v2):执行值v1和v2的按位或运算。

rshift(val,count):将值val右移到count位。

xor(v1,v2):执行v1和v2的按位异或运算。

gawk字符串函数

asort(s [,d ])      将数组s按数据元素值排序。索引值会被替换成表示新的排序顺序的连续数字。

另外如果指定了d,则排序后的数组会在数组d中。

asorti(s( [,d])     将数组s按索引值排序。生成的数组会将索引值作为数据元素值,用连续数字

索引来表明排序顺序。另外如果指定了d,排序后的数组会存储在数组d中。

gensub(r,s,h[,t])   查找变量$0或目标字符串t(如果提供了的话)来匹配正则表达式r.如果h是一

个以g或G开头的字符串,就用s替换掉匹配文本。如果h是一个数字,它表示要

替换掉第几处r匹配的地方。

gsub(r,s[,t])       查找变量$0或目标字符串t(如果提供了的话)来匹配正则表达式r.如果找到了,就

全部替换成字符串s

index(s,t)          返回字符串t在字符串s中的索引值;如果找到的话返回0

math(s,r[,a])       返回字符s正则表达式r出现位置的索引。如果指定了数组a,它会存储s中匹配正则表达式部分。

split(s,a[,r])      将s用FS字符或正则表达式r(如果指定了的话)分开放到数组a中。返回字段的总数。

sprintf(format, variables)  用提供的format和variables返回一个类似于printf输出的字符串。

sub(r,s[,t])        在变量$0或目标字符串t中查找正则表达式r的匹配。如果找到了,就用字符串s替换掉第一处匹配。

substr(s,i[,n])     返回s中从索引值开始的n个字符组组成的子字符串。如果你未提供n,则返回s剩下的部分。

tolower(s)          将s中的所有字符串转换成小写。

toupper(s)          将s中的所有字符串转换成大写。

gawk 'BEGIN{
var["a"] = 1
var["g"] = 2
var["m"] = 3
var["u"] = 4
asort(var, test)
for (i in test)
{
print "Index:",i, "- value:",test[i]
}
}'

gawk 'BEGIN{
var["a"] = 1
> var["a"] = 1
> var["g"] = 2
> var["m"] = 3
> var["u"] = 4
> asort(var, test)
> for (i in test)
> {
>     print "Index:",i, "- value:",test[i]
> }
> }'
Index: 4 - value: 4
Index: 1 - value: 1
Index: 2 - value: 2
Index: 3 - value: 3

新数组test含有排序后的原数组中的数据元素,但索引值在变为表明正确顺序的数字值了

split函数是将数据字段放到数组中以进一步处理的好办法:

cat gm1
data11,data12,data13,data14,data15
data21,data22,data23,data24,data25
data31,data32,data33,data34,data35

gawk 'BEGIN{FS=","}{
split($0,var)
print var[1],var[5]
}' gm1

gawk 'BEGIN{FS=","}{
> split($0,var)
> print var[1],var[5]
> }' gm1
data11 data15
data21 data25

新数组使用连续数字作为数组索引,从含有第一个数据字段的索引值1开始。

7.  时间函数

mktim(detespec)   将一个按YYYY MM DD HH MM SS [DST]格式指定的日期转换成时间戳值。

strftim(format [,timestamp]) 将当前时间时间戳或timestamp(如果提供了的话)转换成shell函数格式date()的格式化日期。

systime( )        返回当前时间的时间戳。

gawk 'BEGIN{
date = systime()
day = strftime("%A, %B, %d, %Y, date")
print day
}'

gawk 'BEGIN{
> date = systime()
> day = strftime("%A, %B, %d, %Y, date")
> print day
> }'
Tuesday, October, 21, 2014, date

用systime函数来从系统获取当前的epoch时间戳,然后用strftime函数来将它转换成人类可读的格式,

转换过程中使用了shell的date命令的日期格式化字符。

8.自定义函数

8.1.1 定义函数

要定义自己的函数,你必须使用function关键字:

function name([variables])
{
statements
}

函数名必须能够唯一标识函数。你可以在调用的gawk程序中传给一个或多个变量:

function printthird()
{
print $3
}

#这个函数会打印数据行中第三个数据字段。

函数还能用return语句返回值:

return value

值可以是变量,或者是最终能计算出值的算式:

function myand(limit)
{
return int(limit * rand())
}

8.1.2使用自定义变量

在定义函数时,它必须出现在所有代码之前(包括BEGIN代码块)

cat data2
Riley Mullen
123 Main Street
Chicago, IL 6061
(312)555-1234

Frank Williams
456 Oak Street
Indianapolis, IN 46201
(317)555-9876

Heley Snell
4231 Elm Street
Detroit, MI 48201
(313)555-4938

gawk '
function myprint()
{
printf "%-16s - %s\n",$1,$4
}
BEGIN{FS="\n";RS=""}
{
myprint()
} '

gawk '
> function myprint()
> {
>      printf "%-16s - %s\n",$1,$4
> }
> BEGIN{FS="\n";RS=""}
> {
>    myprint()
> } '

gawk '
function myprint()
{
printf "%-16s - %s\n",$1,$4
}
BEGIN{FS="\n";RS=""}
{
myprint()
} '  data2
Riley Mullen     - (312)555-1234
Frank Williams   - (317)555-9876
Heley Snell      - (313)555-4938

8.1.3创建库函数

首先,你需要创建一个存储库函数的文件:

vi funclib

function myprint()
{
printf "%-16s - %s\n",$1,$2
}
function myrand(limit)
{
return int(limit * rand())
}
function printthird()
{
print $3

}

vi laomeng104

BEGIN{FS="\n";RS=""}
{
myprint()
}

gawk -f funclib -f laomeng104 data2
Riley Mullen     - 123 Main Street
Frank Williams   - 456 Oak Street
Heley Snell      - 4231 Elm Street
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  sed-gawk