admin 管理员组

文章数量: 887031

Linux之grep,sed,awk语句

目录

 2.sed编辑器及其工作流程

2.1 命令格式及常用选项

 2.2 动作说明

2.3 准备文本

2.4 增加内容

2.5 插入内容

2.6 删除内容

2.7 替换内容

2.8 多个匹配

2.9 转换内容

2.10 打印内容

3.sed高级用法

3.1 多行模式空间

3.2 追加下一行

3.3 多行删除

3.4 多行打印

3.5 包含那一行

4.编写awk脚本

4.1 awk命令及其格式

4.2 awk常见内建变量

4.3 按行输出文本

 4.4 按字段输出文本与-F指定分隔符

4.4 awk命令中两种特殊模式与系统变量

4.5 算数操作符

4.6 关系操作符和布尔操作符

4.7 获取文本信息

4.8 格式化打印


awk、grep、sed是linux操作文本的三大利器,合称文本三剑客,也是必须掌握的linux命令之一。三者的功能都是处理文本,但侧重点各不相同,其中属awk功能最强大,但也最复杂。grep更适合单纯的查找或匹配文本,sed更适合编辑匹配到的文本,awk更适合格式化文本,对文本进行较复杂格式处理。

 2.sed编辑器及其工作流程

sed编辑器:
sed是一种流编辑器,流编辑器会在编辑器处理数据之前基于预先提供的一组规则来编辑数据流。

sed编辑器工作流程:
sed编辑器可以根据命令来处理数据流中的数据,这些命令要么从命令行中输入,要么存储在一个命令文本文件中。


sed的工作流程主要包括读取、执行和显示三个过程:

1.读取: sed从输入流 (文件、管道、标准输入) 中读取一行内容并存储到临时的缓冲区中(又称模式空间,pattern space)

2.执行:默认情况下,所有的sed命令都在模式空间中顺序地执行,除非指定了行的地址,否则sed命令将会在所有的行上依次执行。

3.显示:发送修改后的内容到输出流。在发送数据后,模式空间将会被清空。在所有的文件内容都被处理完成之前,上述过程将重复执行,直至所有内容被处理完。

在所有的文件内容都被处理完成之前,上述过程将重复执行,直至所有内容被处理完。
注意:默认情况下所有的sed命令都是在模式空间内执行的,因此输入的文件并不会发生任何变化,除非是用重定向存储输出。

2.1 命令格式及常用选项

sed -e '格式' 文件1 文件2 ...

sed -n -e ‘操作’ 文件1 文件2 ...

sed -f 脚本文件 文件1 文件2 ...

sed -i -e '操作' 文件1 文件2 ...

sed -e ' n { 操作1 操作2 ... } ' 文件1 文件2

-e或- -expression=: 表示用指定命令来处理输入的文本文件,只有一个操作命令时可省略,一 般在执行多个操作命令使用

f或- -file=: 表示用指定的脚本文件来处理输入的文本文件。

h或- -help: 显示帮助。

-n、- -quiet或silent:禁止sed编辑器输出,但可以与p命令一起使用完成输出。

-i: 直接修改目标文本文件。

 2.2 动作说明

s : 替换,替换指定字符。

d : 删除,删除选定的行。

a :增加,在当前行下面增加一行指定内容。

i  :插入,在选定行,上面插入一行指定内容。

c :替换,将选定行替换为指定内容。

y :字符转换,转换前后的字符长度必须相同。

p :打印,如果同时指定行,表示打印指定行;如果不指定行,则表示打印所有内容;如果有非打印字符,则以ASCII码输出。其通常与“-n”选项一起使用

2.3 准备文本

# 我们先准备一个文件做测试内容如下
[root@c83 zmq]# cat linux 
HELLO LINUX!  
Linux is a free unix-type opterating system.  
This is a linux testfile!  
Linux test

2.4 增加内容

# 增加内容
# 1.使用命令sed 3anewfile linux这个命令的意思就是,在第三行后面追加newLine这么一行字符,字符前面要用反斜线作区分。执行完毕之后可以看到结果[root@c83 zmq]# sed '3anewfile' linux 
HELLO LINUX!  
Linux is a free unix-type opterating system.  
This is a linux testfile!  
newfile
Linux test# 2.但是注意,这个只是将文字处理了,没有写入到文件里,文件里还是之前的内容。其实 a 前面是可以匹配字符串,比如我们只想在出现 Linux 的行后面追加,就可以:sed /Linux/anewfile linux,两个斜线之间的内容是需要匹配的内容。可以看出,只有第二、第四行有Linux,所以结果如下:
[root@c83 zmq]# sed '/Linux/anewfile' linux 
HELLO LINUX!  
Linux is a free unix-type opterating system.  
newfile
This is a linux testfile!  
Linux test
newfile# 3.这里用引号把整个表达式括起来也可以,还方便处理带空格的字符
sed /Linux/anewline linux 等效于 sed '/Linux/anewline' linux

