欢迎各位兄弟 发布技术文章

这里的技术是共享的

You are here

(马哥教育)awk入门(1) 有大用

grep: (搜索文本最合适)根据正则表达式找到条件的行,文本查找工具,它的速度是最好的

sed:Stream Editor,(编辑文本最合适)流处理器,流编辑器,对某一文件中的指定的文本进行逐行读取,而后对每一行进行相应的编辑的工具,它只处理模式空间,不处理原文件,在模式空间的处理过程当中,还有一个保留空间,我们可以通过对保留空间和模式空间的来回对换,并通过sed的各种命令来实现强大的编辑功能

awk:(生成格式化的报告工具及对文档内部的某些内容做一些复杂处理的话最合适)一个或多个文件逐行读入文本,但并不是直接处理的,将读入的文本先按空白(默认分割),分割完成以后,将分割的结果在awk的内部可以实现位置参数的变量直接引用,可以让我们自由的去处理每一个段或者某些个段,从某种意义上讲,它是一个格式化的报告生成工具,(grep,sed没有这种能力)  awk后来扩展到能够实现文本处理过滤,并且根据某种模式,只是对符合某些条件的文本进行匹配或者处理的一种工具

awk已经发展为一门独立的语言,awk自身内部还可以实现脚本编程的,支持实现条件判断,像if case这样的语句,支持循环(在一个命令内部实现循环),这个命令的功能非常强大,支持数组,支持各种内置的变量,这个命令像bash/shell一样,是种完整整的独立的语言,只不过这种语言通常是用来实现文本处理的语言而已.


AWK a.k.a. Aho,Kernighan and Weinberger 三个人名的首字母组合

上个世纪八十年代就已经出现了


new awk: nawk(new 新awk) (现在的awk命令大多数兼nawk)   (九十年代的时候,作为扩展)

linux上使用的awk 即不是awk也不是nawk,而是gawk (GUN awk ,,linux上实现的开源版本的实现)

大多数情况下,我们可以使用awk命令来取而代之,不用写成全称 gawk,因为大家都习惯使用awk这样的命令了



# awk [options] 'script' file1,file2,...

# awk [options] 'PATTERN { action }' file1,file2,...


PATTERN 任何基本的(通用的)正则表达式 我们都可以用


-F: (field separator ) 指定分隔符 ( -F: 表示 指定冒号作为分隔符)

             -F fs

                   --field-separator fs

                      Use fs for the input field separator (the value of the FS prede-fined variable).

                                


awk的输出

一,print

print的使用格式

    print item1,item2,...

要点:

1,各项目之间使用逗号隔开,而输出时则以空白字符(默认的分隔符是空白字符)分隔

2,输出的item可以为字符串或数值,当前记录的字段(如$1),变量或awk的表达式:数值会先转换为字符串,而后再输出

3,print命令后面的item可以省略,此时其功能相当于print $0,因此,如果想输出空白行,则需要使用 print ""

 

例子:

# awk 'BEGIN{ print "line one\nline two\nline three" }'

awf -F: '{ print $1,$2 }' /etc/passwd


内置变量

ORS: (output record separator) 输出的换行符

OFS:(out field separator) 输出的字段分割符,默认也是空白字符

FS:(field separator) 读入的字段分割符,默认是空白字符  (读入文件的段分割符的符号)

RS: (Record separator) 默认换行符

NR: (The number of input records(row)), 行数awk 命令所处理的记录数,如果有多个文件,这个数目会把处理的多个文件中行统一计数

NF:  (Number of Filed),当前行(记录)的field个数

FNR: (field number record(row)) 与NR不同的是,FNR用于记录正处理的行是当前这一文件中被总共处理的行数 当前行所在的这个文件的行数

ARGV:(argument varibale)数组,保存命令行本身这个字符串,如 awk '{print $0}' a.txt b.txt 这个命令中,ARGV[0]保存awk,ARGV[1]保存a.txt

