文本处理三剑客:grep sed awk

    grep,egrep,fgrep:文本过滤工具:

    sed:行编辑器

            模式空间、保持空间

    awk:报表生成器,用于格式化文本输出工具;

        基本用法:    

            awk命令软连接到gawk

            gawk [options] 'program' FILE...

                program: PATTERN{ACTION STATEMENTS}

                语句间用分号分隔

        选项:

            -F:指明输入时用到的字段分隔符;

            -v:var=value用于实现自定义变量

处理文本原理:

    一次读取一行文本,首先会把文本通过指明输入分隔符分成n个组成部分

并且将每一片保存在awk的内键变量中,仅显示某一段某些段,显示整段用$0

我们可以随意指定某一个片段,进行模式判断。也可以对每一个片段进行循环加工;循环功能主要用于在字段间进行循环遍历。总结,文本报告输出的工具。

tail -5 /etc/fstab | awk '{print $2,$4}'显示第二个字段和第四个字段,不加逗号会将两个字段连接在一起,加逗号默认以空白字符分隔

一、print

    print item1,item2.....

    要点:

        (1)逗号分隔符

        (2)输出的各item可以是字符串,也可以是字符;当前记录的字段、变量或awk的表达式;

        (3)省略item,相当于print $0;

tail -5 /etc/fstab | awk {print $2 $4}

/defaults

/bootdefaults

/usrdefaults

swapdefaults


tail -5 /etc/fstab | awk '{print $2,$4}'  瞬间发现有“,”和没有区别是很大的,加,默认为空格,不加就会连接在一起

/ defaults

/boot defaults

/usr defaults

swap defaults

 

[root@localhost ~]# tail -5 /etc/fstab | awk '{print "hello:"$1}'hello:UUID=bd3f9d54-f9f2-48df-9441-0050d0e60b4ahello:UUID=81b1d5b7-48ab-41e4-a34a-f865a015d23chello:UUID=c36a0583-ac95-40bc-bb81-eed920e34ec5hello:UUID=9cc0349f-9faa-4bba-8ef7-689d60280aedhello:[root@localhost ~]# tail -5 /etc/fstab | awk '{print "hello:$1"}' 瞬间你会发现$1 变量引用是不可以放在双引号里面的hello:$1hello:$1hello:$1hello:$1hello:$1

二、变量

内建变量

        FS:默认为空白字符

 awk '{print $1}' /etc/passwd 以空白分隔显示第一段 awk  -v FS=':''{print $1} ' /etc/passwd  指明输出分隔符为冒号

        NF:每一行的字段数量 

 awk '{print NF}' /etc/fstab 为每一个行统计字段数量      {print $NF}

        NR:打印每一行的行号

awk  '{print NR}'  /etc/fstab 相当于set nu

        FILENAME:打印当前文件名

awk '{print FILENAME}' /etc/fstab /etc/issue 打印出两个文件的名称

        ARGC:命令行参数的个数

  awk 'BEGIN{print ARGC}' /etc/fstab /etc/issue

       ARGV:数组,保存的是命令行所给定的各参数

awk 'BEGIN{print ARGV[1]}' /etc/fstab /etc/issue

        OFS:默认为空白字符

        RS:输入时的换行符,一行中只要有空格,就当做换行

        ORS:输出时的换行符    

自定义变量

        -v var=value

        变量名区分字符大小写

        在program中直接定义

~]#awk -v test='hello gawk' '{print test}' /etc/fstabhello gawk
hello gawk
hello gawk
hello gawk
hello gawk
hello gawk
hello gawk
hello gawk
hello gawk
hello gawk
hello gawk
hello gawk
hello gawk~]#awk -v test='hello gawk' 'BEGIN{print test}'hello gawk

~]#awk '{test="hello gawk";print test}'


~]#awk -v test='hello gawk' 'BEGIN{print test}'

hello gawk

三、printf命令

        格式化输出:print FORMAT,item1,item2,...item会显示在FORMAT事先准备的格式中

        (1)FORMAT必须给出

        (2)不会自动换行,需要显式给出行号控制符,\n

       (3)FORMAT中需要分别为后面的每个item指定一个格式化符号