2.5 插入内容

# 插入内容
# 1.跟 a 类似,sed 3inewline linux是在第三行前面插入newfile:
[root@c83 zmq]# sed '3inewfile' linux 
HELLO LINUX!  
Linux is a free unix-type opterating system.  
newfile
This is a linux testfile!  
Linux test# 2.sed /Linux/inewfile linux是在所有匹配到Linux的行前面插入:
[root@c83 zmq]# sed '/Linux/inewfile' linux 
HELLO LINUX!  
newfile
Linux is a free unix-type opterating system.  
This is a linux testfile!  
newfile
Linux test# 可以看出插入的用法和增加很相似。

2.6 删除内容

# 删除内容
# 1.删除的字符是d,用法跟前面也很相似,就不赘述,例子如下:
[root@c83 zmq]# sed '/Linux/d' linux 
HELLO LINUX!  
This is a linux testfile! # 可以看到匹配到的Linux行全被删了

2.7 替换内容

# 替换内容
# 1.替换也是一样,字符是c。举个例子
[root@c83 zmq]# sed '/Linux/cWindows' linux 
HELLO LINUX!  
Windows
This is a linux testfile!  
Windows# 可以看到将匹配到的Linux行全部替换为Windows# 2.替换还有个字符是s,但是用法由不太一样了,最常见的用法:sed 's/old/new/g'其中old代表想要匹配的字符,new是想要替换的字符,比如:
[root@c83 zmq]# sed 's/Linux/Windows/g' linux 
HELLO LINUX!  
Windows is a free unix-type opterating system.  
This is a linux testfile!  
Windows test# 这里可以看到是将Linux这一个字符替换为Windows,而不是整行内容
# 这里的/g的意思是一行中的每一次匹配,因为一行中可能匹配到很多次
# 举个例子
# 编辑一个新文本
[root@c83 zmq]# cat xx 
aaaaaaaa
bbbbabbb
cccaabbb# 3.假设我们想把一行中的第三次及以后出现的a变成大写A,那应该这么写:
[root@c83 zmq]# sed  's/a/A/3g' xx
aaAAAAAA
bbbbabbb
cccaabbb# 可以看出只有第一行的有的改了,因为第二第三行没有这么多a出现。
# 关于s还有很多用法,还是回到第一个文件,比如可以用/^/和/$/分别代表行首和行尾:

2.8 多个匹配

# 1.用-e命令可以执行多次匹配,相当于顺序依次执行两个sed命令:
[root@c83 zmq]# sed -e 's/Linux/Windows/' linux
HELLO LINUX!  
Windows is a free unix-type opterating system.  
This is a linux testfile!  
Windows test[root@c83 zmq]# sed -e 's/Linux/Windows/' -e 's/Windows/Mac OS/' linux
HELLO LINUX!  
Mac OS is a free unix-type opterating system.  
This is a linux testfile!  
Mac OS test# 相当于在前面命令的基础上执行后面的命令

2.9 转换内容

# 转换命令是特有的,不仅因为它在所有的sed命令中拥有最小的肋记符。这个命令按位置将字符串abc中的每个字符,都转换成字符串xyz中的等价字符,它的语法如下:    y/abc/ABC/# 查看文本
[root@c83 zmq]# cat linux 
HELLO LINUX!  
Linux is a free unix-type opterating system.  
This is a linux testfile!  
Linux test# 1.现在我们将文本内容全部变成大写字母
[root@c83 zmq]# sed  'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' linux
HELLO LINUX!  
LINUX IS A FREE UNIX-TYPE OPTERATING SYSTEM.  
THIS IS A LINUX TESTFILE!  
LINUX TEST# 2.将Linux这一行文本内容全部变成大写字母
[root@c83 zmq]# sed  '/Linux/{y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/}' linux
HELLO LINUX!  
LINUX IS A FREE UNIX-TYPE OPTERATING SYSTEM.  
This is a linux testfile!  
LINUX TEST

2.10 打印内容