ARGC:(argument count)awk命令的参数的个数


image.png



二,printf 

printf命令的使用格式:

printf format,item1,item2,...


要点:

1,其与print命令的最大不同是,printf必需要指定format(格式)

2,format用于指定后面的每个item的输出格式

3,printf语句不会自动打印换行符的: (如里需要换行换行,要使用\n)


format格式的指示符都以% (百分号)开头,后跟一个字符,如下:

%c:(character)显示字符(字母)的ACSII码;

%d,%i:( decimal integer)十进制整数

%e,%E: (比如10e-10等 就是指的这个e吧)科学计数法显示数值

%f:(float)显示浮点数

%g,%G:(e和f 中自动选择一个)以科学计数法的格式或浮点数的格式(awk会自动选择)显示数值        

              %g ,  %G

               Use %e or %f conversion, whichever is shorter, with nonsignifi-

               cant zeros suppressed.  The %G format uses %E instead of %e.

%s:(string)显示字符串

%u:(An unsigned decimal number)无符号整数       

                                                

                            [root@localhost ~]# echo "-1 2" | awk '{printf "%u %d\n", $1,$2}'   (%u 没看懂是什么意思 )

                            18446744073709551615 2

     

            

%%:(A single % character; no argument is converted)显示%(百分号)自身,用于转义


修饰符:(加在百分号%后面,指示符的前面)

N:显示宽度

-:左对齐 (默认是右对齐) 减号

+:显示数值符号(如1,显示+1(而不是1),-1的话就显示-1)             加号


例子

# awk -F '{ printf "%-15s %i\n",$1,$3}'


三 输出重定向

print items > output-file            覆盖重定向

print items >> output-file          追加重定向

print items | command               管道,输出给另一个命令进行处理


特殊文件描述符

/dev/stdin:标准输入

/dev/sdtout:标准输出

/dev/stderr:错误输出

/dev/fd/N:某特定文件描述符,如 /dev/stdin就相当于/dev/fd/0:


例子:

# awk -F: '{printf "%-15s %i\n",$1,$3 > "/dev/sdterr" }' /etc/passwd


 "%-15 %i\n"   这里format格式必需用双引号引起来

 "/dev/sdterr"  每一个文件描述符必需用双引号引起来

image.png



awk的操作符

一,算术操作符:


单目 操作符

-x:负值 

+x:转换为数值


双目操作符

x^y:次方

x**y:次方

x*y:乘法

x/y:除法

x+y:加法

x-y:减法

x%y:求模取余取模


二字符串操作符

只有一个,而且不用写出来,用于实现字符串连接


三赋值操作符

+

+=

-=

*=

/=

%=

^=

**=


++

--

需要注意的是,如果某模式为(有)=号(等于号等号),此时使用/=/可能会有语法错误,应以/[=]/替代



image.png

四 布尔值

awk中,任何非0值或非空字符串都为真,反之就为假,与bash相反吧

(bash中,0为真,1-255为假)


五,比较操作符

x < y              True if x is less than y.

x <= y            True if x is less than or equal to  y.

x > y               True if x is great than y.

x >= y             True if x is great thanor equal to  y.

x == y             True if x is equal  to y.

x != y               True if x is not equal  to y.

x ~ y                True if the string x matches the regexp denoted(表示,代表;指代;预示;意思是) by y. (x是字符串,y是正则表达式)

x !~ y                True if the string x does not matches the regexp denoted

subscript in array         True if the array array has an element with the subscript subscript


六,表达式间的逻辑关系符

&&

||


七,条件表达式    (三元运算符(选择操作符)问号?冒号:)

selector?if-true-exp:if-false=exp

A=3

B=4

$A>$B? echo $A: echo $B


八, 函数调用            (awk有很多内置函数)

function_name (para1,para2)


image.png


awk的模式

awk 'program' input-file1 input-file2 ...

其中的program为:

pattern { action }

pattern { action }

...


常见的模式类型:

