正则表达式 grep sed awk

正则表达式:

用一组特殊的字符,表示匹配的内容。
用来处理文本文件(可编辑的)。

grep 字符

普通字符:大小写字母 数字
元字符:特殊含义的字符

使用普通字符举例:

[root@shell /shell]# grep "root" passwd		# 查找包含root的行
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
			使用普通字符
1. ^ 行首定位符
[root@shell /shell]# grep "^root" passwd		# 查找以root开头的行
root:x:0:0:root:/root:/bin/bash
2. $ 行尾定位符
[root@shell /shell]# grep "bash$" passwd		# 查找包含bash末尾的行
root:x:0:0:root:/root:/bin/bash
s:x:1000:1000:s:/home/s:/bin/bash

匹配空行 (linux中文本文件每行结尾$表示,空行也一样)

[root@shell /shell]# cat -A p1 
[root@shell /shell]# grep "^$" p1
3. . 任意的单个字符(前边有个点)

示例:

[root@www test]# cat f1
rot
root
roooot
rooooooooooot
rt
at

[root@www test]# grep 'r..t' f1    # rt之间包含2个字符
root
[root@www test]# grep 'r.t' f1		# rt之间包含一个字符的
rot
[root@www test]# grep '.t' f1
rot
root
roooot
rooooooooooot
rt
at
[root@www test]# grep '^.t' f1		# 以^开头,设置个限制,t是末尾,.中间一个字符。
rt
at

4. 前面的字符可以是任意个(0~无穷大)
[root@shell /shell]# grep "r*t" f1		# *对r来说可以是0~无限字符,r可以没有,所以包含at
rot
root
roooot
rooooooooot
rt
at
[root@shell /shell]# grep "ro*t" f1		# *对o来说取值,r在开头取范围,所以没有at
rot
root
roooot
rooooooooot
rt
5. [ ] 匹配指定字符组中的任意1个字符
[A-Z]
[a-z]
[a-Z]		所有的字母
[0-9]
[a-Z0-9]	字母+数字
[^a-Z0-9]	^取反,不是字母+数字 ==  符号

装 13 表示法,POSIX表示法:
man grep 向下找
[[:alnum:]]	==	[a-Z0-9]		包含大小写字母,数字
[[:alpha:]]	==	[a-Z]				包含大小写字母
[[:lower:]]	==	[a-z]				包含小写字母
[[:upper:]]==	[A-Z]			只包含大写字母
[[:digit:]]	==	[0-9]	十进制数		 数字
[[:punct:]]	==	符号				符号
[[:space:]]	==	空白字符(tab 空格)

passwd文件,输出用户名是4个字母的行?
[a-Z][a-Z][a-Z][a-Z]

[root@shell test]# grep "^[a-Z][a-Z][a-Z][a-Z]" passwd		# ^ 开始  用[a-Z]分别表示四个字符
root:x:0:0:root:/root:/bin/bash
daemon:x:2:2:daemon:/sbin:/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
6. \( \) 标签,保存被匹配的字符
标签在一个表达式中,最多出现9个
从左向右,依次排序,第一个标签,\1 ;第二个 \2

f2文件,输出有3个连续一样的字符的行?

[root@shell /shell]# cat f2		# 添加一个这样的文件
abc
123
qwe
AAA
zxc
BBB
###
@#$

[root@shell /shell]# grep "\(.\)\1\1" f2	# (.)包含任意一个,\1\1 表示三个字符		grep "^\(.\)\1\1$" f2	严谨设置取值范围
AAA
BBB
###
7. \{ \} 表示要取值得范围
\\{m\\}	前面的字符有m个
\\{m,\\}	前面的字符>=m个
\\{m,n\\}	前面的字符>=m <=n 个,
[root@shell test]# grep "^[a-Z]\{4\}:" passwd		# 前边取四个值
root:x:0:0:root:/root:/bin/bash
sync:x:5:0:sync:/sbin:/bin/sync
halt:x:7:0:halt:/sbin:/sbin/halt

[root@shell test]# grep "^[a-Z]\{4,\}:" passwd		# 前边取值大于等于四个值
root:x:0:0:root:/root:/bin/bash
daemon:x:2:2:daemon:/sbin:/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


[root@shell test]# grep "^[a-Z]\{4,8\}:" passwd		# 前边取值大于等于四个值,小于8个值
root:x:0:0:root:/root:/bin/bash
daemon:x:2:2:daemon:/sbin:/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