# 打印命令(p)输出模式空间的内容。它既不清除模式空间也不改变脚本中的控制流。然而,它频繁地用在改变流控制的命令(d,N, b)之前。除非抑制(-n)默认的输出,否则打印命令将输出行的重复复制。当抑制默认的输出或者当通过程序的流控制来避免到达脚本的底部时,可能会使用它。# 查看文本
[root@c83 zmq]# cat xx 
as 'happy'
as 'beautiful'
as 'pig'# 1.我们将文本中的引号和as去掉并打印出来
[root@c83 zmq]# sed '/as/{p;s/"//g;s/as//}' xx
as "happy"happy
as "beautiful"beautiful
as "pig"pig
# 这里面的p是我们将匹配到的内容打印一边,就是原来的文本内容,后面处理后的结果是默认打印的一遍结果,我们可以加上-n选项关闭默认打印功能# 2.-n 关闭默认打印
[root@c83 zmq]# sed -n '/as/{p;s/"//g;s/as//}' xx
as "happy"
as "beautiful"
as "pig"# 3.手动添加打印处理后的结果
[root@c83 zmq]# sed -n '/as/{p;s/"//g;s/as//;p}' xx
as "happy"happy
as "beautiful"beautiful
as "pig"pig

3.sed高级用法

3.1 多行模式空间

# 在前面正则表达式的讨论中,我们强调模式匹配是面向行的。像grep这样的程序尝试在单个输入行上匹配一个模式。这就使它很难匹配一个在一行的结尾处开始。并在下一行的开始处结束的短语。其他一些模式只有当在多行上重复时才有意义# sed 能查看模式空间的多个行。这就是允许匹配模式扩展到多行上。在本节中,我们将来看一下创建多行模式空间并处理它的内容的命令。这里的3个多行命令(N、D、P)对应于上一章出现的小写字母的基本命令(n、d、p)。例如,删除命令(D)是删除命令(d)的多行形式。区别是:d删除模式空间的内容,D只删除多行模式空间的第一行。

3.2 追加下一行

# 1.多行Next (N)命令通过读取新的输入行,并将它添加到模式空间的现有内容之后来创建多行模式空间。模式空间最初的内容和新的输入行之间用换行符分隔。在模式空间中嵌入的换行符可以利用转义序列“\n”来匹配。在多行模式空间中,元字符“^”匹配空间中的第一个字条,而不匹配换行符后面的字符。同样,“$”只匹配模式空间中最后的换行符,而不匹配任何嵌入的换行符。在执行next命令之后,控制将被传递给脚本中的后续命令。# 2.Next命令与next命令不同,next输出模式空间的内容,然后读取新的输入行。next命令不创建多行模式空间。# 3.示例文本
[root@c83 zmq]# cat xx 
I love you is a happy thing
This flower is as beautiful as you
lxy is a pig# 4.我们将第一行中的happy thing替换为worry thing并且与第二行合并
[root@c83 zmq]# sed '/happy/{N;s/happy thing\nThis/worry thing and/}' xx
I love you is a worry thing and flower is as beautiful as you
lxy is a pig# 这里我们可以看到二行变为一行

3.3 多行删除

# 1.准备文本,文本内容间相隔了1,2,3,4行空行
[root@c83 zmq]# cat xx 
I love you is a happy thingThis flower is as beautiful as youlxy is a pigthis 4this 5# 2.原来的做法用d去掉全部空行
[root@c83 zmq]# sed '/^$/d' xx
I love you is a happy thing
This flower is as beautiful as you
lxy is a pig
this 4
this 5# 3.现在用N与d去掉匹配到的空行及其的下一行,不是去掉所有空行
[root@c83 zmq]# sed '/^$/{N;/^\n$/d}' xx
I love you is a happy thingThis flower is as beautiful as you
lxy is a pigthis 4
this 5# 4.当有偶数个空行时,所有的空行都会被删除。仅当有奇数个空行时,有一行被保留下来。这是因为删除命令清除的是整个模式空间。一旦遇到第一个空行,就读入下一行,并且两行都被删除。如果遇到第三个空行,并且下一行不为空,那么删除命令就不会被执行,因此空行被输出。如果使用多行Delete命令(是D不是d),就能得到我们想要的结果:# 5.多行Delete命令完成工作的原因是,当遇到两个空行时,Delete命令只删除两个空行中的第一个。下一次遍历该脚本时,这个空行将导致另一行被读入模式空间。如果那行不为空,那么两行都输出,因此确保了输出一个空行。换句话说,当模式空间中有两个空行时、只有第一个空行被删除。当一个空行后面跟有文本时,模式空间可以正常输出。[root@c83 zmq]# sed '/^$/{N;/^\n$/D}' xx
I love you is a happy thingThis flower is as beautiful as youlxy is a pigthis 4this 5

3.4 多行打印