1,Regexp:正则表达式,格式为 /regular expression/

2,expression:表达式,其值非0或为非空字符串时满足条件,如: $1 ~ /foo/ 或 $1 == "megedu" ,用运算符~(匹配)和~!(不匹配)

3,Ranges: 指定的匹配范围,格式为pat1,pat2  (类似于sed '1,3' 从第一行到第三行, 而且也支持  /bash/,/awk/ 第一次匹配到bash的行开始,到第一次匹配到awk的行结束,的中间的所有行)

4,BEGIN/END:特殊模式,仅在awk命令执行前运行一次或结束前运行一次 (在真正的action之前 或 action之后执行一次,仅执行一次)

5,Empty(空模式):匹配任意输入行  就是不指任意模式


常见的Action有:

1, Expressions:

2, Control statements

3, Compound statements

4, Input statements

5, Output statements


image.png



/正则表达式/: 使用通配符的扩展集

关系表达式:可以用下面运算符表中的关系运算符进行操作,可以是字符串或数字的比较,如 $2>$1选择第二个字段比第一个字段长的行

模式匹配表达式:

模式,模式:指定一个行的范围,该语法不能包括BEGIN和END模式  (BEGIN,AND不能与其它的pattern混用吧,任何两个pattern都不能混用吧?)

BEGIN:让用户指定在第一条输入记录被处理之前所发生的动作,通常可在这里设置全局变量

END:让用户在最后一条输入记录被读取之后发生的动作

image.png



action 就是任何 awk执行的内部语句,可以是赋值语句,可以是命令,可以是函数调用,反正任何经常使用的语句在这里都可以用

控制语句:  

1, if-else

语法:if (condition) {then-body} [ else { else-body } ]                   

 then-body一般要用花括号括起来吧  if 后面的语句如果只执行一行语句,可以不用花括号括起来

例子       ("%-15s: %s\n" ,此时各个段的分隔符就是号了)    

awk -F: '{if ($1=="root") print $1,"Admin";else print $1,"Common User"}' /etc/passwd

awk -F: '{if ($1=="root") printf "%-15s: %s\n", $1,"Admin";else printf  "%-15s: %s\n", $1,"Common User"}' /etc/passwd

awk -F: -v sum=0 '{if ($3>=500) sum++}END{print sum}' /etc/passwd



2,while

语法 while (condition) {statement1;statement2;...}


3,do-while

语法 do {statement1;statement2;...}  while (condition) 


4, for

语法: for ( varible assignment; condition;iteration process) {statement1;statement2;...}


5,case

语法 switch (expression) { case VALUE or /REGEXP/: statement1;statement2;...default  statement1;...}



6, break 和 continue

常用于循环或case语句中


7, next

提前结束对本行文本的处理,并接着处理下一行

image.png




image.png

image.png


[root@localhost ~]# vim a.txt

image.png


[root@localhost ~]# awk '{print $1}' a.txt            (print 命令显示处理后的内容)  ($1表示分割后的第一个字段)

image.png

显示的命令 一个是 print 另一个是printf(可以实现格式化的输出,可以自己控制输出的字段宽度等各种格式)



[root@localhost ~]# df -h

文件系统              容量  已用 可用 已用% 挂载点

/dev/mapper/VolGroup00-LogVol00

                      113G  2.9G  104G   3% /

/dev/sda1              99M   13M   81M  14% /boot

tmpfs                 501M     0  501M   0% /dev/shm

.host:/               311G  227G   84G  73% /mnt/hgfs

[root@localhost ~]# df -h | awk '{print $1}'

文件系统

/dev/mapper/VolGroup00-LogVol00

113G

/dev/sda1

tmpfs

.host:/


[root@localhost ~]# df -hP

文件系统              容量  已用 可用 已用% 挂载点

/dev/mapper/VolGroup00-LogVol00  113G  2.9G  104G   3% /

/dev/sda1              99M   13M   81M  14% /boot