格式符:

    %c: 显示字符的ASCII码;

    %d, %i: 显示十进制整数;

    %e, %E: 科学计数法数值显示;

    %f:显示为浮点数;

    %g, %G:以科学计数法或浮点形式显示数值;

    %s:显示字符串;

    %u:无符号整数;

    %%: 显示%自身;

awk -F: '{print $1}' /etc/passwdawk -F: '{printf "%s\n",$1}' /etc/passwd 显示用户名,一行一个,不加%s就会乱成一坨awk -F: '{printf "Username:%s, UID:%d\n,"$1,$3}' /etc/passwd

修饰符:

    #[.#]: 第一个数字控制显示的宽度,第二个字符表示小数点之后的精度

       例: %3.1f

awk -F: '{printf "Username:%15s,"}' /etc/passwd 默认右对齐

    -:左对齐

    +:显示数值的符号  

四、操作符

    算数操作符

        x+y,x-y, x*y, x/y, x^y,

        -x

        +x:转换为数值

    字符串操作符:没有符号的操作符,字符串连接

    赋值操作符:

        =, +=, -=, *=, /=, %=, ^= ,++, --

    比较操作符:

>, >=, <, <=, !=, ==

    模式匹配符:

        ~:是否匹配

        !~:是否不匹配

    逻辑操作符:

        &&

        ||

        

    函数调用:

        function_name(argu1,argu2,.....)

    条件表达式:

        selector?if-true-expression:if-false-expression

# awk -F: '{$3>=1000?usertype="Common User":usertype="Sysadmin or SysUser";printf "%15s:%-s\n",$1,usertype}' /etc/passwd

五、PATTREN:

        类似于sed中的地址定界

    (1)empty:空模式,匹配每一行

    (2)/regular expression/:仅处理能够被此处模式匹配到的行

awk '/^UUID/{print $1}' /etc/fstab 取UUID开头的行awk '!/^UUID/{print $1}' /etc/fstab 上题取反

        (3)relational expression:关系表达式,结果有真有假;结果为真才会被处理;真;结果为非0值,非空字符串

awk -F: '$NF=="/bin/bash"{print $1,$NF}' /etc/passwd 显示最后一个字段为/bin/bash的行的第一个字段和最后一个字段awk -F: '$NF~/bash$/{print $1,$NF}' /etc/passwd   "~"的意思是是否匹配

     (4)line ranges 行范围

         注意:不支持直接给出数字的格式

awk -F: '/^root/,/^myuser/{print $1}' /etc/passwd  从第一次匹配到root到第一次匹配到myuser结束中间所有的用户名都显示出来awk -F: '(NR>=2&&NR<=10){print $1}' /etc/passwd 打印行号大于2和小于10的行的第一个字段

     (5)BEGIN/END模式

        BEGIN{program段}:尽在开始处理文件的中的文本之前执行一次

        END{}:尽在文本处理完成之后执行一次

awk -F: 'BEGIN{print "    username    uid    \n-----------"}'程序开始之前执行一次awk -F: 'BEGIN{print "    username    uid    \n-----------"}END{print $1,$3}' /etc/passwd   程序结束之前执行一次

六、常用的action

    (1)Expression:表达式语句

    (2)控制语句:if while    

    (3)组合语句:

    (4)输入语句:

    (5)输出语句:

七、控制语句

        在一行当中实现循环语句的使用

    if(condition) {statments}

    if(condition) {statments} else {statments}

    while(conditon) {statments}

    do {statments} while(condition)

    for(expr1;expr2;expr3) {statements}

    break

    continue

    delete array[index]

    delete array

    exit

    { statements }

7.1 if-else

    语法:if(condition) statement [else statement]

~]#awk -F: '{if($3>=1000) print $1,$3}' /etc/passwd UID大于等于1000就显示用户名和id号 普通用户~]#awk -F: '{if($3>=1000) printf "Common user: %3\n",$1 else {printf "root or Sysuser:%3\n",$1}}' /etc/passwd

使用场景:对awk取得的整行或某个字段做条件判断

awk -F: '{if($NF=="/bin/bash") print $1}' /etc/passwd
字段数大于5就显示出来,否则不予以显示awk '{if(NF>5) print $0}' /etc/fstab
df -h | awk -F[%] '/^\/dev/{print $1}' | awk '{if($NF>=20) print $1}'如果一个设备使比例大于80就取出来