8. \< \> 词
\\<	词首定位符
\\>	词尾定位符
词:单词 一串连续的字母、数字
[root@shell test]# grep "^\<[a-Z]\{4,8\}\>" passwd		# 这样就界定取值是什么位置的单词词组
root:x:0:0:root:/root:/bin/bash
daemon:x:2:2:daemon:/sbin:/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

9. \ 转义字符,屏蔽元字符的特殊含义
[root@shell /shell]# cat f3
r.t
r*t
rat
rot
r$t
[root@shell /shell]# grep "r.t" f3	# 按照 . 作用,只能找到替代一个字符的
r.t
r*t
rat
rot
r$t
[root@shell /shell]# grep "r\.t" f3		# 在符号前边添加转义字符可以显示出符号,否则会显示元字符的特殊作用
r.t


‘’ 强引用符号
" " 弱引用符号
` $ \ 不能屏蔽

[root@shell /shell]# grep "t$" f3	# 双引号无法屏蔽 $字符
r.t
r*t
rat
rot
r$t
[root@shell /shell]# grep 't$' f3	# 单引号无法屏蔽 $字符
r.t
r*t
rat
rot
r$t
	在正则表达式中,没有影响。
[root@shell /shell]# touch "\"		# \ 表示转义,所以无法创建
> ^C
[root@shell /shell]# touch '\\'		# 使用转义字符屏蔽掉元字符的特殊含义
[root@shell /shell]# ls
\
	在shell中,有效果。
扩展正则元字符
|	或
+	前面的字符匹配>=1次(1~无穷大)
?	前面的字符配置0次或1次
()	== \(\)
{m}		==	\{m\}
{m,}	==	\{m,\}
{m,n}	==	\{m,n\}
egrep 用在扩展正则
**|**	或
[root@shell /shell]# cat f4		# 添加文件
a
bb
ccc
abc
cde
[root@shell /shell]# egrep "a|bb" f4		# | 将两个匹配条件符合的都输出
a
bb
abc
[root@shell /shell]# egrep "aa|bb" f4		# | 搜索前边或后边,前边无匹配无输出,后边匹配输出后边
bb

+ 前面的字符匹配>=1次(1~无穷大)

[root@shell /shell]# egrep "r+t" f1		# 表示t前边至少有一个r
rt				#符合
[root@shell /shell]# egrep "ro+t" f1	# 表示o至少一个或者无限个
rot							# 有一个,其它是多个o
root
roooot
rooooooooot

? 前面的字符配置0次或1次

[root@shell /shell]# egrep "r?t" f1		# ?对r负责,r可以没有,或者无限
rot
root
roooot
rooooooooot
rt						# 前边有r 其余没有r,t前边是o
at
[root@shell /shell]# egrep "ro?t" f1		# ?对前边o负责
rot						# 有一个o
rt						# 没有o

( ) == \( \) 在egrep里 作用相同

[root@shell /shell]# egrep "(.)\1\1" f2    # 在正则里括号可以不用 \
AAA
BBB
###


fgrep
取消元字符的特殊含义。	
[root@shell /shell]# fgrep "r.t" f3		# 屏蔽一切元字符的含义,搜啥找啥(傻瓜式搜索)
r.t
[root@shell /shell]# fgrep "r*t" f3
r*t

sed 命令

sed + 正则表达式
处理文本文件的流编辑器,可以过滤和转换。

将文本文件,以行 为单位,“流”入模式空间,使用命令、选项进行处理,处理完,打印到标准输出。(sed命令:如果不加 -i 只改变输出,不改变原文件)
然后再处理下一行,直到结束。

与grep对比:
grep只有匹配,没有修改
与vi对比:
光标在哪,就编辑哪;

sed是默认处理文件所有的行。

选项:
-n * 关闭模式空间的输出
-e * 多点编辑
-i ***
-f
-r *
命令:
d *** 删除匹配行
p *** 打印匹配行
q *** 退出
s ***** 替换(重点)
y ***
r
w
a
i
c
h H
g G

语法:
sed [选项] ‘/定址/命令’ 文件名
定址:通知sed,处理文件的哪一行;如果不写,处理所有的行。

例子: vi一个带序列的文件进行如下操作
介绍定址,使用命令 d 或 p。

[root@shell /shell]# sed 'd' p3
	没有加定址,所有行被删掉
[root@shell /shell]# sed '1d' p3
[root@shell /shell]# sed '5d' p3
	定址使用行号,删除第1行,第5行
[root@shell /shell]# sed '1,3d' p3
	使用2个定址,删除区间 1-3行
[root@shell /shell]# sed '1~2d' p3		# 删除奇数行,从1行开始删除
[root@shell /shell]# sed '2~2d' p3		# 删除偶数行,从2行开始删除

删除第1行和第5行

[root@shell /shell]# sed '1d;5d' p3
	||
[root@shell /shell]# sed -e '1d' -e '5d' p3		# -e 可以同时支持多个指令,操作更灵活

使用定址删除:

[root@shell /shell]# sed '/1001/d' p3		# 删除指定行
[root@shell /shell]# sed '/1001/,/1005/d' p3	# 删除从包含1001行  到   1005行,包括之间行都删除 
	定址使用正则表达式

关于定制删除需要了解:

[root@shell /shell]# sed '/1010/,/1005/d' p3	
	前面的定址在文件中没有,操作不执行

[root@shell /shell]# sed '/1005/,/1010/d' p3
后面的定址在文件中没有,从第一定址直接匹配到文件结束,执行操作

p 打印匹配行

[root@shell /shell]# sed 'p' p3		# 不指定,默认打印全部行
[root@shell /shell]# sed '1p' p3		# 打印第一行
[root@shell /shell]# sed '1,3p' p3		# 打印从第一行到第三行

[root@shell /shell]# sed -n '1,3p' p3	# 关闭空间模式打印一行

打印奇数行
打印偶数行

[root@shell /shell]# sed -n '1~2p' p3		# 打印奇数行
[root@shell /shell]# sed -n '2~2p' p3		# 打印偶数行

打印3的倍数行

[root@shell /shell]# sed -n '0~3p' p3		# 打印3的倍数行

打印第1行和第5行

[root@shell /shell]# sed -n '1p;5p' p3		# 打印第1行和第5行
	||
[root@shell /shell]# sed -n -e '1p' -e '5p' p3		# 打印第1行和第5行

q 退出

[root@shell /shell]# sed '1q' p3		# 遍历一条就退出
[root@shell /shell]# sed '3q' p3		# 遍历

打印文件的第一行:
模拟 head -1

[root@shell /shell]# sed -n '1p' p3
[root@shell /shell]# sed '1!d' p3
[root@shell /shell]# sed '1q' p3	这条最好

最后一条最好,因为只遍历一条就退出;另外两条是对全文件进行遍历


s	查找替换

语法结构:s/模式匹配/替换内容/旗标
模式匹配 正则表达式
替换内容 将模式匹配的内容替换成什么内容
旗标:
n:1-512之间的正整数,表示第n次出现的匹配内容
g:全局替换
p:打印替换的行
w:另存为

[root@shell /shell]# sed 's/user/USER/' p3		# 将小写替换成大写(不添加表示默认每行第一个)
[root@shell /shell]# sed 's/user/USER/2' p3		# 将小写替换成大写(表示每行第二个)
[root@shell /shell]# sed 's/user/USER/g' p3		# 将小写替换成大写(g表示全部替换)

[root@shell /shell]# sed -n 's/root/ROOT/p' p1	# -n关闭空间模式,p打印小写替换大写的行
ROOT:x:0:0:root:/root:/bin/bash		
operator:x:11:0:operator:/ROOT:/sbin/nologin

[root@shell /shell]# sed -n 's/root/ROOT/gp' p1		# 参数里的gp可以不区分顺序
ROOT:x:0:0:ROOT:/ROOT:/bin/bash
operator:x:11:0:operator:/ROOT:/sbin/nologin
[root@shell /shell]# sed -n 's/root/ROOT/pg' p1
ROOT:x:0:0:ROOT:/ROOT:/bin/bash
operator:x:11:0:operator:/ROOT:/sbin/nologin
[root@shell /shell]# sed -n 's/root/ROOT/2p' p1		# 参数里的2p可以不区分顺序
root:x:0:0:ROOT:/root:/bin/bash
[root@shell /shell]# sed -n 's/root/ROOT/p2' p1
root:x:0:0:ROOT:/root:/bin/bash

[root@shell /shell]# sed 's/root/ROOT/w file1' p1		# w 另存,默认当前路径保存,也可以指定路径
[root@shell /shell]# cat file1 
ROOT:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/ROOT:/sbin/nologin

[root@shell /shell]# sed 's/root/ROOT/w /tmp/file1' p1	# w 另存,可以指定路径

y 根据指定位置替换(这种模式下字母必须一一对应)

[root@shell /shell]# sed 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' p3
 # 将一个文件中,所有的小写字母,替换成大写字母(这种模式下字母必须一一对应)

a 在匹配行下面插入内容
i 在匹配行上面插入内容
c 本行替换

a 在匹配行下面插入内容 (a前边不指定行数,默认每一行)

[root@shell /shell]# sed 'a hehe' p3		# 在文件p3每一行下插入hehe
[root@shell /shell]# sed '1a hehhe' p3		# 在文件p3第一行下插入hehe

i 在匹配行上面插入内容

[root@shell /shell]# sed 'i hehhe' p3		# 在文件p3每一行上插入hehe
[root@shell /shell]# sed '1i hehhe' p3		# 在文件p3第一行上插入hehe

c 本行替换

[root@shell /shell]# sed 'c hehhe' p3		# 在文件p3每一行上替换hehe
[root@shell /shell]# sed '1c hehhe' p3		# 在文件p3第一行上替换hehe

r 读取一个文件的内容

[root@www test]# sed 'r f1'  passwd		# 将文件f1里的内容插入到passwd文件的每一行下

w 另存为

[root@www test]# sed 'w pass.txt'  passwd  # 将文件passwd另存一份 pass.txt

r 读取一个文件的内容(不改变原文件,空间模式显示)

[root@shell /shell]# sed 'r apache.txt' p3		写入引号的文件内容到引号外的文件里,不指定行就是在每一行写入
[root@shell /shell]# sed '3r apache.txt' p3			将引号里的文件引入到引号外的文件第三行开始写入

w 另存为

[root@shell /shell]# sed -n '1w p31' p3  引入p3第一行,另存一个文件p31里,-n关闭空间模式
[root@shell /shell]# cat p31
user1:x:1000:1000::/home/user1:/bin/bash

g 将保留空间的内容,复制到模式空间,覆盖原来模式空间的内容
G 将保留空间的内容,追加到模式空间,保留原来模式空间的内容
h 将模式空间的内容,复制到保留空间,覆盖原来保留空间的内容
H 将模式空间的内容,追加到保留空间,保留原来保留空间的内容

H 在前边 ;分号隔离,g

sed
处理文本文件–模式空间(PATT)
可以用来存储文件内容(行)–保留空间(HOLD),保留空间,默认有一个空行

从老师那里下载了一个调试脚本,查看工作模式状态
“lftp 172.16.0.99
下载调试文件 sedsed-1.0

chmod +x sedsed-1.0
mv sedsed-1.0 sedsed
mv sedsed /bin/
cd /shell/”


sedsed -d ‘1h;3g’ p3 # sedsed -d是调试脚本的选项
sed ‘1h;3g’ p3
sed ‘1h;3G’ p3
sed ‘1H;3g’ p3
sed ‘1H;3G’ p3


[root@www test]# sed '1h;4g' f1    # 1h将第一行,复制到保留空间,然后g从保留空间取回覆盖第4行 
rot
root
roooot
rot
rt
at
[root@www test]# sed '1h;4G' f1		# 1h将第一行,复制到保留空间,然后G从保留空间取回追加第4行 尾
rot
root
roooot
roooooooot
rot
rt
at


[root@www test]# sed '1H;4g' f1		# 1H将第一行,复制到保留空间(上边有空格),然后G从保留空间取回覆盖第4行 尾(带着空格)
rot
root
roooot

rot
rt
at
[root@www test]# sed '1H;4G' f1		# 1H将第一行,复制到保留空间(上边有空格),然后G从保留空间取回追加第4行 尾(带着空格)
rot
root
roooot
roooooooot

rot
rt
at
awk 命令
awk是一个优良的文本处理工具。

工作模式:
行处理模式
在处理文件时:
读入文件的行,将行存入内置变量 $0 中
再使用内置变量 FS(列的分隔符,默认是空白字符(空格或tab)) 将行拆分成若干列
第1列 存入 内置变量$1
第2列 存入 内置变量$2

开始处理
输出的时候,再使用内置变量OFS(输出列的分隔符,默认是空格)
继续处理下一行

[root@shell /shell]# awk -F: '{print $0}' p3	输出行

[root@shell /shell]# awk -F: '{print $1}' p3		# 输出第一列
[root@shell /shell]# awk -F: '{print $1,$3}' p3		# 输出第一列,和第三列

语法:
awk [选项] ‘/定址/{动作}’ 文件名

选项:
-F 指定列的分隔符
-f 调用脚本

动作:
print 标准输出
printf 格式化输出

定址:
正则表达式
模式计算


awk的分隔符:

默认的:空格或tab
[root@centos7-bj /var/log/httpd]# awk ‘{print $1}’ access_log # 不添加-F分隔符表示默认分隔符为 空格或者tab

tab
实现windows下的excel和centos进行文件交互。

在linux下通过awk输出格式后,复制到excel可以直接按列粘贴,方便!

[root@shell /shell]# awk -F: '{print $1"\t"$3}' p3
user1	1000
user2	1001
user3	1002
user4	1003
user5	1004
user6	1005
user7	1006
user8	1007
user9	1008
user10	1009

	\t	表示 tab键
[root@shell /shell]# awk -F [:/] '{print $10,$11}' p3	
	指定2个符号,做分隔符 ,[  ]里是“或”的关系
[root@shell /shell]# awk -F "" '{print $1}' p3
	指定 空 ,做分隔符

输出:

  1. print 普通输出

  2. printf 格式化输出
    %s 字符串:包含所有的字母 数字 符号
    %d 十进制整数:小数直接取整,字母 符号归0
    %f 浮点数:默认,小数点后面保留6位,不够添0,;字母 符号 归0

    输出,行尾默认是没有换行符 ,换行时末尾添加 \n
    %的数量 <= $ (%小于¥变量的数量才有输出结果,参考下边例子)

创建一个演示文件

[root@shell /shell]# cat a1
23.456 11.234 66 aa bcd #@

%s 可以输出显示所有字符

[root@shell /shell]# awk '{printf "%s,%s;%s-%s_%s\t%s\n",$1,$2,$3,$4,$5,$6}' a1		
# %s 可以输出显示所有字符
23.456,11.234;66-aa_bcd	#@

%d 可以输出整数,不是整数的识别成0

[root@shell /shell]# awk '{printf "%d,%d;%d-%d_%d\t%d\n",$1,$2,$3,$4,$5,$6}' a1		
# %d 可以输出整数,不是整数的识别成0
23,11;66-0_0	0

%f 可以输出识别输出所有小数,并且默认保留小数后六位

[root@shell /shell]# awk '{printf "%f,%f;%f-%f_%f\t%f\n",$1,$2,$3,$4,$5,$6}' a1		
# %f  可以输出识别输出所有小数,并且默认保留小数后六位
23.567000,11.234000;66.000000-0.000000_0.000000	0.000000

对齐演示:

[root@shell /shell]# awk -F: '{printf "%s %d\n",$1,$3}' passwd 
	常规输出
root 0				15表示$1列最长的是15个字符,5表示$3列最长的是5个字符
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
operator 11
games 12
ftp 14
nobody 99
[root@shell /shell]# awk -F: '{printf "%15s %5d\n",$1,$3}' passwd 
	右对齐
           root     0
            bin     1
   		 daemon     2
       	    adm     3
             lp     4
       	   sync     5
	   shutdown     6
           halt     7
           mail     8
[root@shell /shell]# awk -F: '{printf "%-15s %-5d\n",$1,$3}' passwd 
	左对齐
root         	  0    
bin            	  1    
daemon   	  	  2    
adm        		  3    
lp           	  4    
sync      	 	  5    
shutdown	  	  6
 

画表格:

[root@shell /shell]# awk -F: '{printf "|%-15s|%-5d|\n-----------------------\n",$1,$3}' passwd 
	画上表格    用  |  分割  ,用___\n上下分割
[root@shell /shell]# awk '{printf "%10.1f %10.2f\n",$1,$2}' a1
      23.6      11.23	# 默认向右对齐
[root@shell /shell]# awk '{printf "%-10.1f %-10.2f\n",$1,$2}' a1
23.6       11.23  	# 添加 - 向左对齐
	10是输出的宽度
	.1是小数点后面保留几位,四舍五入
	- 左对齐

定址:

  1. 正则表达式 匹配
    大多数元字符,都支持。
    {} () 不支持
[root@shell /shell]# awk -F: '/^root/{print $1}' passwd 
root

[root@shell /shell]# awk -F:  '$3 ~ /\<[0-9]\>/{print $1,$3}' passwd 
  1. 关系运算符
> <   ==   !=   >=     <= 

3. 逻辑运算符
&& (2个条件都要满足)
|| (2个条件满足一个就行)
! (条件取反)

[root@shell /shell]# awk -F:  '$3 == 0{print $1,$3}' passwd 
# 筛选第三列 是0的,输出第一列和第三列

[root@shell /shell]# awk -F:  '$3 >= 10{print $1,$3}' passwd 
# 筛选第三列 大于等于10的,输出第一列和第三列
	 
[root@shell /shell]# awk -F:  '$3 != 10{print $1,$3}' passwd
# 筛选第三列 不等于10的,输出第一列和第三列
	
[root@shell /shell]# awk -F:  '$3 >= 1 && $3 <=10{print $1,$3}' passwd
# 筛选第三列 大于等于1的 并且 小于等于10的,输出第一列和第三列

[root@shell /shell]# awk -F:  '$3 >=5  || $3 <= 3{print $1,$3}' passwd 
# 筛选第三列 大于等于5的 或者 小于等于3的,输出第一列和第三列

[root@shell /shell]# awk -F:  '!($3 >= 1 && $3 <=10){print $1,$3}' passwd
# 筛选第三列 不要(大于等于5的 并且 小于等于3)的,输出第一列和第三列,当条件相反时,条件用括号标注
 
关系运算比较,要求是数值型数据;
~ !~ 可以是数值型,也可以是字符型 (~匹配;!~ 不匹配)
[root@shell /shell]# awk -F:  '$3 ~ /1/{print $1,$3}' passwd		
# $3匹配1的
[root@shell /shell]# awk -F:  '$3 !~ /1/{print $1,$3}' passwd 
# 筛选$3这列,不匹配1的

4. 算数运算符
+ - * / % ^(幂运算)

[root@shell /shell]# cat num
2 9 4
7 5 3
6 1 8

[root@shell /shell]# awk '$3-$2 >=1{print $3,$2}' num	
# 计算$3减去$2结果大于等于1的,按照$3,$2 顺序显示出来
8 1

[root@shell /shell]# cat f6
zhangyi 80 85 86
lier 78 76 90
wangsan 91 89 75

求出每个人的总成绩?平均分?

[root@shell /shell]# awk '{print $1,$2+$3+$4,($2+$3+$4)/3}' f6
zhangyi 251 83.6667
lier 244 81.3333
wangsan 255 85

格式化输出,名字 总成绩,平均分保留2位小数

[root@shell /shell]# awk  '{printf "%-7s %-3d %-5.2f \n",$1,$2+$3+$4,($2+$3+$4)/3}' f6



awk的完成格式:
BEGIN{} 在处理文本文件之前,执行的操作
打出表头
设置变量
定义分隔符
只执行1次
/定址/{} 处理文本文件,有定址,处理匹配定址的行;没有定址,处理整个文件
文件有几行,执行几次
END{} 在处理文本文件之后,执行的操作
数据汇总
只执行1次


[root@shell /shell]# awk  'BEGIN{print "|姓名|总成绩|平均分|";print "-------------------"}{printf "|%-7s|%-3d|%-5.2f|\n-------------------\n",$1,$2+$3+$4,($2+$3+$4)/3}' f6
|姓名|总成绩|平均分|		# BEGIN{print “”} 可以添加标题,
-------------------
|zhangyi|251|83.67|
-------------------
|lier   |244|81.33|
-------------------
|wangsan|255|85.00|
-------------------

awk的变量:

1. 内置变量
$0
$1 $2 $3 …
FS 输入列的分隔符
OFS 输出列的分隔符

(1)NR 行号

NR添加行号。($0表示每一行)
[root@shell /shell]# awk '{print NR,$0}' p3		

打印第一行,NR在{  }前边表示第几行
[root@shell /shell]# awk 'NR==1{print $0}' p3		

打印第一行和第三行,NR在{  }前边表示第几行
[root@shell /shell]# awk 'NR==1 || NR==3{print $0}' p3		

打印第一行到第三行 (范围行数) 
[root@shell /shell]# awk 'NR>=1 && NR<=3{print $0}' p3  

(2)NF 列的数量
文件中,列的数量不一致。(比如个人信息,每个人填的不一样多)

取每一行的最后一列(最后一个)
[root@shell /shell]# awk '{print $NF}' a1		# 倒数第1列
	
倒数第二列 NF-1
[root@shell /shell]# awk '{print $(NF-1)}' a1  # 倒数第2列

(3)FS 一般在脚本里使用
== -F

[root@shell /shell]# awk 'BEGIN{FS=":"}{print $1}' p3		#
BEGIN{FS=":"}代替 -F

(4)OFS

[root@shell /shell]# awk 'BEGIN{FS=":";OFS="\t"}{print $1,$2,$3,$4}' p3		# 按照 : 分隔符划分列,然后输出$1,$2,$3,$4,输出后按照tab格式间隔开
  1. 自定义变量
    变量=值
    变量=数
    变量=“字符串”

    赋值运算:
    a=5
    a+=5 a=a+5
    a-=5

$2,$3,$4的总和,然后求平均数:
[root@shell /shell]# awk '{total=$2+$3+$4;print $1,total,total/3}' f6
zhangyi 251 83.6667
lier 244 81.3333
wangsan 255 85
[root@shell /shell]# awk '{total=$2+$3+$4;avg=total/3;print $1,total,avg}' f6
zhangyi 251 83.6667		total变量表示总和
lier 244 81.3333				avg 变量表示平均数
wangsan 255 85				输出第一列,总和,平均分

[root@shell /shell]# awk '{a+=1;print a}' p3
1
2
3
4
5
6
7
8
9
10
[root@shell /shell]# awk '{a+=1}END{print a}' p3
10
[root@shell /shell]# cat f6
name	ULE	ULA	oracle
zhangyi	80	85	86
lier	78	76	90
wangsan	91	89	75

打印每科的总成绩?

[root@shell /shell]# awk '{ule+=$2;ula+=$3;oracle+=$4}END{print ule,ula,oracle}' f6
# 打印每科的总成绩
249 250 251

写awk脚本:
把命令行搬到文件里。

[root@shell /shell]# vim f6.awk1
BEGIN{
}
{
    ule+=$2
    ula+=$3
    oracle+=$4
}
END{
    print ule,ula,oracle
}

[root@shell /shell]# awk -f f6.awk1 f6
249 250 251

awk 的判断

if (判断条件)
{
动作
}
else
{
动作
}

多分支判断
if (判断条件)
{
动作
}
else if (判断条件)
{
动作
}
else if (判断条件)
{
动作
}
else
{
动作
}

[root@shell /shell]# cat f6
name ule ula oracle
zhangyi 80 85 86
lier 78 76 90
wangsan 91 89 75
zhaosi 65 77 57
liuwu 78 67 54
zhouliu 85 79 91
maqi 55 67 63

判断标准:
A 90-100
B 80-89
C 70-79
D 60-69
E 0-59

统计:ule个标准的人数有几个?

BEGIN{
    a=0
    b=0
    c=0
    d=0
    e=0

#可以这么写:a=b=c=d=e=0

}
NR>1{
    if($2>=90 && $2<=100)
    {
        a+=1
    }
    if($2>=80 && $2<=89)
    {
        b+=1
    }
    if($2>=70 && $2<=79)
    {
        c+=1
    }
    if($2>=60 && $2<=69)
    {
        d+=1
    }
    if($2>=0 && $2<=59)
    {
        e+=1
    }
}
END{
    print "ULE成绩是A的有"a"人"
    print "ULE成绩是B的有"b"人"
    print "ULE成绩是C的有"c"人"
    print "ULE成绩是D的有"d"人"
    print "ULE成绩是E的有"e"人"
}

awk 的循环

(1)while
变量=初值
while (条件表达式)
{
动作
变量更新
}

(2)for
for(变量=初值;变量的取值范围;变量更新)
{
动作
}

倒序输出passwd文件的每一列:
while方式:

BEGIN{
    FS=":"		# 表示标记文件文件的分隔符
}
{
    i=NF		# i=NF 表示列数
    while(i>1)	# 循环开始:当i大于1的时候
    {
        printf "%s:",$i   输出列
        i=i-1
    }
    print $1
}
BEGIN{
    FS=":"
}
{
    for(i=NF;i>1;i--)
    {
        printf "%s:",$i
    }
    print $1
}

循环 + 判断
[root@shell /shell]# cat num
2 9 4
7 5 3
6 1 8

练习:
打印出每行最大的数字?

{
    max=0
    i=1
    while (i<=NF)
    {
        if (max<$i)
        {
            max=$i
        }
        i=i+1
    }
    print max
}

打印出每行最小的数字?

{
    min=999999999999
    i=1
    while (i<=NF)
    {
        if (min>$i)
        {
            min=$i
        }
        i=i+1
    }
    print min
}

打印出整个文件最大的数字?

BEGIN{
    max=0
}
{
    i=1
    while (i<=NF)
    {
        if (max<$i)
        {
            max=$i
        }
        i=i+1
    }
}
END{
    print max
}

打印出整个文件最小的数字?


 awk的数组
数组用于存储一组值。
数组里面的值(元素)用数组下标来表示。
数组名[下标]=元素
	数组名	[a-Z][a-Z0-9_]*
	下标		数字(正整数)
	元素		"字符串" 数字

name ule ula oracle
zhangyi 80 85 86
lier 78 76 90
wangsan 91 89 75
zhaosi 65 77 57
liuwu 78 67 54
zhouliu 85 79 91
maqi 55 67 63

每个人的总成绩,总平均分
求每科的平均分:每科总成绩/(NR-1)
	ule_total+=$2
	ule_avg=ule_total/(NR-1)

需求:
每科超过平均分的有几个人?都是谁?

练习:模拟tac
元素 $0
下标
正整数 没有定义,默认从0开始;可以定义从1开始
NR
名字

{
    line[i++]=$0
}
END{
    for(j=NR-1;j>=0;j--)
    {
        print line[j]
    }

}
	下标从0开始,到NR-1结束
BEGIN{
    i=1
}
{
    line[i++]=$0
}
END{
    for(j=NR;j>=1;j--)
    {
        print line[j]
    }

}
	下标从1开始,到NR结束
{
    line[NR]=$0
}
END{
    for(j=NR;j>=1;j--)
    {
        print line[j]
    }

}
	下标直接使用NR

完成需求:

BEGIN{
    ule_total=0		# 定义各科的初始值为0
    ula_total=0
    oracle_total=0

    ule_num=ula_num=oracle_num=0 # 定义各科的平均分人数为0
}
NR>1{
# 成绩的累加
    ule_total+=$2	# 计算各科的总和
    ula_total+=$3
    oracle_total+=$4
# 数组传值
    name[NR]=$1 	# 定义名字的数组
    ule[NR]=$2		# 定义ule科目的数组
}
END{
# 求出各科的平均分
    ule_avg=ule_total/(NR-1)	# 计算平均分 (NR-1)表示出了标题行的所有行
    ula_avg=ula_total/(NR-1)
    oracle_avg=oracle_total/(NR-1)
    printf "ULE的平均分是:%.1f\n",ule_avg	# 输出结果
    printf "ULA的平均分是:%.1f\n",ula_avg
    printf "ORACLE的平均分是:%.1f\n",oracle_avg
# 求出超过ule平均分的人数
# 定义一个新的数组,将超过平均分的人名传给数组
    for(i=2;i<=NR;i++)	# 设置条件(i自定义取值),因为没有标题行,所以i从2开始;(i<=NR)表示NR从2开始大于等于i;(i++)表示i增加
    {
        if (ule[i]>ule_avg)
        {
            ule_num+=1
            new_name[j++]=name[i]	# 定义一个新的数组,将超过平均分的人名传给数组
        }
    }
    print "超过ule平均分的有"ule_num"个人"
    # 遍历超过ule平均分的人名数组

    printf "超过ule平均分的是:"
    for (k=0;k<=ule_num;k++)
    {
        printf new_name[k]" "
    }
    printf "\n"	# 为了输出结果时,光标不跟随显示,添加换行符

}	

求出各科最高分是谁?

BEGIN{
ule_max=ula_max=oracle_max=0
}
if ($2>ule_max)
{
ule_max_name=$1
ule_max=$2
}


awk 常用函数
sub gsub 替换

[root@shell /shell]# cat pet 
cat dog bird pig
dog cat dog bird
cat bird cat cat

[root@shell /shell]# awk '{sub(/cat/,"snake");print}' pet
snake dog bird pig
dog snake dog bird
snake bird cat cat

[root@shell /shell]# awk '{gsub(/cat/,"snake");print}' pet
snake dog bird pig
dog snake dog bird
snake bird snake snake

[root@shell /shell]# awk '{gsub(/cat/,"snake",$3);print}' pet
cat dog bird pig
dog cat dog bird
cat bird snake cat
	替换第3列的猫为蛇

toupper() 小写转大写
tolower() 大写转小写

[root@shell /shell]# awk ‘{print toupper($0)}’ pet

[root@shell /shell]# awk ‘{print toupper($1)}’ pet

[root@shell /shell]# awk ‘{print toupper($1),toupper($2)}’ pet


文本文件的处理命令:
grep
sed
awk ***
处理文本文件只是让其输出更人性化。

sed -i 更改原文件。

[root@shell /shell]# sed -i 's/cat/CAT/' pet
[root@shell /shell]# cat pet
CAT dog bird pig
dog CAT dog bird
CAT bird cat cat

[root@shell /shell]# sed -i.bak 's/CAT/cat/g' pet
	改变的同时,原文件备份下来

[root@shell /shell]# cat pet
cat dog bird pig
dog cat dog bird
cat bird cat cat
[root@shell /shell]# cat pet.bak 
CAT dog bird pig
dog CAT dog bird
CAT bird CAT CAT

sed -r 让sed支持扩展正则


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值