tmpfs                 501M     0  501M   0% /dev/shm

.host:/               311G  227G   84G  73% /mnt/hgfs

[root@localhost ~]# df -hP | awk '{print $1}'

文件系统

/dev/mapper/VolGroup00-LogVol00

/dev/sda1

tmpfs

.host:/

[root@localhost ~]#

[root@localhost ~]# awk '{print $1}' /etc/passwd

image.png


[root@localhost ~]# awk -F: '{print $1}' /etc/passwd        (冒号可以与-F连在一起,也可以与-F中间留空格)

image.png



[root@localhost ~]# awk -F: '{print $1,$7}' /etc/passwd                           $7表示第7个字段

image.png




[root@localhost ~]# awk -F: '{print NF}' /etc/passwd

image.png

[root@localhost ~]# awk -F: '{print $NF}' /etc/passwd

image.png


[root@localhost ~]# cat a.txt

welcome to redhat linux.

how are you?

[root@localhost ~]#


[root@localhost ~]# awk '{print $NF}' a.txt

linux.

you?

[root@localhost ~]#


[root@localhost ~]# awk -F: '{print $(NF-1)}' /etc/passwd        打印出倒数第二个字段(NF-1)

image.png



[root@localhost ~]# awk -v FS=: '{print $(NF)}' /etc/passwd   (-v 表示声时一个变量var,variable) (FS=: 指定分割符的符号为冒号)

image.png






[root@localhost ~]# awk '{print $NF}' a.txt

linux.

you?

[root@localhost ~]#

[root@localhost ~]# awk '{print $1 $2}' a.txt    (如果$1 与 $2用空格分开,awk以为是把$1和$2连接起来显示的)

welcometo

howare

[root@localhost ~]#


[root@localhost ~]# awk '{print $1,$2}' a.txt   (如果$1 与 $2用逗号分开,awk才把$1和$2用分隔符隔开(默认的输出段分隔符也是空格)来显示的)

welcome to

how are

[root@localhost ~]#


[root@localhost ~]# awk -v OFS=: '{print $1,$2}' a.txt  (OFS就是输出的字符分隔符)

welcome:to

how:are


[root@localhost ~]# awk '{printf "%s,%s", $1,$2}' a.txt   


[root@localhost ~]#  awk '{printf "%s,%s", $1,$2}' a.txt    (看到了吗 没有\n 此时不换行)

welcome,tohow,are1,2-1,-2


[root@localhost ~]# awk '{printf "%10s,%s", $1,$2}' a.txt   (%10s,%s 第一个字段10个字符,第二个字段默认的字符,默认不换行,默认右对齐)

   welcome,to       how,are[root@localhost ~]# 



[root@localhost ~]# awk '{printf "%10s,%s\n", $1,$2}' a.txt    (\n表示换行)

   welcome,to

       how,are


[root@localhost ~]# awk '{printf "%-10s,%s\n", $1,$2}' a.txt       (减号-表示左对齐)

welcome   ,to

how       ,are

[root@localhost ~]#


[root@localhost ~]# awk '{printf "%10-s,%s\n", $1,$2}' a.txt        (%-10s 与 %10-s 是一样的,修饰符在百分号后,指示符前面)

welcome   ,to

how       ,are


[root@localhost ~]# awk '{printf "%-10s%s\n", $1,$2}' a.txt        (格式符号之间 是不需要任何符号的,把上面的%-10s,%s\n 里面的逗号去掉)(这里$1匹配第一个百分号,$2匹配第二个百分号)

welcome   to

how       are

[root@localhost ~]# awk '{printf "%-10s %s\n", $1,$2}' a.txt    (当然  "%-10s %s\n" 中间可以用空格隔开的,也可以不用空格隔开"%-10s%s\n",效果是一样的)

welcome    to

how        are


[root@localhost ~]# awk 'BEGIN{print "a" "b"}'                (这里输出字符串,a和b要用双引号)

ab



