awk入门学习笔记

来源:互联网 发布:8051 单片机有哪些 编辑:程序博客网 时间:2024/06/06 00:06

零、awk的介绍
awk是Linux及Unix操作系统中非常优秀的数据及文本处理工具,它是一种编程语言。
主要用途是自动化运维和文本处理
一、awk基本语法
1、命令行格式:
awk -F' ' '{print $1}' pets.txt
awk -F '{print $1}' pets.txt(因为默认是空格,所以这种情况和上面的等效,但是我在尝试的时候会报错)
-F后面是指定的分隔符,:或者' '

awk 'BEGIN{FS=" "}{print $1}' pets.txt
2、文本格式:
#!/usr/bin/awk
BEGIN{ FS=":"}
{print $1}

二、awk的变量
1、常用内置变量
$0 当前所有字段
$1~$n 当前第n个字段
FS 分隔符(默认为空格)
NF 字段个数
NR 行号
RS 输入记录的分隔符(默认为空格)

2、RS是指定的换行符,系统默认是\n进行换行,但是如果我们不希望使用\n而是使用自定义的换行符来进行分行,
那么只需要更改RS参数的值即可
awk 'BEGIN{RS=" "}{print $0}' pets.txt

3、NF是列数,如果我们需要打印每一行按照我们指定的分隔方法有多少列,可以用如下命令调用
awk -F":" '{print NF}' /etc/passwd----------->输出若干列7,代表文件中每一行中以“:”作为分隔符都有7列。

4、NR是行号,如果我们需要给文件的每一行加上一个固定的行号格式,例如 "1 : "的形式,可以使用以下语句
awk -F' ' '{print NR" : " $0}' pets.txt

5、调用外部变量
awk -v host=$HOSTNAME 'BEGIN{print host}'
也可以自己定义变量名
awk -v host="host" 'BEGIN{print host}'

三、awk的操作符
关系操作符:<、>、<=、>=、==、!=、~ 、!~
1、按照指定要求匹配内容,如果我们需要匹配passwd文件中第七列是以/bin开头的那些行,可以如下表示
awk -F: '$7 ~ /^\/bin/{print $0}' /etc/passwd
冒号分隔 ~代表匹配 ^代表字符串起始标志,匹配内容是/bin(注意后面还要带一个/,否则会报错)
那如果我们需要不匹配/bin开头的行,只需要将~改成!~即可。
上述代码也可以用变量的形式来替代
awk -F: -v reg='^/bin.*' '$7 ~ reg {print $0}' /etc/passwd
用一个正则表达式 reg来代替^/bin.*,然后再匹配第七列符合正则表达式的行并且返回
2、print与printf
如果要打印 /etc/passwd 中的“第一列 : 第二列”这种形式的输出,可以如下操作:
awk -F: '{print $1" : "$2}' /etc/passwd
如果要实现上述功能,可以用printf操作如下:
awk -F: '{printf("%s : %s\n",$1,$2)}' /etc/passwd

四、awk的流程控制
1、条件语句
格式:if(expression) action1;[else action2]
输入一串数字,单数打印no,双数打印yes,可以如下表示
seq 10|awk '{if($0%2==0){print "ok"}else {print "no"}}'
对文件操作,如果/etc/passwd最后一列是以/bin/bash结尾的,那么就打印整行的内容
awk -F: '{if($NF=="/bin/bash"){print $0}}' /etc/passwd
同样可以不写if语句加上一次判断实现一样的功能
awk -F: '$NF=="/bin/bash" {print $0}' /etc/passwd
2、循环语句
格式:while(condition) action
例:如果我们需要给每个按照分隔符分开的列加上一个列号,如 1:第1列的内容 2:第二列的内容,.......
awk -F: '{i=1;while(i<=NF){printf(" %d:%s",i,$i);i++}{print " "}}' /etc/passwd
同样也能用for循环完成同样的功能
awk -F: '{for(i=1;i<=NF;i++){printf(" %d:%s",i,$i)}{print " "}}' /etc/passwd
例:需要统计最后一列的词出现的频数
awk -F: '{a[$NF]++}END{for(i in a){print i":"a[i]}}' /etc/passwd