7.2 while循环

    语法:while(condition) statement

        条件“真”进入循环;条件“假”退出循环

        使用场景:对一行内的多个字段逐一类似处理时使用;对数组中的各个元素注意处理时使用;

awk '/^[[:space:]]*linux16/{(i=1;while(i<=NF) {print $i,length($i); i++}}' /etc/grub2.cfg显示文件中每一个符合条件的行(含有linux16),行内的每一个字段,字段的本身和字符个数。length():计算字符个数若我现在只想显示大于等于7的字段awk '/^[[:space:]]*linux16/{(i=1;while(i<=NF) {print $i,length($i); i++}}' /etc/grub2.cfg

7.3 do-while循环

    语法:do statement while(condition)

    意义:至少执行一次

7.4 for循环

    语法:for(expr1;pxpr2;pxpr3) statement

    特殊用法:

         能够遍历数组中的元素:

         语法:for (var in array) {for-body}遍历数组的下标

    若要遍历数组中的每个元素,要使用for循环;

    for (var in array) {for-body}

awk '/^[[:space:]]*linux16/{for(i=1;i<=NF;i++) {print $i,length($1)}}' /etc/grub2.cfg

显示文件中每一个符合条件的行(含有linux16),行内的每一个字段,字段的本身和字符个数。

注意var会遍历array的每个索引


netstat -tan | awk '/^tcp\>/{state[$NF]++}END{for(i in state) { print i,state[i]}}'格式:state["LISTEN"]++      state["ESTABLISHEB"]++显示netstat -tan 每个TCP状态出现了多少次
awk '{ip[$1]++}END{for(i in ip) {print i,ip[i]}}' /var/log/httpd/access_log对每一个在我服务器上获取资源次数的ip地址做统计
awk '/^UUID/{fs[$3]++}END{for(i in fs) {print (i in fs) {print}}'   未完.....统计/etc/fstab文件中每个文件系统出现的次数
awk '{for(i=1;i<=NF;i++){count[$i]++}}END{for(i in count) }'    未完.....统计指定文件中每个单词出现的次数

7.5 switch语句

    (类似于case)

     语法:switch(expression) {case VALUE1 or /REGEXP/: statement; case VALUE2 or /REGEXP2/: statement; ...; default: statement}

   case是关键字后面可以是一个值,或者是一个模式  default 为默认分支

7.6 break和continue

  break [n]  退出n层循环

  continue 让当前循环提前结束,而进行下一轮

7.7 next

    提行结束对本行的处理,而直接进入下一行

awk -F: '{if($3%2!=0)} next; print $1,$3' /etc/passwdID号为偶数的用户名的显示出来

八、 array数组

关联数组:array[index-expression]

    index-expression:

          (1)可以使用任意字符串

          (2)如果某数组元素事先不存在,在引用时,awk会自动创建此元素,并将其值初始化为"空串":

         (3)若要判断数组中是否存在某元素,要使用"index in array"

       weekdays[mon]="monday"

awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";print weekdays["mon"]}'  字符串要使用双引号,不要乱用单引号awk 'BEGIN{weekdays["mon"]"Monday";weekdays["tue"]="Tuesday";for(i in weekdays) {print weekdays{i}}}'

九、函数

  9.1内置函数

      数值处理:

          rand():返回0和1之间一个随机数

awk 'BEGIN{print rand()}' 重复执行随机数不会变,可以调用第一次执行结果

      字符串处理:

          length([S]):返回指定字符串的长度

          sub(r,s,[t]):以r表示的模式来查找t所表示的字符中的匹配的内容,并将其第一次出现替换为s所表示的内容    

awk -F: '{print sub(o,O,$0)}' /etc/passwd找/etc/passwd 第一次匹配到o替换为O  有print表示是否替换成功 ,一般不用print

gsub(r,s,[t]):以r表示的模式来查找t所表示的字符中的匹配的内容,并将其所有出现均替换为s所表示的内容;


split(s,a[],r):以r为分隔符切割字符s,并将切割后的结果保存至a所表示的数组中

netstat -tan | awk '/^tcp\>/{split($5,ip,":");count[ip[1]]++}END{for (i in count) {print i,count[i]}}'统计每一个IP对我们主机建立了多少次连接