# 1.多行打印(Print)命令与小写字母的print命令稍有不同。该命令输出多行模式空间的第一部分,直到第一个嵌入的换行符为止。在执行完脚本的最后一个命令之后,模式空间的内容自动输出(-n选项或#n抑制这个默认的动作)。因此,当默认的输出被抑制或者脚本中的控制流更改,以至不能到达脚本的底部时,需要使用打印命令(P或p) .Print命令经常出现在Next命令之后和Delete命令之前。这3个命令能建立一个输入/输出循环,用来维护两行的模式空间,但是一次只输出一行。这个循环的目的是只输出模式空间的第一行,然后返回到脚本的顶端将所有的命令应用于模式空间的第二行。没有这个循环,当执行脚本中的最后一个命令时,模式空间中的这两行都将被输出。创建# 2.准备文本
[root@c83 zmq]# cat xx
this is a happy thing
ahh l love you is a happy thing
ahh lxy is a pig# 3.Next命令将一个新的输入行追加到模式空间的当前行。在替换命令应用于多行模式空间之后,模式空间的第一部分被Print命令输出,然后被Delete命令删除。这意味着当前被输出并且新的行成为当前行。Delete命令阻止脚本到达底部,这将输出两行并清除模式空间的内容。Delete命令让我们保护了模式空间的第二部分,并将控制转移动脚本的顶端,在顶端所有的编辑命令都可以被应用于一行。这些命令中有一个是Next命令,它将另一个新行读入模式空间。# 我们匹配以thing结尾的,下一行是ahh开头,在这一行的末尾追加hahaha,并打印
# 4.第一次循环,第一行末尾加上了hahaha,但是模式空间内导致第二行匹配不上,所以要先删掉模式空间内修改后的第一行,重新匹配,形成循环。
[root@c83 zmq]# sed '/thing$/{N;/\nahh/{s// hahaha &/;P}}' xx
this is a happy thing hahaha 
this is a happy thing hahaha 
ahh l love you is a happy thing
ahh lxy is a pig# 5.第二次循环,第二行满足条件,在末尾添加上hahaha然后打印
[root@c83 zmq]# sed '/thing$/{N;/\nahh/{s// hahaha &/;P;D}}' xx
this is a happy thing hahaha 
ahh l love you is a happy thing hahaha 
ahh lxy is a pig

3.5 包含那一行

# 1.
模式空间是容纳当前输入行的缓冲区。还有一个称为保持空间(hold space)的顶留(set-aside)缓冲区。模式空间的内容可以复制到保持空间,而且保持空间的内容也可以复制到模式空间。有一组命令用于在保持空间和模式空间之间移动数据。保持空间用于临时存储。单独的命令不能寻址保持空间或者更改它的内容。
保持空间最常的用途是,当改变模式空间中的原始内容时,用于保留当前输入行的副本。影响模式空间的命令有:
命令        缩写          功能
Hold        h或H      将模式空间的内容复制或追加到保持空间
Get         g或G      将保持空间的内容复制或追加到模式空间
Exchange    x         交换保持空间和模式空间的内容# 2.
这些命令中的每一条都可以利用一个地址来指定一行或行范围。Hole(h,H)命令将数据移至保持空间、而get (g.G)命令将保持空间的数据移回到模式空间。同一命令的小写字母和大写字母之间的差别是,小字字母命令改写目的缓存区的内容,而大写字母命令追加缓存区的现有内容。
Hold命令用模式空间的内容取代保持空间的内容。get命令用保持空间的内容取代模式空间的内容。
Hole命令在保持空间的内容之后放置一个换行符,且后面跟随模式空间的内容(即使保持空间是空的,换行符也被追加到保持空间中)。Get命令模式空间的内容之后放置一个换行符,且后面跟随保持空间的内容。
交换命令交换两个缓存区的内容,对两个缓存区没有副作用。# 3.准备文本
[root@c83 zmq]# cat 3 
[root@c83 zmq]# cat 3
1
2
11
22
111
222
# 4.颠倒1和2,11和22,111和222的顺序
[root@c83 zmq]# sed '/1/{h;d};/2/G' 3
2
1
22
11
222
111
# 这里先将匹配到的含1的数据复制到保持空间,然后删除模式空间匹配的内容,然后用G将保持空间中的含1的内容追加到含2的内容后面# 4.大写转换
# 准备文本示例如下
[root@c83 zmq]# cat xx 
find the Match statement
Consult the Get statement.
Using the Read statement to retrieve data# 5.将Match,Get,Read全部换成大写
[root@c83 zmq]# sed '/the .* statement/{h;s/.*the \(.*\) statement.*/\1/;y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/;G;s/\(.*\)\n\(.*the \).*\( statement.*\)/\2\1\3/}' xx
find the MATCH statement
Consult the GET statement.
Using the READ statement to retrieve data# 6.详解: 
# 先匹配到这三行,然后将这三行覆盖到保持空间中,然后在模式空间中将这三行替换为中的那个单词
[root@c83 zmq]# sed '/the .* statement/{h;s/.*the \(.*\) statement.*/\1/}' xx
Match
Get
Read# 然后将这三个单词全部替换为大写,然后将将保持空间的三行追加回来,在这三个单词后面
[root@c83 zmq]# sed '/the .* statement/{h;s/.*the \(.*\) statement.*/\1/;y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/;G}' xx
MATCH
find the Match statement
GET
Consult the Get statement.
READ
Using the Read statement to retrieve data# 最后用大写单词替换掉三行的原来的单词
[root@c83 zmq]# sed '/the .* statement/{h;s/.*the \(.*\) statement.*/\1/;y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/;G;s/\(.*\)\n\(.*the \).*\( statement.*\)/\2\1\3/}' xx
find the MATCH statement
Consult the GET statement.
Using the READ statement to retrieve data

