LINUX学习—AWK(LINUX三剑客)

awk是一个报告生成器,拥有强大的文本格式化能力;
也是一种文本处理工具,但其主要功能是从处理文件中按照输入的信息格式后显示的工具
awk是一种编程语言,支持条件判断、数组、循环等功能。用于在linux/unix下对文本和数据进行处理。数据可以来自标准输入(stdin)、一个或多个文件,或其它命令的输出。它支持用户自定义函数和动态正则表达式等先进功能,是linux/unix下的一个强大编程工具。它在命令行中使用,但更多是作为脚本来使用。awk有很多内建的功能,比如数组、函数等,这是它和C语言的相同之处,灵活性是awk最大的优势。
LINUX三剑客特长
grep更适合单纯的查找或匹配文本 grep ‘pattern’ input-file…
sed更适合编辑匹配到的文本 sed [option] ‘AddressCommand’ file…
awk更适合格式化文本,对文本进行较复杂格式处理 awk [option] ‘pattern {action}’ file

awk基本语法

awk [options] ‘script’ file1 file2
awk [options] ‘pattern { action} pattern {action}…’ file

一、OPTION (常用选项)
-F:分隔符  
-v var=value:赋值一个用户自定义变量,将外部变量传递给awk   
二、PATTERN(模式)

awk [option] ‘Pattern {Action}’ file1 file2
除了BEGIN 和END模式(不需要去读取文件的内容)外, awk中还有其他pattern,如:

    1. 空模式,就是平时不添加任何模式参数的情况,即会匹配文本中的每一行,对于满足条件的行执行相应的动作;如 awk '{print $0}' test  
    2. 关系运算模式; 如 awk 'NF==5 {print $0}' test  
        关系运算符有:  
            <:小于  
            <=:小于等于  
            ==:等于  
            !=:不等于  
            >=:大于等于  
            >:大于  
            ~:与对应的正则匹配则为真  
            !~: 与对应的正则不匹配则为真  
    3. 正则模式:  
        正则表达式通常被用来检索、替换那些符合某个模式(规则)的文本  
        awk '/正则表达式/{print $0}' /etc/passwd  
        当正则表达式中已经存在/ 号时,需要使用转义符对其进行转义;  
            如awk'/\/bin\/bash$/{print $0}' /etc/passwd  
            除此之外,awk在使用正则模式时,使用到的正则用法属于“扩展正则表达式”  
            当使用{x, y}这种次数匹配的正则表达式时,需要配合--posix或--re-interval选项,否则会报错;  
    4. 行范围模式:pat1,pat2  
        注意相邻的正则表达式用逗号隔开,且都是以第一次匹配到的行为为准;  
        awk '/正则1/,/正则2/{动作}’ /some/file   
        这种方法还可以用多个关系表达式来达到效果:但相互之间用&&连接 如: awk 'NR>=3 && NR<=6 {print $0}' file  
三、ACTION

1、print
print的使用格式:
print item1, item2,…
要点:
1、各项目之间使用逗号隔开,而输出时则以空白字符分隔
2、输出的item可以为字符串或数值、当前记录的字段(如 1 ) a w k 3 p r i n t i t e m p r i n t 0,因此,如果想输出空白行,则需使用print“”;
例:
#awk ‘BEGIN {print “line one\n line two\n line three”}’ (文本字符串必须用双引号,不能用单引号)
awk -F: ‘{print 1 , 2}’ /etc/passwd
awk变量
常用内置变量
- n n n 1 n 2 0 这个变量包含执行过程中当前行的文本内容;
- FS 输入字段分隔符(默认是任何空格); FS=”:” ==-F:
- OFS 输出字段分隔符,(默认值是一个空格);
- RS 输入记录分隔符(输入换行符),指定输入时的换行符,默认换行;
- ORS 输出记录分隔符(输出换行符),输出时用指定符号代替换行符,默认换行;
- FS/OFS/RS/ORS使用时都要用-v选项
– 例:查看当前系统所有用户名:
– awk -F: ‘{print $1}’ /etc/passwd
- NF 表示字段数,在执行过程中对应于当前的字段数(即当前行被分割成了几列),字段数量;
- NR 表示记录数,当前处理的文本行的行号;
- FNR 同NR,各文件分别计数的行号;
- NF:一条记录的字段数; 是
- FILENAME 当前输入文件的名;
- ARGC 命令行参数的个数;
- ARGV 包含命令行参数的数组,保存的是命令行所给定的各参数;
这几个内置变量和FS/OFS RS/ORS不同的是,它们是在大括号内使用,且可以直接使用,不需要用-v参数;

如果没有以上内置变量,可以自己定义变量:
方法一: -v varname=value变量名区分字符大小写; 如awk -v myVar=”testVar” ‘BEGIN{print myVar}’
方法二: 在action中直接定义。 awk ‘BEGIN{myvar=”ttt”;print myvar}’ 两个独立的语句,语句之间注意中间隔开需要使用分号,逗号会报错
这种同样也可以一次性定义多个变量;

