AWK用法全解

    技术2022-07-11  93

    一、awk介绍

    awk是Linux自带的一个逐行扫描的文本处理工具,支持正则表达式、循环控制、条件判断、格式化输出。AWK自身带有一些变量,可以在书写脚本时调用。

    二、基本语法格式

    2.1、在shell中使用awk

    awk [option] 代码块 文件名

    option的选项及含义 选项含义使用演示演示说明-F指定文件分隔符awk -F "\n"按\n做分隔符-f使用文件中的内容作为命令输入awk -f  script.txt使用script.txt文件中的内容作为命令-v给变量赋值,支持多个v赋值awk -v Num=$num -v Num1=$num1把num的值给Num、num1的值给Num1 代码块的说明:

    条件判断'{要执行的内容}'               注:条件判断与“{”之间不带空格,{}的两侧要使用单引号"'’"包围。

    条件判断为真则执行{}中的内容,条件判断为假则不执行{}中的内容。

    例如:

    awk -F "," NR==2'{print $1}' awktest.txt   

    #将awktest.txt文件中的文本以",",如果行号为2则打印第一列内容。

    awk -F "," NR==10'{print "这是第"NR"行","第1列是:"$1,"第2列是:"$2}' awktest.txt

    #打印多个列的字段、行号并于固定的字符串拼接

    2.2、在脚本中使用awk代码

    有些脚本命令比较长,在shell中编辑比较麻烦,这时考虑将命令写入脚本中方便保存和修改。

    在脚本文件中,大致格式如下:

    BEGIN{

    语句一

    语句二

    }

    表达式1 {要执行的内容}

    表达式2 {要执行的内容}

    END{

    语句一

    语句二

    }

    注意:{要执行的内容}中如果有多个语句要执行,使用","进行分割。在awk中,{}中的内容表示要执行的操作,赋值、判断等操作可以放在{}之外。

    创建一个文件awkScript.txt vi awkScript.txt

    以下脚本文件中的FS、NR是awk的自带变量,后面的内容中对此进行解释。 

    #awk的脚本文件 #开始部分,一般用于脚本执行前的初始化,比如设置每一列的标题、设置分割符等等。 BEGIN{ FS="," print "第一列","第二列" } #这里是主要执行的代码块 {print "这是第"NR"行"} NR%2 {print NR,"这是偶数行"} #END代码块。 END{ print "总计共有"NR"行" print "脚本执行结束" } awk以脚本的方式执行这些文件 awk -f awkScript.txt awktest.txt

    三、awk的内置变量

    awk内置一些变量,这些变量可能会随着文本读取的进度发生变化,比如现在读取到第几行。我们可以调用这些内置变量。

    变量名称说明使用示例示例说明$number记录被分割后的第number列的字段,$表示整行文本。{print $1,$3}打印第1列和第3列字段FS字段分割符(可使用FlieSplit记忆)BEGIN{FS="\n"}使用换行分割文本NF当前行中的字段数量{print "当前行共有"NF"列"}打印当前行的列数NR当前的行号(NnumberRow,从1开始)NR%2{print "这是偶数行"}判断是否是偶数行RS表示记录分隔符,多行文本的情况下,RS字符将文本分割成几个大块(RowSplit)

    BEGIN{

    FS="\N"

    RS=" "

    }

    对一个使用空行分割多个行的文本,RS表示的字符将文本分成多个段落,FS表示的字符将这些段落中的行分割成多个列。OFS表示输出字段之间分隔符,将输出的多个字段使用OFS拼接,缺省为" "。(OutFileSpilt)

    BEGIN{OFS=";"}

    {print "字段1","字段2","字段3"}

    输出的字段1、字段2、字段3变成"字段1;字段2;字段3"ORS表示输出行之间记录分隔符,在两个单独行插入定义的字符串,缺省为"\n"

    BEGIN{

    ORS="\n\n"

    }

    输出的文本行之间有两个空行

    四、awk的正则表达式

    awk的正则表达式和其他语言的正则表达式规则一致

    字符

    描述

    .

    可代替除一行之外的任何单个字符

    *

    可代替零个或多个在它前面出现的字符

    [chars]

    可代替chars中的任何一个字符,chars是一串字符序列。你可以用-符号来定义一个字符范围。如果^是chars中的第一个字符,那么将匹配没有在chars中指定的字符

    ^

    匹配一行的开头

    $

    匹配一行的结尾

    \

    把\后面的字符照常输出,通常用来转义(不使用特殊含义)一个元字符

    !~匹配到的内容取反,表示不匹配 在{}包裹的语句块之前使用正则表达式语法 

    awk ‘/REG/{action}’        /REG/为要匹配的内容,{action}为匹配成功后要执行的动作。

    #打印awktest.txt文件中包含2020年时间的行(使用"\"对/符号进行转义)

    awk -F "," '/2020\/[0-9]{1,2}\/[0-9]{1,2}/{print $0}' awktest.txt

    匹配到的结果为:

    在{}代码块中使用正则表达式语法

    awk -F "," '{if($0 ~ "2020/07/01"){print $0}else{print "none"}}' awktest.txt

    五、awk控制流语句

    5.1、条件语句

    awkif语句类似于C语言的if语句

    { if ( $1 == "foo" ) { if ( $2 == "foo" ) { print "uno" } else { print "one" } } else if ($1 == "bar" ) { print "two" } else { print "three" } }

    5.2、循环语句

    do...while循环 { count=1 do { print "I get printed at least once no matter what" } while ( count != 1 ) } for循环 for ( x = 1; x <= 4; x++ ) { print "iteration",x } break和continue语句

    如同C语言一样,awk提供了breakcontinue来控制awk的循环结构。break语句用于跳出最深层的循环,使循环立即终止,并继续执行循环代码块后面的语句。continue语句使awk立即开始执行下一个循环迭代,而不执行代码块的其余部分。

    5.4、数组

    awk中,数组下标通常从1开始,而不是0

    myarray[1]="jim" myarray[2]=456

     awk不需要连续的下标编号,例如,给myarray[1]赋值之后可以直接赋值myarrary[10]。

    awk可以使用"in"操作来遍历数组中的所有元素,但这种遍历是无序的,无法保证按下标顺序输出。

    for ( x in myarray ) { print myarray[x] }

     awk数组中还可以使用字符串下标,其实,不管你使用的下标是字符串还是数字,awk在幕后还将其认为是字符串下标。

    myarr["1"]="China" print myarr["1"] myarr["name"]="Mr. Whipple" print myarr["name"]

    六、awk的内置函数

    awk并不像其他语言一样,把字符串看作是字符数组。执行以下代码:

    mystring="How are you doing today?" print mystring[3]

    将会报错: 

    awk: string.gawk:59: fatal: attempt to use scalar as array

    为了应对这种情况,awk内置了许多字符串函数。 

    字符串函数功能说明使用示例示例说明length()返回字符串的长度print length(mystring) 打印mystring字符串的长度index()返回子字符串在另一个字符串中出现的位置print index(mystring,"you") 返回子字符串“you”在另一个mystring中出现的位置,如果没有找到该字符串则返回0tolower()返回字符串并且将所有字符转换成小写print tolower(mystring) 把mystring所有的字母改成大写toupper()返回字符串并且将所有字符转换成大写print toupper(mystring) 把mystring所有的字母改成小写substr()返回从字符串中选择的子串awk '{print substr($0,2,10)}'打印字符串从第2位开始后面10个字符match()返回子字符串在另一个字符串中出现的位置。它与index()的区别在于它并不搜索子串,它搜索的是正则表达式。match()还将设置两个变量,叫作RSTARTRLENGTHRSTART包含返回值(第一个匹配的位置),默认返回RESTART,RLENGTH指定它占据的字符跨度(如果没有找到匹配,则返回-1print match($0,/2020\/07\/01/),RLENGTH打印2020/07/01匹配到的起始位置和它的长度。sub()替换匹配的第一个字符序列,并返回整个字符串sub(regexp,replstring,mystring) replstring替换在mystring中匹配regexp的第一个字符序列,sub()替换第一个regexp匹配gsub()替换匹配的全部字符序列,并返回整个字符串gsub(regexp,replstring,mystring) replstring替换全部在mystring中匹配regexp的第一个字符序列split()分割字符串,并将各部分放到使用整数下标的数组中num=split($0,var,",") {print var[1]}将当前行的文本以","分割,放进var数组中,打印第一各元素。num为接受分割后数组的长度。

    七、awk的格式化输出

    然大多数情况下awkprint语句可以完成任务,但有时我们还需要更多。使用两个函数printf()sprintf(),将能让输出锦上添花。printf()会将格式化字符串打印到stdout,而sprintf()则返回可以赋值给变量的格式化字符串。

    x=1 b="foo" printf("%s got a %d on the last test\n","Jim",83) myout=("%s-%d",b,x) print myout

     

    Processed: 0.011, SQL: 9