4.编写awk脚本

4.1 awk命令及其格式

awk 概述:
逐行读取文本,默认以空格或tab键为分隔符进行分隔,将分隔所得的各个字段保存到内建变量中,并按模式或者条件执行编辑命令。

sed命令常用于一整行的处理,而awk比较倾向于将一行分成多个“字段”然后再进行处理。awk信息的读入也是逐行读取的,执行结果可以通过print的功能将字段数据打印显示。在使用awk命令的过程中,可以使用逻辑操作符“&&”表示“与”、“||”表示“或”、“!”表示“非”;还可以进行简单的数学运算,如+、-、*、/、%、^分别表示加、减、乘、除、取余和乘方。

awk命令格式:

awk 选项 ‘模式或条件 {操作}’ 文件 1 文件 2 …
awk -f 脚本文件 文件 1 文件 2 …

4.2 awk常见内建变量

FS:列分割符。指定每行文本的字段分隔符,默认为空格或制表位。与"-F"作用相同
NF:当前处理的行的字段个数。
NR:当前处理的行的行号(序数)。
$0:当前处理的行的整行内容。
$n:当前处理行的第n个字段(第n列)。
FILENAME:被处理的文件名。
RS:行分隔符。awk从文件上读取资料时,将根据RS的定义把读取的资料切割成许多条记录,而awk一次仅读入一条记录,以进行处理。预设值是’\n’

4.3 按行输出文本

awk '{print}' name.txt        #输出所有内容

awk '{print $0}' name.txt   #输出所有内容

# 1.查看系统磁盘使用情况
[root@c83 zmq]# df -h
Filesystem           Size  Used Avail Use% Mounted on
devtmpfs             854M     0  854M   0% /dev
tmpfs                874M     0  874M   0% /dev/shm
tmpfs                874M  8.7M  865M   1% /run
tmpfs                874M     0  874M   0% /sys/fs/cgroup
/dev/mapper/cs-root   17G  4.4G   13G  26% /
/dev/sda1           1014M  227M  788M  23% /boot
tmpfs                175M     0  175M   0% /run/user/0# 2.使用awk命令查看全部情况
[root@c83 zmq]# df -h | awk '{print $0}' 
Filesystem           Size  Used Avail Use% Mounted on
devtmpfs             854M     0  854M   0% /dev
tmpfs                874M     0  874M   0% /dev/shm
tmpfs                874M  8.7M  865M   1% /run
tmpfs                874M     0  874M   0% /sys/fs/cgroup
/dev/mapper/cs-root   17G  4.4G   13G  26% /
/dev/sda1           1014M  227M  788M  23% /boot
tmpfs                175M     0  175M   0% /run/user/0# 3.使用awk命令查看任一行列的内容
# 输出第3行的全部内容
[root@c83 zmq]# df -h | awk 'NR==3{print}' 
tmpfs                874M     0  874M   0% /dev/shm# 输出第1-3行的全部内容
[root@c83 zmq]# df -h | awk 'NR==1,NR==3{print}' 
Filesystem           Size  Used Avail Use% Mounted on
devtmpfs             854M     0  854M   0% /dev
tmpfs                874M     0  874M   0% /dev/shm# 输出第1行和第3行的全部内容
[root@c83 zmq]# df -h | awk 'NR==1||NR==3{print}' 
Filesystem           Size  Used Avail Use% Mounted on
tmpfs                874M     0  874M   0% /dev/shm

 4.4 按字段输出文本与-F指定分隔符