这四个内置变量在使用的时候需要使用-v参数(用于赋值于一个用户定义的变量)
在action中的如果有多个语句,语句间用分号隔开;

2. printf
print只能实现简单的文本输出功能,并不能对文本格式进行改变,如果想要改变文本的格式,则需要awk中的另一个动作printf;
1) 在awk中使用printf时,指定的“格式”与列之间需要用逗号隔开,而使用printf命令时,指定的格式与传入的文本不需要用逗号隔开
printf "%s \n" teststring
awk '{printf "%s\n", $1}' test
$0表示整行

2) 另外,在awk中,格式替换符的数量必须与传入的参数的数量是相同的,即格式替换符必须与需要格式化的参数一一对应,但printf函数单独使用时不需要,它可以逐个读取并打印在终端
3)使用printf动作输出的文本不会换行,如果需要换行,可以在对应的“格式替换符”后加入“\n”进行转义;
printf命令详解
\n : 转义符;
printf命令语法
printf format, item1, item2… (printf “指定的格式” “文本1”“文本2”“文本3”…)
printf “%s\n” abc def ghi jkl mno =echo/printf “abc \ndef \nghi \nmno” 这就是格式替换符参数的使用方法
要点:
1.同print最大的不同是需要指定format
2.format不会自动打印换行符 \n
3.format需要使用双引号包括
4.format和C语言的格式化输出很类似

3. 格式化替换符有(都是用百分号%表示)
%s 代替传入的参数,并转换为字符串类型;(注意前面都是%)
%f 浮点格式;
%b 相对应的参数中包含转义字符时,可以使用此替换符进行替换,对应的转义字符会被转义;
%c ASCII字符。显示相对参数的第一个字符;
%d %i 十进制整数;
%o 不带正负号的八进制值
%u 不带正负号的十进制值
%x 不带正负号的十六进制值,使用a至f表示10至15
%X 不带正负号的十六进制值,使用A至F表示10至15
%%表示“%”本身

4. 转义字符(都是用\表示)
\a 警告字符,通常为ASCII的BEL字符
\b 后退
\c 抑制(不显示)输出结果中任何结尾的换行字符(只在%b格式指示符控制下的参数字符串中有效),而且,任何留在参数里的字符、任何接下来的参数以及任何留在格式字符串中的字符,都被忽略;
\f 换页(formfeed)
\n 换行
\r 回车
\t 水平制表符
\v 垂直制表符
\ 一个字面上的反斜杠字符,即“\”本身
\ddd表示1到3位数八进制值的字符,仅在格式字符串中有效
\0ddd表示1到3位的八进制值字符

注意:当格式替换符有多个时,则参数依次传递到格式替换符中,即第一个参数对应第一个替换符,后一个参数对应第二个替换符,当本次格式化操作完成以后,则传入下一步参数;
5. 修饰符
“数字”:如%7s 这里的数字7对应的输出宽度为7个字符宽,如果对应的输出不足7个字符,则用空格补全,如果输出长度超过7个字符,超出部分也会显示;
此外数字修饰符还可以表示数字字符的宽度如 %s %12d \n,也可以表示数字小数点的格式 如%10s %-12.3f\n 这里12.3表示替换符“%f”输出宽度为12个字符,同时数字后面保留3位小数点;
“+” 表示如果数字为正,则显示其前面的+号;
“-” 表示左对齐,不加这个符号表示右对齐;

  1. 输出重定向
    使用格式:
    print items>outputfile
    print items>>outfile
    print items |command
    注意:outputfile与command需要使用双引号包括
    例: awk -F: ‘{print 1 , 3|”sort -k1”}’ etc/passwd

awk [option] ‘pattern {action}’ file
{action} 可以分为{ }和action,前者相当于“组合语句”类型动作,后者为“输出语句”类型动作
awk '{print $1} {print $2}' test ==awk '{print $1; print $2}' test
后者需要用分号分开

四、控制语句在awk中的应用

1:条件判断语句
- if 条件判断语句
语法:if (条件) {语句1;语句2;….}
例: awk ‘{if (NR==1) {print $0} }’ test5
需要注意的是,当print动作只有一个时,大括号可以省略,即可以写成
awk '{ if "(NR==1) print $0}' test
但当print动作有多个时,大括号不能省略,否则会报错,
awk '{if (NR==1) {print $1, $2}}' test
- “if…else”语句
“if…else”语法: if(条件) {语句1; 语句2;…} else {语句1; 语句2;…}
awk -F":" '{if ($3<500) {print $,"系统用户"} else {print $1, "普通用户"}}' /etc/passwd
- “if…else if …else”语句
“if…else if …else”语法: if(条件1) {语句1; 语句2;…} else if (条件2) {语句1; 语句2;…}
awk 'NR !=1' {if ($2<=30) {print $1, "年轻人"} else if ($2>=30 && $2<=50) {print $1, "中年人"} else {print $1, "老年人"}}' test7

