tubaobaoya3 发表于 2018-8-28 09:05:13

Linux Shell常用技巧(四) awk-442938684

Linux Shell常用技巧(四) awk
  九.awk实用功能:
  和sed一样,awk也是逐行扫描文件的,从第一行到最后一行,寻找匹配特定模板的行,并在这些行上运行“选择”动作。如果一个模板没有指定动作,这些匹配的行就被显示在屏幕上。如果一个动作没有模板,所有被动作指定的行都被处理。
  1.awk的基本格式:
      /> awk 'pattern' filename
      /> awk '{action}' filename
      /> awk 'pattern {action}' filename
  具体应用方式分别见如下三个用例:
   /> cat employees
  Tom Jones         4424    5/12/66         543354
  Mary Adams      5346    11/4/63         28765
  Sally Chang       1654    7/22/54         650000
  Billy Black         1683    9/23/44         336500
   /> awk '/Mary/' employees   #打印所有包含模板Mary的行。
  Mary Adams      5346    11/4/63         28765
  #打印文件中的第一个字段,这个域在每一行的开始,缺省由空格或其它分隔符。
   /> awk '{print $1}' employees
  Tom
  Mary
  Sally
  Billy
  /> awk '/Sally/{print $1, $2}' employees #打印包含模板Sally的行的第一、第二个域字段。
  Sally Chang
  2.awk的格式输出:
  awk中同时提供了print和printf两种打印输出的函数,其中print函数的参数可以是变量、数值或者字符串。字符串必须用双引号引用,参数用逗号分隔。如果没有逗号,参数就串联在一起而无法区分。这里,逗号的作用与输出文件的分隔符的作用是一样的,只是后者是空格而已。下面给出基本的转码序列:
转码含义\n换行\r回车\t制表符      /> date | awk '{print "Month: " $2 "\nYear: ", $6}'
  Month: Oct
  Year:2011
  /> awk '/Sally/{print "\t\tHave a nice day, " $1,$2 "\!"}' employees
  Have a nice day, Sally Chang!
  在打印数字的时候你也许想控制数字的格式,我们通常用printf来完成这个功能。awk的特殊变量OFMT也可以在使用print函数的时候,控制数字的打印格式。它的默认值是"%.6g"----小数点后面6位将被打印。
  /> awk 'BEGIN { OFMT="%.2f"; print 1.2456789, 12E-2}'
  1.250.12
  现在我们介绍一下功能更为强大的printf函数,其用法和c语言中printf基本相似。下面我们给出awk中printf的格式化说明符列表:
格式化说明符功能示例结果%c打印单个ASCII字符。printf("The character is %c.\n",x)The character is A.%d打印十进制数。printf("The boy is %d years old.\n",y)The boy is 15 years old.%e打印用科学记数法表示的数。printf("z is %e.\n",z)z is 2.3e+01.%f打印浮点数。printf("z is %f.\n",z)z is 2.300000%o打印八进制数。printf("y is %o.\n",y)y is 17.%s打印字符串。printf("The name of the culprit is %s.\n",$1);The name of the culprit is Bob Smith.%x打印十六进制数。printf("y is %x.\n",y)y is f.      注:假设列表中的变脸值为x = A, y = 15, z = 2.3, $1 = "Bob Smith"
      /> echo "Linux" | awk '{printf "|%-15s|\n", $1}' # %-15s表示保留15个字符的空间,同时左对齐。
  |Linux          |
   /> echo "Linux" | awk '{printf "|%15s|\n", $1}' # %-15s表示保留15个字符的空间,同时右对齐。
  |          Linux|
  #%8d表示数字右对齐,保留8个字符的空间。
   /> awk '{printf "The name is %-15s>

  The name is Tom            >
  The name is Mary         >
  The name is Sally         >
  The name is Billy            >  3.awk中的记录和域:
  awk中默认的记录分隔符是回车,保存在其内建变量ORS和RS中。$0变量是指整条记录。
  /> awk '{print $0}' employees #这等同于print的默认行为。
  Tom Jones      4424    5/12/66         543354
  Mary Adams      5346    11/4/63         28765
  Sally Chang       1654    7/22/54         650000
  Billy Black         1683    9/23/44         336500
  变量NR(Number of Record),记录每条记录的编号。
  /> awk '{print NR, $0}' employees
  1 Tom Jones      4424    5/12/66         543354
  2 Mary Adams      5346    11/4/63         28765
  3 Sally Chang       1654    7/22/54         650000
  4 Billy Black         1683    9/23/44         336500
  变量NF(Number of Field),记录当前记录有多少域。
  /> awk '{print $0,NF}' employees
  Tom Jones      4424    5/12/66          543354   5
  Mary Adams      5346    11/4/63         28765   5
  Sally Chang      1654    7/22/54          650000   5
  Billy Black      1683   9/23/44         336500    5
  #根据employees生成employees2。sed的用法可以参考上一篇blog。
   /> sed 's/[[:space:]]\+\(\)/:\1/g;w employees2' employees
      /> cat employees
  Tom Jones:4424:5/12/66:543354
  Mary Adams:5346:11/4/63:28765
  Sally Chang:1654:7/22/54:650000
  Billy Black:1683:9/23/44:336500
  /> awk -F: '/Tom Jones/{print $1,$2}' employees2 #这里-F选项后面的字符表示分隔符。
  Tom Jones 4424
  变量OFS(Output Field Seperator)表示输出字段间的分隔符,缺省是空格。
  />awk -F: '{OFS = "?"};/Tom/{print $1,$2 }' employees2 #在输出时,域字段间的分隔符已经是?(问号)了
  Tom Jones?4424
  对于awk而言,其模式部分将控制这动作部分的输入,只有符合模式条件的记录才可以交由动作部分基础处理,而模式部分不仅可以写成正则表达式(如上面的例子),awk还支持条件表达式,如:
  /> awk '$3 < 4000 {print}' employees
  Sally Chang   1654    7/22/54         650000
  Billy Black       1683    9/23/44         336500
  在花括号内,用分号分隔的语句称为动作。如果模式在动作前面,模式将决定什么时候发出动作。动作可以是一个语句或是一组语句。语句之间用分号分隔,也可以用换行符,如:
  pattern { action statement; action statement; etc. } or
  pattern {
  action statement
  action statement
  }
  模式和动作一般是捆绑在一起的。需要注意的是,动作是花括号内的语句。模式控制的动作是从第一个左花括号开始到第一个右花括号结束,如下:
  /> awk '$3 < 4000 && /Sally/ {print}' employees
  Sally Chang   1654    7/22/54         650000
  4.匹配操作符:
  " ~ " 用来在记录或者域内匹配正则表达式。
  /> awk '$1 ~ /ill/' employees    #显示所有第一个域匹配Bill或bill的行。
  Billy Black   1683    9/23/44         336500
  /> awk '$1 !~ /ill/' employees    #显示所有第一个域不匹配Bill或bill的行,其中!~表示不匹配的意思。
  Tom Jones      4424    5/12/66         543354
  Mary Adams      5346    11/4/63         28765
  Sally Chang       1654    7/22/54         650000
  5.awk的基本应用实例:
  /> cat testfile
  northwest   NW      Charles Main            3.0      .98      3      34
  western      WE      Sharon Gray            5.3      .97      5      23
  southwest   SW      Lewis Dalsass          2.7      .8          2      18
  southern       SO      Suan Chin                5.1      .95      4      15
  southeast      SE      Patricia Hemenway    4.0      .7          4      17
  eastern         EA      TB Savage                4.4      .84      5      20
  northeast      NE      AM Main Jr.               5.1      .94      3      13
  north            NO      Margot Weber          4.5      .89      5      9
  central          CT      Ann Stephens         5.7      .94      5      13
  /> awk '/^north/' testfile            #打印所有以north开头的行。
  northwest      NW      Charles Main   3.0   .98   3       34
  northeast       NE      AM Main Jr.      5.1   .94   3       13
  north             NO      Margot Weber   4.5   .89   5       9
   /> awk '/^(no|so)/' testfile      #打印所有以so和no开头的行。
  northwest       NW      Charles Main                3.0   .98      3       34
  southwest       SW      Lewis Dalsass            2.7   .8       2       18
  southern         SO      Suan Chin                  5.1   .95   4       15
  southeast      SE      Patricia Hemenway      4.0   .7       4       17
  northeast      NE      AM Main Jr.                   5.1   .94   3       13
  north            NO      Margot Weber            4.5   .89   5       9
  /> awk '$5 ~ /\.+/' testfile   #第五个域字段匹配包含.(点),后面是7-9的数字。
  southwest       SW      Lewis Dalsass            2.7   .8      2       18
  central             CT      Ann Stephens            5.7   .94   5       13
  /> awk '$8 ~ /$/{print $8}' testfile#第八个域以两个数字结束的打印。
  34
  23
  18
  15
  17
  20
  13
  十.awk表达式功能:
  1.比较表达式:
  比较表达式匹配那些只在条件为真时才运行的行。这些表达式利用关系运算符来比较数字和字符串。见如下awk支持的条件表达式列表:
运算符含义例子大于x > y~匹配x ~ /y/!~不匹配x !~ /y/      /> cat employees
  Tom Jones      4424    5/12/66         543354
  Mary Adams      5346    11/4/63         28765
  Sally Chang       1654    7/22/54         650000
  Billy Black         1683    9/23/44         336500
  /> awk '$3 == 5346' employees       #打印第三个域等于5346的行。
  Mary Adams      5346    11/4/63         28765
  /> awk '$3 > 5000 {print $1}' employees #打印第三个域大于5000的行的第一个域字段。
  Mary
  /> awk '$2 ~ /Adam/' employess    #打印第二个域匹配Adam的行。
  Mary Adams      5346    11/4/63         28765
  2.条件表达式:
  条件表达式使用两个符号--问号和冒号给表达式赋值: conditional expression1 ? expression2 : expressional3,其逻辑等同于C语言中的条件表达式。其对应的if/else语句如下:
  {
  if (expression1)
  expression2
  else
  expression3
  }
  /> cat testfile
  northwest   NW      Charles Main             3.0      .98      3      34
  western      WE      Sharon Gray             5.3      .97         5      23
  southwest   SW      Lewis Dalsass         2.7      .8          2      18
  southern       SO      Suan Chin               5.1      .95      4      15
  southeast      SE      Patricia Hemenway   4.0      .7          4      17
  eastern         EA      TB Savage               4.4      .84      5      20
  northeast      NE      AM Main Jr.                5.1       .94         3      13
  north            NO      Margot Weber         4.5       .89         5      9
  central          CT      Ann Stephens            5.7       .94         5      13
  /> awk 'NR4 ? "high "$7 : "low "$7) }' testfile
  low 3
  high 5
  low 2
  3.数学表达式:
  运算可以在模式内进行,其中awk将所有的运算都视为浮点运算,见如下列表:
运算符含义例子+加x + y-减x - y*乘x * y/除x / y%取余x % y^乘方x ^ y      /> awk '/southern/{print $5 + 10}' testfile #如果记录包含正则表达式southern,第五个域就加10并打印。
  15.1
  /> awk '/southern/{print $8 /2 }' testfile #如果记录包含正则表达式southern,第八个域除以2并打印。
  7.5
  4.逻辑表达式:
  见如下列表:
运算符含义例子&&逻辑与a && b||逻辑或a || b!逻辑非!a  /> awk '$8 > 10 && $8 < 17' testfile #打印出第八个域的值大于10小于17的记录。
  southern      SO      Suan Chin               5.1   .95   4       15
  central            CT      Ann Stephens         5.7   .94   5       13
  #打印第二个域等于NW,或者第一个域匹配south的行的第一、第二个域。
  /> awk '$2 == "NW" || $1 ~ /south/ {print $1,$2}' testfile
  northwestNW
  southwestSW
  southern    SO
  southeast   SE
   /> awk '!($8 > 13) {print $8}' testfile #打印第八个域字段不大于13的行的第八个域。
  3
  9
  13
  5.范围模板:
  范围模板匹配从第一个模板的第一次出现到第二个模板的第一次出现,第一个模板的下一次出现到第一个模板的下一次出现等等。如果第一个模板匹配而第二个模板没有出现,awk就显示到文件末尾的所有行。
  /> awk '/^western/,/^eastern/ {print $1}' testfile #打印以western开头到eastern开头的记录的第一个域。
  western    WE
  southwest SW
  southern   SO
  southeastSE
  eastern      EA
  6.赋值符号:
  #找到第三个域等于Ann的记录,然后给该域重新赋值为Christian,之后再打印输出该记录。
  /> awk '$3 == "Ann" { $3 = "Christian"; print}' testfile
  central CT Christian Stephens 5.7 .94 5 13
  /> awk '/Ann/{$8 += 12; print $8}' testfile #找到包含Ann的记录,并将该条记录的第八个域的值+=12,最后再打印输出。
  25

页: [1]
查看完整版本: Linux Shell常用技巧(四) awk-442938684