# 1.查看一下/etc/passwd的(部分)内容
[root@c83 zmq]# cat /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
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
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin# 2.输出每行中第1个字段,这里用-F指定分隔符
[root@c83 zmq]# awk -F ':' '{print $3}' /etc/passwd
[root@c83 zmq]# awk -F ':' '{print $1}' /etc/passwd
root
bin
daemon
adm
lp
sync
shutdown
halt
mail
operator# 3.输出每行第1,2,3个字段
[root@c83 zmq]# awk -F ':' '{print $1,$2,$3}' /etc/passwd
root x 0
bin x 1
daemon x 2
adm x 3
lp x 4
sync x 5
shutdown x 6
halt x 7
mail x 8
operator x 11# 4.在BEGIN中写入FS指定分隔符等效与-F
[root@c83 zmq]# awk 'BEGIN {FS = ":"}{print $1,$2,$3}' /etc/passwd
root x 0
bin x 1
daemon x 2
adm x 3
lp x 4
sync x 5
shutdown x 6
halt x 7
mail x 8
operator x 11# 5.指定多个分隔符
# 这里我们过滤想要取出ip地址
# 先去掉127这一行
[root@c83 zmq]# ip a | grep 'inet 'inet 127.0.0.1/8 scope host loinet 192.168.187.134/24 brd 192.168.187.255 scope global noprefixroute ens160# 发现ip后面还有/,也要去掉
[root@c83 zmq]# ip a | grep 'inet ' | grep -v 127inet 192.168.187.134/24 brd 192.168.187.255 scope global noprefixroute ens160# 用FS以空格和/都为分隔符
[root@c83 zmq]# ip a | grep 'inet ' | grep -v 127 | awk 'BEGIN{FS = "[ /]+"}{print $3}'
192.168.187.134

4.4 awk命令中两种特殊模式与系统变量

# 两种特殊模式:BEGIN 和 END

BEGIN 被放置在没有读取任何数据之前

END 被放置在所有的数据读取完成以后执行

体现如下:

BEGIN{}: 读入第一行文本之前执行的语句,一般用来初始化操作

{}:逐行处理

END{}:处理完最后一行文本后执行,一般用来处理输出结果

# 系统变量

1.awk 中有许多系统变量或内置变量。awk有两种类型的系统变量。第一种类型定义的变量默认值可以改变,例如默认的字段和记录分隔符。第二种类型定义的变量的值可用于报告或数据处理中。例如当前记录中字段的数量,当前记录的数量等。这些可以由awk自动更新,例如,当前记录的编号和输入文件名。


2.有一组默认值会影响对记录和字段的输入和输出的识别。系统变量FS定义字段分隔符。它的默认值为一个空格,这将提示awk可以用若干个空格和/或制表符来分隔字段。FS可以被设置为任何单独的字符或一个正则表达式,前面,我们将分隔符改变为逗号,为的是读取一个名字和地址的列表。


3.和FS等效的输出是OFS,它的默认值为一个空格。我们将看到一个例子来简单地重新定义OFS。


3.awk 将变量NF定义为当前输入记录的字段个数。改变NF的值会有副作用。当$0(字段)和NF被改变时将产生令人费解的相互作用,尤其是当NF减小时(注3)。增加NF值会创建新的(空的)字段,并重新建立$0,字段由OFS的值来分隔。在NF减小的情况下,gawk 和mawk重新建立记录,超过新的NF值的字段被设置为一个空字符。Bell Labs awk 没有改变$0.


4.awk还定义了记录分隔符RS为一个换行符。RS有一点例外,它是awk 仅仅注意它的值的首字符的惟一变量。


4.和RS输出等价的是ORS,它的默认值也是一个换行符。在系一部分“处理多行记录“中,我们将解释如何改变记录分隔符的默认值。awk 设置变量NF为当前输入记录的编号。它可以用来给列表中的记录编号。变量FILENAME中包含了当前输入文件的名称。当应用多个输入文件时,变量FNR被用来表示与当前输入文件相关的当前记录的代码。


5.通常情况下,因为希望在读入第一个输入行之前设置字段和记录分隔符的值。所以可以在BEGIN过程中定义它们。然而,也可以在脚本的任何位置重定义它们的值,在POSIX awk 中为FS赋值不影响当前的输入行,它仅影响下一个输入行。

# 1.有了系统变量之后,就可以对前面查看/etc/passwd(部分)数据进行优化
[root@c83 zmq]# awk 'BEGIN{FS = ":"}{print $1,$2,$3}' /etc/passwd
root x 0
bin x 1
daemon x 2
adm x 3
lp x 4
sync x 5
shutdown x 6
halt x 7
mail x 8
operator x 11# 2.用OFS设定的值来对数据进行分隔
# 用 : 号
[root@c83 zmq]# awk 'BEGIN{FS = ":";OFS = ":"}{print $1,$2,$3}' /etc/passwd
root:x:0
bin:x:1
daemon:x:2
adm:x:3
lp:x:4
sync:x:5
shutdown:x:6
halt:x:7
mail:x:8
operator:x:11
# 用 - 号
[root@c83 zmq]# awk 'BEGIN{FS = ":";OFS = "-"}{print $1,$2,$3}' /etc/passwd
root-x-0
bin-x-1
daemon-x-2
adm-x-3
lp-x-4
sync-x-5
shutdown-x-6
halt-x-7
mail-x-8
operator-x-11

4.5 算数操作符

操作符描述
+
-
*
/
%取模
^取幂
**乘方
# 可以在BEGIN中自定义变量
[root@c83 zmq]# echo | awk '{x=2;y=x+1;print x+y}'
5[root@c83 zmq]# echo | awk '{x=2;y=x+1;print x-y}'
-1[root@c83 zmq]# echo | awk '{x=2;y=x+1;print x*y}'
6[root@c83 zmq]# echo | awk '{x=2;y=x+1;print x/y}'
0.666667
操作符定义
++ 变量加1
--变量减1
+=将加的结果赋予变量
-=将减的结果赋予变量
*=将乘的结果赋予变量
/=将除的结果赋予变量
%=将取模的结果赋予变量
^=将取幂的结果赋予变量
**=将乘方的结果赋予变量
# 1.准备了一个文件,里面有三行空行
[root@c83 zmq]# cat xx 
1234
# 2.用变量的方法查看有多少空行
[root@c83 zmq]# awk '/^$/{print x += 1}' xx
1
2
3# 3.文本共有的行数
[root@c83 zmq]# awk '{print x += 1}' xx
1
2
3
4
5
6
7# 4.计算
# 给出一组数据,计算平均值
[root@c83 zmq]# cat xx
football    80 86 88 90 92
basketball  88 92 94 88 90
pingpang    86 80 92 98 90
# 设置变量计算平均值
[root@c83 zmq]# awk '{num= $2 + $3 + $4 + $5 + $6;avg = num /5;print $1,avg}' xx
football 87.2
basketball 90.4
pingpang 89.2# 5.支票薄的计算
# 编辑一个文本内容如下
[root@c83 zmq]# cat xx
1000
125 Market -125.45
126 Jerry Store -34.95
127 Video Store -7.45
128 Bob Store -14.32
129 Gasoline -16.10
# 求出初始值减去每张支票后最后的金额
[root@c83 zmq]# awk 'NR==1{print "Beginning Balance:\t " $1;balance = $1;next}{print $1,$2,$3,$4;print balance += $3+$4}' xx
Beginning Balance:       1000
125 Market -125.45 
874.55
126 Jerry Store -34.95
839.6
127 Video Store -7.45
832.15
128 Bob Store -14.32
817.83
129 Gasoline -16.10 
801.73# 在第一行打印出初始余额,然后与每次扣除的数据相加,考虑到有些数据是在第四个字符,所以在计算时要加上

4.6 关系操作符和布尔操作符

关系操作符

操作符描述
<小于
>大于
<=小于等于
>=大于等于
==等于
!=不等于
~匹配
!~不匹配
# 举例:
# 打印第二行的第二个字符
[root@c83 zmq]# df -h |awk 'NR==2{print $2}'
854M

布尔操作符

操作符定义
||逻辑或
&&逻辑与
逻辑非

给定两个或多个表达式,只有当给定的表达式之一的值为真(非零或非空)时,使用操作符|的等个表达式的值才为真。而只有当&&操作符连接的两个表达式的值都为真时结果才为真。
 

下面的表达式:

NF ==6 && NR>1

表示字段的数量必须等于6并且记录的编号必须大于1.

4.7 获取文本信息

# 查看当前路径下的全部信息
[root@c83 ~]# ll
total 8
-rw-------. 1 root root 1088 Sep  7 21:09 anaconda-ks.cfg
drwxr-xr-x. 2 root root   43 Sep 19 06:55 zmq
-rw-r--r--. 1 root root 3740 Sep 12 03:47 zmq-lamp.tar.xz# 查看当前路径下文件目录的信息总和
# 首先设置变量sum是第五行大小的相加总和,filenum是文件目录的个数
[root@c83 ~]# ll | awk 'NR!=1{sum+=$5;++filenum;print $5,"\t",$9}END{print "Total:",sum,"bytes (" filenum "files)"}'
1088     anaconda-ks.cfg
43       zmq
3740     zmq-lamp.tar.xz
Total: 4871 bytes (3files)# 使文本对齐

4.8 格式化打印

1.到现在为止,我们编写的许多脚本可以很好地实现对数据的操作,但没有对输出进行适当的格式化。这是因为基本的print语句所能做的工作有限。因为awk 的大多数功能是产生报告,因此以整齐的样式产生格式化报告是很重要的。程序filesum可以很好地处理数据,但它的报告缺乏整齐的格式。


2.awk 提供的printf可以代替print 语句,printf是借用了C程序设计语言。Printf 语句和print语句一样可以打印一个简单的字符串。
                         awk 'BEGIN { printf ("Hello,world\n") }'
首先可以看出,printf和print 的主要区别是printf没有提供自动换行功能。必须明确地为它指定“\n”。

Printf 语句的完整语法由两部分组成:
                       printf ( for mat-expression [, ar guments] )
其中的圆括号是可选的。第一部分是一个用来描述格式的表达式,通常以引号括起的字符串常量的形式提供。第二部分是一个参数列表,例如变量名列表,它和格式说明相对应。在格式说明前面有一个百分号(%),而格式说明符号为表7-6列出的字符之一。两个主要的格式说明符是s和d,s表示字符串,d表示十进制整数。

用在printf的 格式说明符

字符定义
cASCLL字符
d十进制整数
i十进制整数(在POSIX中添加的)
e浮点格式([-]d.precision[+-]dd)
E浮点格式([-]d.precision[+-]dd)
f浮点格式([-]ddd.precision)
ge或f 的转换形式,长度最短,末尾的О被去掉
GE或f 的转换形式,长度最短,末尾的О被去掉
O无符号的八进制
s字符串
u无符号的十进制
x无符号的十六进制,用a-f表示10-15
X无符号的十六进制,用A-F表示10-15
%字面字符%

Printf 语句可以规定输出域的宽度和对齐方式。一个格式表达式由3个可选的修饰符组成,跟在“%”后面,并出现在格式说明符之前。
                     %一width. precision format-specifier

描述输出字段宽度的width是一个数值。当指定域宽度时,这个域的内容默认为向右对齐。必须指定“-”来设置左对齐。因此,“%-20s”输出的是向左对齐的一个域长度为20个字符的字符串,如果字符串少于20个字符,那么这个域将用空格来填满。在下面的例子中,输出一个“|”来指示输出域的真实长度。

# 举例1:
# 查看当前路径下的详细信息
[root@c83 ~]# ll
total 8
-rw-------. 1 root root 1088 Sep  7 21:09 anaconda-ks.cfg
drwxr-xr-x. 2 root root   43 Sep 19 06:55 zmq
-rw-r--r--. 1 root root 3740 Sep 12 03:47 zmq-lamp.tar.xz
# 打印出第五行和第九行
# 只有第五行和第九行的数据匹配d(整数),s(字符串)才会打印出来
# 所以我们要将第一行去掉
[root@c83 ~]# ll | awk 'NR!=1{printf"%d\t%s\n",$5,$9}'
1088    anaconda-ks.cfg
43      zmq
3740    zmq-lamp.tar.xz# 举例2:
# 打印一个hello,占据十个字符的大小
[root@c83 zmq]# awk '{printf("|%10s|\n","hello")}' xx
|     hello|# 加上-号就在右边多了2个空格
[root@c83 zmq]# awk '{printf("|%-10s|\n","hello")}' xx
|hello     |# 举例2:
# 在4.7获取文本内容的基础上进行格式化输出(对齐)
[root@c83 ~]# ll | awk 'NR!=1{sum+=$5;++filenum;print $5,"\t",$9}END{print "Total:",sum,"bytes (" filenum "files)"}'
1088     anaconda-ks.cfg
43       zmq
3740     zmq-lamp.tar.xz
Total: 4871 bytes (3files)# 使数据对齐
[root@c83 ~]# ll | awk 'BEGIN{print "bytes","\t","files"}NR!=1{sum+=$5;++filenum;print $5,"\t",$9}END{printf "Total:\t %d bytes(%d files)",sum,filenum}'
bytes    files
1088     anaconda-ks.cfg
43       zmq
3740     zmq-lamp.tar.xz
Total:   4871 byte(3 file)

本文标签: Linux之grep sed awk语句