* 2. for 循环语句 *
- for 循环语法格式1
for (初始化;布尔表达式;更新){//代码语句}
例:awk ‘BEGIN {for ( i=1; i<=6; i++) {print i}}’
- for 循环语法格式2
for (变量in数组){//代码语句}
3. while循环
- while 循环语法(当while对应的条件满足时,则执行对应的语句,语句执行完成后,对条件进行修改。)
while (布尔表达式){//代码语句}
例: awk ‘BEGIN {i=1; while (i<=5) {print i; i++}}’ 自定义变量的两种表达方式
或 awk -v i=1 ‘BEGIN {while (i<=5) {print i; i++}}’
- do…while循环语法 (它与while循环的不同之处在于,while循环只有当满足条件时才会执行对应的语句,而do…while则是无论是否满足条件,都会先执行一遍do对应的代码,然后再判断是否满足while中对应的条件,满足条件,则执行do对应的代码,如果不满足条件,则不再执行do对应的代码。)
do {//代码语句} while (条件)
例:awk ‘BEGIN { i=1; do {print “test”; i++} while (i<1)}’打印一个test;
例2:awk ‘BEGIN {do {print “test”; i++} while (i<=5)}’ 打印6行test
4. continue 语句: 跳出”当前“循环
5. break语句:跳出“整个”循环

    例:   
        awk 'BEGIN{for (i=0; i<=6; i++) {print i}}'  
        0
        1
        2
        3
        4
        5
        6
        awk 'BEGIN{ for (i=0; i<=6; i++){if (i==3){continue}; print i}}'  
        0
        1
        2
        4
        5
        6
        awk 'BEGIN{for (i=0;i<=6;i++) {if (i==3){break}; print i}}'  
        0
        1
        2

6.exit语句:表示不再执行awk命令,相当于退出了当前的awk命令当时当exit和END模式同时使用时,表示exit语句之后的所有动作都不执行,END模式除外;
例: awk ‘BEGIN{print “start”; exit} {print $0} END{print “over”}’打印出来的结果是(start和over)
7.next语句:next 与continue有点类似,continue针对的是循环而已,它的作用主要是结束本次循环,而next 是针对逐行处理而言
值得注意的是,exit命令出现后会终止其后的所以语句,有点类似break awk ‘BEGIN{ for (i=0; i<=6; i++) { if (i==3) {break}; print i}}’
awk -F: ‘{if (NR%2==0} print NR; esle next}’ /etc/passwd #代表只显示文件/etc/passwd偶数行的用户名;

五、内置函数

1:算数函数
1.1 rand函数、srand函数(初始化函数)、int函数。 (相当于awk语法中的action)
rand函数生成随机数,一般使用时需要配合strand函数一起使用,否则rand函数返回的值将一直不变:
awak ‘BEGIN {print rand( )}’
awak ‘BEGIN{srand ( ); print rand ( )}’
这两个直接生成的都是小数,要变成整数需要rand前100,然后在用int函数取整数,即:awk ‘BEGIN{srand ( ); print int (100 rand( ))}’
2:字符串函数
- gsub函数: 替换指定范围内的所有符合条件的字符,全局替换;

    cat test11  
    Allen Phillips  (14)
    Green Lee (9)
    Willim Ken Allen (18)
    awk  '{gsub("l", "L", $1); print $0}' test11  
    返回: ALLen Phillips \n(表示换行) Green Lee \n WiLLim Ken Allen 
     awk '{sub("l", "L", $1); print $0}' test11
     返回: ALlen Phillips \n Green Lee \n WiLlim Ken Allen.
  • sub函数: 替换指定范围内的单次替换,只替换第一次匹配到的字符;
  • length 函数:获取指定字符串的长度;

    awk '{for (i=1; i<=NF;i++) {print $i, length($i)}}' test11  
    返回:14、9、18.  
    
  • index函数:获取到指定字符位于整个字符串中的位置;
    awk ‘{print index ($0, “Lee”)}’ test11
    返回0 7 0
    使用index函数在整个文件查找Lee所在行,不存在,则返回值0,表示当前行不存在Lee,如找到,则返回Lee 所在行的字符位置;
  • split (string, array [, fieldseq [, seps]])
    将string按照分隔符fieldseq进行分割,保存在以array为名的数组中,数组下标从1开始计数。(将指定字符串按照指定的分割符切割,将切割后的每一段赋值到数组的元素中,从而动态创建数组)
    awk -F: ‘{if (NR>3) next; split ($NF, bash_dir,”/”); for (str in bash_dir) {print str, bash_dir[str]}’
    if语句只处理前3行,split会将每一行最后的bash地址以斜杠分割并存储于数组bash_dir中,后面的for用于打印
    awk -v ts=”大娃:二娃:三娃” ‘BEGIN{split (ts, huluwa, “:”); for (i in huluwa){print huluwa[i]}}’
    返回 大娃 \n 二娃 \n 三\n2.6
  • substr (string, start [, length]):截取字符串string的子串,从start开始,取length长度;若未指定长度,则返回从起始位置到字符末尾的子字符串。
    如:echo “123”|awk ‘{print substr ($0,1,1)}’ 返回1
  • system(command)
    执行系统命令,并将结果返回至awk命令
    如:awk -F: ‘BEGIN{system (“date”)}’ 执行date命令,输出到屏幕上
  • systime ( )与 ( )
    1. systime ( )取得当前系统时间的时间戳
      awk ‘BEGIN{now = systime ( ); print now }’
    2. strfime ( )将时间戳格式化为时间
      awk ‘BEGIN{now=strftime (“%D”, systime( )); print now}’
  • tolower (s)
    将字符串s所有字母转为小写
  • toupper(s)
    将字符串s所有字母转为大写

**3. 用户自定义函数  **
使用function关键字。格式如下:  
function F_name([varible]) {statement} 可以使用return语句返回,格式为return valuw  
将自定义函数保存为awk脚本,配合-f参数使用。   

六、三元操作符

awk三元运算符 与打印奇偶行
1. 三元运算符
1. 第1种使用方式:条件?结果1:结果2 (表示如果条件成立,则返回结果1,反之则返回结果2)
可以用来替换if..else..语句
如:awk -F: ‘{if ( 3 < 500 ) u s e r t y p e =" e l s e u s e r t y p e =" " ; p r i n t 1,usertype}’ /etc/passwd
或:awk -F:’ { 3 < 500 ? " u s e r t y p e =" u s e r t y p e =" " ; p r i n t 1,usertype}’ /etc/passwd
2. 第2种使用方式: 表达式1?表达式2:表达式3 (如果表达式1为真,则执行表达式2,如果表达式1为假,则执行表达式3)
awk -F: ‘{$3<500?a++:b++} END{print a,b}’ /etc/passwd

2. 打印奇偶行
两个知识点:
1、在awk中,如果省略了模式对于的动作,当前行满足模式时,默认动作为打印整行,即{print $0}.
2、 在awk中, 0或者空字符串表示“假”,非0值或非空字符串值表示“真”。
打印奇数行:awk ‘i=!i’ file
当awk开始处理第一行时,变量i被初始化,变量i在被初始化时,值为“空”,由于在awk中,数字0或者“空字符串”表示假,所以可以认为模式为假,但i被直接取反,对假取反后的值为真,将取反的值又赋予了变量i,此时i变量值为真,所以awk在处理第一行文本时,变量i的值被赋值为真,模式成立则需要执行对应的动作,而又省略了动作,所以默认动作为“{print $0}”,因此第一行被打印了。当第一行文本处理完毕后,awk开始处理第二行文本,此时i为真,但取反后为假,所以第二行没有被输出,依次类推,最终只打印了奇数行。
打印偶数行: awk ‘!(i=!i)’ file

或者的符号用 [A|B] 表示A或B
例: awk -F: ‘{if ( 1   / [ C | E ] / ) p r i n t 1}’ b.txt 表示打印b.txt文件中第一行中已C或E开头的名字;

七、数组

数组

反斜杠将命令进行换行,是命令可读性更强;(好像并没有什么卵用,肉测)
由于数组中存在空字符串,所以不能单纯的用空格带判断数组元素是否为空,应用“if (下标in数组名)”来判断数组中是否存在对应的元素。用“!”对条件进行取反
例:awk ‘BEGIN{huluwa[0]=”大娃”; huluwa[1]=”二娃”; huluwa[2]=”三娃”; huluwa[3]=”四娃”; huluwa[4]=”“; if (5 in huluwa) {print “数组中第6个元素存在即可看到这句话”}}’
awk ‘BEGIN{huluwa[0]=”大娃”; huluwa[1]=”二娃”; huluwa[2]=”三娃”; huluwa[3]=”四娃”; huluwa[4]=”“; if (!(5 in huluwa)) {print “数组中第6个元素存在即可看到这句话”}}’
在awk中,数组的下标不仅可以为“数字“,还可以为”任意字符串”

delete可以用来删除数组中的元素

当要想打印数组中所有元素时,需要使用for循环语法才能够遍历输出数组中的元素
for 循环语法格式1:
for (初始化;布尔表达式;更新) {//代码语句} 这种语法只能输出以数字作为小标的数组;

猜你喜欢

转载自blog.csdn.net/ihblxh/article/details/81952216