[root@localhost ~]# awk -F: '$1 ~ /^root/ {print $3,$4,$NF}' /etc/passwd  ($1如果以root开头,那么就打印出$3,$4,$NF)

0 0 /bin/bash

[root@localhost ~]# awk -F: '$1 ~ /^root/{print $3,$4,$NF}' /etc/passwd    ($1如果以root开头,那么就打印出$3,$4,$NF)

0 0 /bin/bash

[root@localhost ~]#

[root@localhost ~]# awk -F: '$1 !~ /^root/{print $3,$4,$NF}' /etc/passwd   ($1如果以不root开头,那么就打印出$3,$4,$NF)

image.png


[root@localhost ~]# awk -F: '/bash/{print $0}' /etc/passwd   包含 bash字符串的 整行都显示出来 $0表示所有 美元符0 美元符零

root:x:0:0:root:/root:/bin/bash



[root@localhost ~]# awk -F: '/bash/{print $1}' /etc/passwd      包含 bash字符串的行中 第一段显示出来

root


[root@localhost ~]# awk -F: '$3>=500{print $1}' /etc/passwd  (当第三段大于等于500的时候,把第一段显示出来)

nfsnobody



[root@localhost ~]# awk -F: '$3 >= 500{print $1,$3}' /etc/passwd  (当第三段大于等于500的时候,把第一段第三段显示出来)

nfsnobody 65534

[root@localhost ~]#



[root@localhost ~]# awk -F: '$3 >= 500{printf "%-15s %s\n", $1,$3}' /etc/passwd  (当第三段大于等于500的时候,把第一段第三段显示出来, 第一段为左对齐,15个字符的长度)

nfsnobody       65534



[root@localhost ~]# awk -F: '$3 >= 500{print "Username            UID";printf "%-15s %s\n", $1,$3}' /etc/passwd    (此时每一行都加上了头部,因为每读一行awk都要执行一次)

Username UID

nfsnobody       65534

Username UID

shipingzhong    500

Username UID

tom             501

[root@localhost ~]#


[root@localhost ~]# awk -F: 'BEGIN{print "Username     UID"}$3 >= 500{printf "%-15s %s\n", $1,$3}' /etc/passwd 

(这里BEGIN是在真正显示用户名和ID号之前先打印首部 Username UID)

Username     UID

nfsnobody       65534

shipingzhong    500

tom             501


[root@localhost ~]# awk -F: 'BEGIN{print "Username UID"}{printf "%-15s %s\n", $1,$3}' /etc/passwd  (这里BEGIN是在真正显示用户名和ID号之前先打印首部 Username UID)

image.png



[root@localhost ~]# awk -F: 'BEGIN{print "Username         UID"}{printf "%-15s %s\n", $1,$3}END{print "Over"}' /etc/passwd

 (这里END是在真正显示用户名和ID号之后打印尾部部 Over)

image.pngimage.png

image.png




[root@localhost ~]# awk 'BEGIN{print "a" "b"}'        (不对文件进行处理,直接显一示个内容而已 )(没有action这里只是不有$1吧,或者不把  BEGIN后面的当作action吧,不用对任何文件进行任何处理  )

ab

[root@localhost ~]#





[root@localhost ~]# awk -F: '{print $1}' /etc/passwd            (使用冒号分隔符)(第一种方法)

image.png

[root@localhost ~]# awk -v FS=: '{print $1}' /etc/passwd          (使用冒号分隔符)(第二种方法)

image.png



[root@localhost ~]# awk 'BEGIN{FS=":"}{print $1}' /etc/passwd         (使用冒号分隔符)(第三种方法)

BEGIN段中进行变量赋值,BEGIN段中明确说明我们有个变量叫FS,让这个变量等于冒号:,在BIGIN段中赋值的时候我们需要使用引用引起来

image.png




[root@localhost ~]# awk -F: '{if($3==0) print $1,"Admin"; else print $1,"Common user"}' /etc/passwd

image.png






普通分类: