awk
awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大。简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理。
调用awk的三种方式
1.命令行方式
awk [-F field-separator] 'commands' input-file(s)
其中,commands 是真正awk命令,[-F域分隔符]是可选的。 input-file(s) 是待处理的文件。
在awk中,文件的每一行中,由域分隔符分开的每一项称为一个域。通常,在不指名-F域分隔符的情况下,默认的域分隔符是空格。
2.shell脚本方式
将所有的awk命令插入一个文件,并使awk程序可执行,然后awk命令解释器作为脚本的首行,一遍通过键入脚本名称来调用。
相当于shell脚本首行的:#!/bin/sh
可以换成:#!/bin/awk
3.将所有的awk命令插入一个单独文件,然后调用:
awk -f awk-script-fileinput-file(s)
其中,-f选项加载awk-script-file中的awk脚本,input-file(s)跟上面的是一样的。
基本用法实例,一些规则可从例子中总结
1.显示最近登陆系统的五个用户
last –n 5 | awk '{print $1}' #$1表示第一项,$NF表示最后一项
awk工作流程是这样的:读入有'\n'换行符分割的一条记录,然后将记录按指定的域分隔符划分域,填充域,$0则表示所有域,$1表示第一个域,$n表示第n个域。默认域分隔符是"空白键" 或 "[tab]键"
2.查看/etc/passwd获取所有用户
cat /etc/passwd | awk –F ':' '{print $1}' #-F指定分隔符
3.获取用户名及其登陆shell,用tab分开
cat /etc/passwd | awk -F ':' '{print $1"\t"$7}'
4.获取用户及其登陆shell,用逗号隔开,对所有行添加列名name,shell,在最后一行添加"blue,/bin/nosh"
cat /etc/passwd | awk -F ':' 'BEGIN {print"name,shell"} {print $1","$7} END {print"blue,bin/nosh"}'
打印的信息需加双引号
5.搜索/etc/passwd中含root关键字的行
awk –F ':' '/root/' /etc/passwd # //不可少
支持正则.如搜索以root关键字开头的行
awk –F ':' '/^root/' /etc/passwd
其实这里的两句都不用–F ':'
6.搜索/etc/passwd中有root关键字的行,并输出第七个域
awk –F ':' '/root/{print$7}' /etc/passwd
命令只能写在第二个引号里,看来可以把搜索条件和print放一起
7.搜索uid,gid均为500的行
awk -F ':' '$3 == 500,$4 == 500' /etc/passwd
8.匹配多个空格
awk -F ' +' '{print $2}' testfile
匹配多个空格或:
netstat –lnt | grep 80
tcp 0 0 :::80 :::* LISTEN
现在要取出80
netstat –lnt | grep 80 | awk –F '[ :]+' '{print$4}'
也可以
netstat –lnt | grep 80 | awk –F ' +' '{print$4}' | cut -d ':' -f 4
awk内置变量
ARGC 命令行参数个数
ARGV 命令行参数排列
ENVIRON 支持队列中系统环境变量的使用
FILENAME awk浏览的文件名
FNR 浏览文件的记录数
FS 设置输入域分隔符,等价于命令行 -F选项
NF 浏览记录的域的个数
NR 已读的记录数
OFS 输出域分隔符
ORS 输出记录分隔符
RS 控制记录分隔符
变量应用实例
对/etc/passwd,输出:文件名 行号 每行列数 每列内容
awk -F ':''{print "filename:" FILENAME ",linenumber:" NR",columns:" NF ",linecontent:" $0}' /etc/passwd
使用printf,代码更简洁、易读
awk -F ':''{printf("filename:%5s,linenumber:%s,columns:%s,linecontent:%s\n"),FILENAE,NR,NF,$0}'/etc/passwd
$0表示所有域
print和printf
awk中同时提供了print和printf两种打印输出的函数。
其中print函数的参数可以是变量、数值或者字符串。字符串必须用双引号引用,参数用逗号分隔。如果没有逗号,参数就串联在一起而无法区分。这里,逗号的作用与输出文件的分隔符的作用是一样的,只是后者是空格而已。
printf函数,其用法和c语言中printf基本相似,可以格式化字符串,输出复杂时,printf更加好用,代码更易懂。
(更多用法今后需要再补充)
sed
正则表达式与元字符
元字符 |
功能 |
示例 |
^ |
行首定位符 |
/^my/ 匹配所有以my开头的行 |
$ |
行尾定位符 |
/my$/ 匹配所有以my结尾的行 |
. |
匹配除换行符以外的单个字符 |
/m..y/ 匹配包含字母m,后跟两个任意字符,再跟字母y的行 |
* |
匹配零个或多个前导字符 |
/my*/ 匹配包含字母m,后跟零个或多个y字母的行 |
[] |
匹配指定字符组内的任一字符 |
/[Mm]y/ 匹配包含My或my的行 |
[^] |
匹配不在指定字符组内的任一字符 |
/[^Mm]y/ 匹配包含y,但y之前的那个字符不是M或m的行 |
\(..\) |
保存已匹配的字符 |
1,20s/\(you\)self/\1r/ 标记元字符之间的模式,并将其保存为标签1,之后可以使用\1来引用它。最多可以定义9个标签,从左边开始编号,最左边的是第一个。此例中,对第1到第20行进行处理,you被保存为标签1,如果发现youself,则替换为your。 |
& |
保存查找串以便在替换串中引用 |
s/my/**&**/ 符号&代表查找串。my将被替换为**my** |
\< |
词首定位符 |
/\ |
\> |
词尾定位符 |
/my\>/ 匹配包含以my结尾的单词的行 |
x\{m\} |
连续m个x |
/9\{5\}/ 匹配包含连续5个9的行 |
x\{m,\} |
至少m个x |
/9\{5,\}/ 匹配包含至少连续5个9的行 |
x\{m,n\} |
至少m个,但不超过n个x |
/9\{5,7\}/ 匹配包含连续5到7个9的行 |
命令太多,只列出目前常用的
s |
用一个字符串替换另一个 |
g |
在行内进行全局替换 |
p |
打印行。命令p用于显示模式空间的内容。默认情况下,sed把输入行打印在屏幕上,选项-n用于取消默认的打印操作。当选项-n和命令p同时出现时,sed可打印选定的内容 |
i |
搜索不区分大小写。默认sed区分大小写搜索 |
d |
删除行 |
sed选项
选项 |
功能 |
-e |
进行多项编辑,即对输入行应用多条sed命令时使用 |
-n |
取消默认的输出 |
-f |
指定sed脚本的文件名 |
例
1.s,g命令
a.行内全局替换
echo"hello world" | sed 's/ll/kk/g'
如果没有g,那么每行只替换一次
b.改变默认分隔符/。紧跟在s命令后的字符就是查找串和替换串之间的分隔符
echo"hello world" | sed 's#ll#kk#g'
2.p命令
a.取消默认输出,处理1到20行里匹配以nologin结尾的行,把行内所有的nologin替换为NOLOGIN,并打印到屏幕上
sed -n '1,20s/nologin$/NOLOGIN/gp'/etc/passwd
在此句中,-n取消默认输出,p指定了输出的行,所以只打印了1到20行里匹配以nologin结尾的行
b.打印所有行,如果有行含nologin,那么该行再打印一次
sed '/nologin/p'passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/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
……
c.打印含nologin的行
sed -n '/nologin/p' passwd
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
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
gopher:x:13:30:gopher:/var/gopher:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
……
d.取出第一行
sed –n ‘1p’ file
3.i命令
sed 's/cat/dog/gi' sed_file
4.d命令
a.删除文件中1-5行内容,然后打印全部内容
sed'1,5d' passwd
b.删除最后一行,然后打印全部内容
sed'$d' passwd
c.删除包含nologin的行,然后打印所有内容
sed'/nologin/d' passwd
5.-e参数
sed -e 's/bin/BIN/g' -e's/nologin/NOLOGIN/g' passwd
grep
grep 使用BRE书写匹配模式
egrep 使用ERE书写匹配模式,等效于grep -E。
fgrep 不使用任何正则表达式书写匹配模式(以固定字符串对待),执行快速搜索等效于grep –F
Unix的grep家族包括grep、egrep和fgrep。egrep和fgrep的命令只跟grep有很小不同。egrep是grep的扩展,支持更多的re元字符, fgrep就是fixed grep或fast grep,它们把所有的字母都看作单词,也就是说,正则表达式中的元字符表示回其自身的字面意义,不再特殊。linux使用GNU版本的grep。它功能更强,可以通过-G、-E、-F命令行选项来使用egrep和fgrep的功能。
常用参数
-i : 不区分大小写
-n : 返回行号
-r : 递归搜索,从命名目录开始
-c : 显示具有匹配模式的行的计数
-v : 返回不包含模式的行
--color=auto
-l : 从多个文件中查找包含匹配项
例:
1.在多个文件中搜索
grep 'cat' sed_file passwd
sed_file:cat Cat CAT
passwd:cat:x:500:500::/home/cat:/bin/bash
2.在当前目录的所有文件将中搜索含cat关键字的行,并输出行号(算空行)
grep –n 'cat' *
menu.sh:4: cat<< EOF
menu.sh:16: cat << EOF
passwd:34:cat:x:500:500::/home/cat:/bin/bash
read_line.sh:4:cat test1.sh | while read line
sed_file:1:cat Cat CAT
sed_file:6:cat #很强大呢。sed_file第6行前有空行的,也可以
在当前目录的所有文件中搜索含*的行
grep '*' *
搜索含$的行
grep : grep '\$' test1.sh
fgrep : grep $ test1.sh
3.匹配所有空行
grep -n '^$' test1.sh
2:
10:
12:
4.显示首字符为字母的所有行
grep -n '^[a-zA-Z]' file
5.打印首字符不是#的行
grep -v '^#' test1.sh
6.打印至少含有5个连续小写字母的行
grep '[a-z]\{5\}' file
7.找出文件中含132的行及其前2行和后3行
grep -n -B2 -A3 '132' file
5-1sdf
6-cat
7:132
8-abcde
9-abcdefg
10-abcdefghijklmn
并且含132的行号后是:,而其它几行行号后是-
8.在当前目录递归查找CAT
grep -r 'CAT' *
file:cat Cat CAT
test/file3:CAT
grep -l -r 'CAT' *
file
test/file3
9.查找cat或bin
grep “cat\|bin”*
egrep “cat|bin”*
grep结合正则表达式
1.[]里的字符任取其一,比如[ae]表示取a或者取e
grep -n 't[ae]st' file
13:finish the test.
14:the soup taste good.
2.找出含oo的行,但oo前不能是g
grep -n '[^g]oo' file
16:apple is my favorite food
17:Football game is not use feet only
18:google is the best tool for searchkeyword.
19:goooooogle yes
第18行被打印是因为有tool,19行被打印是因为oooooo
限制oo前不能是小写字母
grep -n '[^a-z]oo' file
连续字符用[0-9a-zA-Z]来表示所有英文字母和数字
^放在[xx]前表示以xx开头,如果[^xx]表示非xx
3.找出以小数点.结尾的行
grep -n '\.$' file
13:finish the test.
14:the soup taste good.
18:google is the best tool for search keyword.
4. .*
.代表一定有一个字符,任意
*代表重复前一字符0到无穷次
找出g??d的字符串,g开头,d结尾,共4个字符
grep 'g..d' file
找出至少含2个oo的行
grep 'ooo*' file
找出g开头,g结尾的字符所在行,当中字符可有可无
grep 'g.*g' file
找出含任意数字的行
grep '[0-9][0-9]*' file
5.限定连续RE字符串范围{}
找出2个连续的o
grep -n 'o\{2\}' file
g后面接2-5个o,并且以g结尾
grep -n 'go\{2,5\}g' file
至少含3个o的行
grep -n 'o\{3,\}' file
这些应该够日常用了
cut
参数
-b: 以字节为单位分割
-c: 以字符为单位分割
-d: 自定义分隔符,默认是tab
-f: 指定要从每行中提取的字段
select only these fields; also print any line that contains no delimiter character, unless the -s optionis specified
-n: 取消分割多字节字符,与-b一起使用
with -b: don’t splitmultibyte characters
--complement : complement the set of selected bytes,characters or fields
-s: do not print lines not containing delimiters
--output-delimiter=STRING: use STRING as the output delimiter the defaultis to use the input delimiter
Use one, and only one of -b, -c or -f. Each LIST is made up of onerange, or many ranges separated by commas. Selected input is written in the same orderthat it is read, and is written exactly once.Each range is one of:
N N’th byte, character orfield, counted from 1
N- from N’th byte, characteror field, to end of line
N-M from N’th to M’th(included) byte, character or field
-M from first to M’th(included) byte, character or field
With no FILE, or when FILE is -, read standard input.
例:
1.从/etc/passwd文件中提取第3字段
cut -f 3 -d ':' /etc/passwd
相当于awk –F ':' '{print $3}' /etc/passwd
2.提取每行第3字节
who | cut –b 3
who | cut –c 3
3.提取每行1-3字节和第12字节
who | cut –b 1-3,12
who | cut –c 1-3,12
需要注意的是,如果使用了-b,-c,cut会对后面的数字排序,比如
who | cut –b 12,1-3
who | cut -c 12,1-3
输出结果不变
4.N-,-M
who | cut –b -3 #提取前3个字节(含第3个字节)
who | cut –b 3- #提取从第3个直接开始到末尾(含第3个字节)
who | cut –b -3,3- #提取整行
此处-b和-c等效
5.-b和-c在对英文处理时看不出区别,下面处理中文
cat cut.txt
星期一
星期二
星期三
星期四
cat cut.txt | cut -b 3
�
�
�
�
cat cut.txt | cut -c 3
一
二
三
四
当遇到多字节字符时,使用-n告诉cut不要将多字节字符拆开,如:
cat cut.txt | cut -nb3
星
星
星
星
6.-f指定域,可同时提取多个域
cat passwd | cut -d : -f 1-3,5
很好用,输出不如awk的print和printf定义性强
7.cut -d ' ' -f 2 testfile
cut: the delimiter must be asingle character
Try `cut --help' for more information.t有个缺点,就是不能匹配多个空格
这时就需要awk了
awk -F ' +' '{print $2}' testfile
uniq
uniq“删除”文件中重复的相邻行。若要只打印文件中出现的唯一行(“删除”所有重复行),必须首先对uniq的输入进行排序。由于可以为uniq指定其决策所基于的字段或列,因此这些字段或列是对其输入进行排序所必须的字段或列。如果未与选项一起使用,uniq会使用整个记录作为决策键,删除其输入中的重复行
先使用sort可使重复行排列在一起,方便uniq。如果未排序,重复行不连续,直接使用uniq会看到重复行出现多次。
cat file
hello
world
cat
cat
hello
未排序直接uniq
uniq file
hello
world
cat
hello
排序后uniq
cat file | sort | uniq
cat
hello
world
如果不加参数,如uniq file,那么uniq从上到下读文件,遇到连续重复行就输出一行,否则原样输出。也就说明了为什么要先sort
参数
-u : 仅显示唯一行(只出现一次的行),打印一次
-d : 显示重复行(出现过2次及2次以上的行),打印一次
-c : 计数
-f n : 忽略前n个域(包括n)
-i : 忽略大小写
参数使用:
-u
cat file | sort | uniq #列出了唯一行和重复行
cat
hello
world
cat file | sort| uniq –u #找出了唯一行
world
-d
cat file | sort| uniq -c –d #列出出现过2次及2次以上的行
2 cat
2 hello
-i
cat file
hello
world
cat
cat
hello
CAT
cat file | sort| uniq –i –c –d #-i忽略大小写
3 cat
2 hello
-fn 排除第n个域及其之前域,即不作比较
cat file
AK123 33 46 6u OPP ty yu
DK122 5h 67 y8 OPP ty yu
EK999 56 78 78 IIY ty yu
cat file | sort| uniq -f 4 -c
2 AK123 33 46 6u OPP ty yu
1 EK999 56 78 78 IIY ty yu
如果使用-f报错,试试用-n替代
sort
参数
-f :忽略大小写的差异,例如 A 与 a 视为编码相同;
-b :忽略最前面的空格符部分;
-M :以月份的名字来排序,例如 JAN, DEC 等等的排序方法;
-n :使用『纯数字』进行排序(默认是以文字型态来排序的);
-r :反向排序;
-u :就是 uniq ,相同的数据中,仅出现一行代表;
-t :分隔符,默认是用 [tab] 键来分隔;
-k :以某个区间 (field)来进行排序的意思
例
1.以第3个字段值排序,并取出来
cat /etc/passwd | sort -t ':' -k 3 -n | awk -F ':' '{print $3}'
cat /etc/passwd | sort -t ':' -k 3 -n | cut-d ':' -f 3
2.反向排列(-r)
cat /etc/passwd | sort -t ':' -k 3 -nr | cut-d ':' -f 3
3. 对/etc/passwd,先以第六个域的第2个字符到第4个字符进行正向排序,再基于第一个域进行反向排序
cat /etc/passwd | sort -t ':' -k 6.2,6.4 -k1 -r
4.统计/etc/passwd中共多少个shell,各有多少个用户使用,并按用户数由小到大输出
cat /etc/passwd | cut -d ':' -f 7 | sort | uniq -c | sort -n -k 1
tr
tr用于转字符。如果给定了两个字符范围,则只要发现某个字符位于第一个范围中,就会将其转换为第二个范围中对等的字符。该命令通常在shell脚本中使用,以按预期情况转换数据
[o*n]表示字符o重复n次
例:
1.将用户输入中大写字母转换为小写字母
#!/bin/bash
echo -n "enter yes or no:"
read answer
answer="$(echo $answer | tr 'A-Z' 'a-z')"
echo $answer
wc
参数
-l : 行数
-m : 字符数(chars)
-c : 字节数(bytes)
-w : 字数(words)
-L : 打印最长行的长度(printthe length of the longest line)
--files0-from=F
read input from the files specified byNUL-terminated names in file F; If F is - then read names from standard input
在传统unix系统中,一个字符占用一个字节,所以-m和-c等效。但随着unicode的出现,一些字符可以占用四个字节,因此,如果文档使用任何非ASCII字符,则需要使用-m选项以获得准确的字符计数。
例:
1.
cat file
abc abc
!@#$%
abc
直接cat不容易看,加上-ET参数,显示行尾的$和tab
cat –ET file
abc abc$
!@#$%$
^I^I$
abc$
cat file | wc
4 4 21
行数 字数 字节数
cat file | wc –l #算空行
4
cat file | wc -w
4
cat file | wc -c
21
cat file | wc –m
21
可知-l以换行作为计数依据;-m以空格或者回车分割内容;-c与-m除了计数字母外,还计数行尾符$和tab键。一个字母是一个字节,也即一个字符
2.如果文件中含有中文
cat file
abc abc
!@#$%
abc
猫 猫
猫
cat –ET file
abc abc$
!@#$%$
^I^I$
abc$
猫 猫$
猫$
cat file | wc
6 7 34
cat file | wc -c
34
可知一个中文字占3个字节
cat file | wc -m
28
一个中文字占1个字符
最终结论:
1. 可知-l以换行作为计数依据;-m以空格或者回车分割内容;-c与-m除了计数文字外,还计数符号、行尾符$和tab键。
2.一个字母、一个符号或一个空格是一个字节,也即一个字符。一个中文字占3个字节(c),一个中文字占1个字符(m)
head
默认输出文件前10行
参数:
-c,--bytes=[-]K
print the first K bytes of each file; with the leading ‘-’,print all but the last K bytes of each file
-n,--lines=[-]K
print the first K lines instead of the first 10; with the leading ‘-’, printall but the last K lines of each file
-q,--quiet, --silent
never print headers giving file names(查看多个文件时不显示文件名)
-v,--verbose
always print headers giving file names(查看多个文件时显示文件名)
例:
-c(默认单位为字节)
获取文件前20字节内容
head–c 20 file
获取文件前1K内容
head–c 1K file
不显示最后20字节内容
head–c -20 file
-n
获取文件前5行内容
head –n 5 file
不显示最后5行内容
head–n -5 file
-q
head -n 5 -q test1.sh test2.sh
#!/bin/bash
for i in $(seq 0 1) #equal to "for((i=0;i<2;i++))"
do
for j in $(seq 0 1)
#!/bin/bash
for ((i=0;i<2;i++))
do
for j in $(seq 0 1)
-v(默认)
head -n 5 -v test1.sh test2.sh
==>test1.sh <==
#!/bin/bash
for i in $(seq 0 1) #equal to "for((i=0;i<2;i++))"
do
for j in $(seq 0 1)
==> test2.sh <==
#!/bin/bash
for ((i=0;i<2;i++))
do
for j in $(seq 0 1)
tail
参数:
-c,--bytes=K
outputthe last K bytes; alternatively, use -c +K to output bytes starting with theKth of each file
-f,--follow[={name|descriptor}]
outputappended data as the file grows; -f, --follow, and --follow=descriptor areequivalent(实时监控文件变化)
-F same as --follow=name --retry
-n,--lines=K
outputthe last K lines, instead of the last 10; or use -n +K to output lines starting with the Kth
--pid=PID
with -f, terminate after process ID, PID dies(与-f合用,在进程id,pid死后结束)
-q,--quiet, --silent
never output headers giving file names
-v,--verbose
always output headers giving file names
--retry
keep trying to open a file even when it is or becomes inaccessible;useful when following by name, i.e., with --follow=name
-s, --sleep-interval=N
with -f, sleep for approximately N seconds (default 1.0) between iterations.Withinotify and --pid=P, check process P at least once every N seconds.
掌握-c,-n,-f,-q,-v就好
例:
-c
显示最后20字节
tail -c 20 file
显示最后1k内容
tail –c 1K file
-n
显示最后5行
tail–n 5 file
从文件第5行开始显示
tail –n +5 file
-f
tail –f xxx.log
-q
tail -n 5 -q test1.sh test2.sh
do
eval echo -n "\$man$i$j\ "
done
echo #equal to "printf "\n" "
done
do
eval echo -ne "\$man$i$j\ "
done
printf "\n"
done
-v
tail -n 5 -v test1.sh test2.sh
==> test1.sh <==
do
eval echo -n "\$man$i$j\ "
done
echo #equal to "printf "\n" "
done
==> test2.sh <==
do
eval echo -ne "\$man$i$j\ "
done
printf "\n"
done