3、awk数组
定义一个数组并且打印它
awk 'BEGIN{a[5]="Jack";a["name"]="Lilei";print a[5],a["name"]}'
同样可以用循环来遍历
awk_sed$ awk 'BEGIN{a[5]="Jack";a["name"]="Lilei";for(i in a)print i":"a[i]}'

netstat -an | awk '/^tcp/{state[$NF]++}END{for(key in state){print key"\t"state[key]}}'
五、awk函数
1、算术函数
awk的算术函数、字符串函数
int(x) 返回x的整数部分的值
sqrt(x) 返回x的平方根
rand() 返回伪随机数r,其中0<=r<1
sand(x) 建立rand()新的种子数。如果没有指定就用当天的时间。
随机数示例:
awk 'BEGIN{print rand();srand();print rand()}'
2、字符串函数
sub(),gsub() 替换函数
index(s,t) 返回子串t在字符串s中的位置,如没有则返回0。
length(s) 返回字符串长度,当没有给出s时,返回$0的长度。
match(s,r) 如果正则表达式r在s中匹配到,则返回出现的起始位置,否则返回0
split(s,a,sep) 使用sep将字符串s分解到数组a中。默认sep为FS。
tolower(s) 将字符串s中的所有大写字符转换为小写。
toupper(s) 将字符串s中的所有小写字符转换为大写。
例:替换字符串中的某个单词。将world换成China,
echo "hello world world" | awk '{sub("world","China");print $0}'
输出: hello China world

上例只是替换了一个world,用gsub可以将所有的都进行替换
echo "hello world world" | awk '{gsub("world","China");print $0}'
输出:hello China China

查找子串的位置
echo "hello world world" | awk '{print index($0,"world")}'

用指定分隔符分隔字符串
echo "00-11-22-33-44" |awk '{split($0,a,"-");for(i in a){print i":"a[i]}}'

3、自定义函数
自定义加法
awk 'function sum(n,m) {total=n+m;return total} BEGIN{print sum(1,2)}'

六、一些常用的操作
1、获取本机的ip地址
ifconfig eth0 | awk -F':| +' '/inet addr:/{print $4}'
2、统计网络连接数
netstat -an | awk '/^tcp/{state[$NF]++}END{for(key in state){print key"\t"state[key]}}' | column -t
3、在做训练集的时候需要统计不同类别的分布的时候,可以有如下办法(假设label放在最后,个人习惯):
cat test.txt | awk '{count[$NF]++}END{for(key in count){print key"\t"count[key]}}' | sort -k2 -n -r
或者
awk '{print $NF}' test.txt | sort | uniq -c | sort -nr
test.txt的最后一列是label,统计它的label
4、将文件最后一列去掉
awk '{$NF="";print $0 >>"test.txt"}' 51job.txt
5、统计下列表格中的某个ip出现次数

log_time        ip      other

2000    192.168.1.1     100

2001    192.168.1.2     200

2002    192.168.1.2     300

2003    193.168.1.3     400

2003    193.168.1.3     400

2003    193.168.1.3     400

2003    193.168.1.3     400

2003    193.168.1.3     400

2003    193.168.1.3     400

可以使用shell命令   cat ip.txt  | grep 192.168.1.1 | wc -l

也可以用awk: cat ip.txt |awk -F"\t" '{if($2=="192.168.1.2") cnt++}END {print(cnt)}'或者

awk -F"\t" '{if($2=="192.168.1.2") cnt++}END {print(cnt)}' ip.txt

如果需要统计各个ip各自出现的次数:

awk -F'\t' 'NR>1{a[$2]++}END {for(i in a) {print i":"a[i]} }' ip.txt |sort -r

cut -d $'\t' -f 2  ip.txt |tail -n +2| sort -r| uniq -c




0 0