awk运用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 | awk 编程 1. 变量: 在 awk 中变量无须定义即可使用,变量在赋值时即已经完成了定义。变量的类型可以是数字、字符串。根据使用的不同,未初始化变量的值为0或空白字符串 " " ,这主要取决于变量应用的上下文。 awk '$1 ~ /Tom/ {Wage = $2 * $3; print Wage}' filename 该命令将从文件中读取,并查找第一个域字段匹配Tom的记录,再将其第二和第三个字段的乘积赋值给自定义的Wage变量,最后通过print命令将该变量打印输出。 awk ' {$5 = 1000 * $3 / $2; print}' filename 在上面的命令中,如果$5不存在, awk 将计算表达式1000 * $3 / $2的值,并将其赋值给$5。如果第五个域存在,则用表达式覆盖$5原来的值。 我们同样也可以在命令行中定义自定义的变量,用法如下: awk -F: -f awkscript month=4 year=2011 filename 这里的month和year都是自定义变量,且分别被赋值为4和2000,在 awk 的脚本中这些变量将可以被直接使用,他们和脚本中定义的变量在使用上没有任何区别。 除此之外, awk 还提供了一组内建变量(变量名全部大写),见如下列表: 变量名 变量内容 ARGC 命令行参数的数量。 ARGIND 命令行正在处理的当前文件的AGV的索引。 ARGV 命令行参数数组。 CONVFMT 转换数字格式。 ENVIRON 从shell中传递来的包含当前环境变量的数组。 ERRNO 当使用close函数或者通过getline函数读取的时候,发生的重新定向错误的描述信息就保存在这个变量中。 FIELDWIDTHS 在对记录进行固定域宽的分割时,可以替代FS的分隔符的列表。 FILENAME 当前的输入文件名。 FNR 当前文件的记录号。 FS 输入分隔符,默认是空格。 IGNORECASE 在正则表达式和字符串操作中关闭大小写敏感。 NF 当前文件域的数量。 NR 当前文件记录数。 OFMT 数字输出格式。 OFS 输出域分隔符。 ORS 输出记录分隔符。 RLENGTH 通过match函数匹配的字符串的长度。 RS 输入记录分隔符。 RSTART 通过match函数匹配的字符串的偏移量。 SUBSEP 下标分隔符。 cat employees2 Tom Jones:4424:5 /12/66 :543354 Mary Adams:5346:11 /4/63 :28765 Sally Chang:1654:7 /22/54 :650000 Mary Black:1683:9 /23/44 :336500 awk -F: '{IGNORECASE = 1}; $1 == "mary adams" { print NR, $1, $2, $NF}' employees2 2 Mary Adams 5346 28765 awk -F: ' $1 == "mary adams" { print NR, $1, $2, $NF}' employees2 没有输出结果。 当IGNORECASE内置变量的值为非0时,表示在进行字符串操作和处理正则表达式时关闭大小写敏感。这里的 "mary adams" 将匹配文件中的 "Mary Admams" 记录。最后print打印出第一、第二和最后一个域。需要说明的是NF表示当前记录域的数量,因此$NF将表示最后一个域的值。 awk 在动作部分还提供了BEGIN块和END块。其中BEGIN动作块在 awk 处理任何输入文件行之前执行。事实上,BEGIN块可以在没有任何输入 文件的条件下测试。因为在BEGIN块执行完毕以前 awk 将不读取任何输入文件。BEGIN块通常被用来改变内建变量的值,如OFS、RS或FS等。也可 以用于初始化自定义变量值,或打印输出标题。 awk 'BEGIN {FS = ":" ; OFS = "\t" ; ORS = "\n\n" } { print $1,$2,$3} filename 上例中 awk 在处理文件之前,已经将域分隔符(FS)设置为冒号,输出文件域分隔符(OFS)设置为制表符,输出记录分隔符(ORS)被设置为两个换行符。BEGIN之后的动作模块中如果有多个语句,他们之间用分号分隔。 和BEGIN恰恰相反,END模块中的动作是在整个文件处理完毕之后被执行的。 awk 'END {print "The number of the records is " NR }' filename awk 在处理输入文件之后,执行END模块中的动作,上例中NR的值是读入的最后一个记录的记录号。 awk '/Mary/{count++} END{print "Mary was found " count " times." }' employees2 Mary was found 2 times . awk '/Mary/{count++} END{print "Mary was found " count " times." }' employees2 Mary was found 2 times . 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/{count += 1; print count}' testfile #如记录以正则north开头,则创建变量count同时增一,再输出其值。 1 2 3 #这里只是输出前三个字段,其中第七个域先被赋值给变量x,在自减一,最后再同时打印出他们。 awk 'NR <= 3 {x = $7--; print "x = " x ", $7 = " $7}' testfile x = 3, $7 = 2 x = 5, $7 = 4 x = 2, $7 = 1 #打印NR(记录号)的值在2--5之间的记录。 awk 'NR == 2,NR == 5 {print "The record number is " NR}' testfile The record number is 2 The record number is 3 The record number is 4 The record number is 5 #打印环境变量USER和HOME的值。环境变量的值由父进程shell传递给awk程序的。 awk 'BEGIN { print ENVIRON["USER"],ENVIRON["HOME"]}' root /root #BEGIN块儿中对OFS内置变量重新赋值了,因此后面的输出域分隔符改为了\t。 awk 'BEGIN { OFS = "\t"}; /^Sharon/{ print $1,$2,$7}' testfile western WE 5 #从输入文件中找到以north开头的记录count就加一,最后在END块中输出该变量。 awk '/^north/{count++}; END{print count}' testfile 3 2. 重新定向: 在 动作语句中使用shell通用的重定向输出符号 ">" 就可以完成 awk 的重定向操作,当使用>的时候,原有文件将被清空,同时文件持续打开, 直到文件被明确的关闭或者 awk 程序终止。来自后面的打印语句的输出会追加到前面内容的后面。符号 ">>" 用来打开一个文件但是不清空原有文 件的内容,重定向的输出只是被追加到这个文件的末尾。 awk '$4 >= 70 {print $1,$2 > "passing_file"}' filename #注意这里的文件名需要用双引号括起来。 #通过两次cat的结果可以看出>和>>的区别。 awk '/north/{print $1,$3,$4 > "districts" }' testfile cat districts northwest Joel Craig northeast TJ Nichols north Val Shultz awk '/south/{print $1,$3,$4 >> "districts" }' testfile cat districts northwest Joel Craig northeast TJ Nichols north Val Shultz southwest Chris Foster southern May Chin southeast Derek Jonhson awk 中对于输入重定向是通过getline函数来完成的。getline函数的作用是从标准输入、管道或者当前正在处理的文件之外的其他输入文件获得 输入。他负责从输入获得下一行的内容,并给NF、NR和FNR等内建变量赋值。如果得到一个记录,getline就返回1,如果达到文件末尾就返回0。如 果出现错误,如打开文件失败,就返回-1。 awk 'BEGIN { "date" | getline d; print d}' Tue Nov 15 15:31:42 CST 2011 上例中的BEGIN动作模块中,先执行shell命令 date ,并通过管道输出给getline,然后再把输出赋值给自定义变量d并打印输出它。 awk 'BEGIN { "date" | getline d; split(d,mon); print mon[2]}' Nov 上例中 date 命令通过管道输出给getline并赋值给d变量,再通过内置函数 split 将d拆分为mon数组,最后print出mon数组的第二个元素。 awk 'BEGIN { while("ls" | getline) print}' employees employees2 testfile 命令 ls 的输出传递给getline作为输入,循环的每个反复,getline都从 ls 的结果中读取一行输入,并把他打印到屏幕。 awk 'BEGIN { printf "What is your name? " ; \ getline name < "/dev/tty" }\ $1 ~ name {print "Found" name " on line " , NR "." }\ END {print "See ya, " name "." }' employees2 What is your name? Mary Found Mary on line 2. See ya, Mary. 上例先是打印出BEGIN块中的 "What is your name? " ,然后等待用户从 /dev/tty 输入,并将读入的数据赋值给name变量,之后再从输入文件中读取记录,并找到匹配输入变量的记录并打印出来,最后在END块中输出结尾信息。 awk 'BEGIN { while(getline < "/etc/passwd" > 0) lc++; print lc}' 32 awk 将逐行读取 /etc/passwd 文件中的内容,在达到文件末尾之前,计数器lc一直自增1,当到了末尾后打印lc的值。lc的值为 /etc/passwd 文件的行数。 由于 awk 中同时打开的管道只有一个,那么在打开下一个管道之前必须关闭它,管道符号右边可以通过可以通过双引号关闭管道。如果不关闭,它将始终保持打开状态,直到 awk 退出。 awk {print $1,$2,$3 | "sort -4 +1 -2 +0 -1" } END {close( "sort -4 +1 -2 +0 -1" ) } filename 上例中END模块中的close显示关闭了 sort 的管道,需要注意的是close中关闭的命令必须和当初打开时的完全匹配,否则END模块产生的输出会和以前的输出一起被 sort 分类。 3. 条件语句: awk 中的条件语句是从C语言中借鉴来的,见如下声明方式: if (expression) { statement; statement; ... ... } awk '{if ($6 > 50) print $1 "Too hign"}' filename awk '{if ($6 > 20 && $6 <= 50) { safe++; print "OK}}' filename if (expression) { statement; } else { statement2; } awk '{if ($6 > 50) print $1 " Too high"; else print "Range is OK" }' filename awk '{if ($6 > 50) { count++; print $3 } else { x = 5; print $5 }' filename if (expression) { statement1; } else if (expression1) { statement2; } else { statement3; } awk '{if ($6 > 50) print "$6 > 50" else if ($6 > 30) print "$6 > 30" else print "other"}' filename 4. 循环语句: awk 中的循环语句同样借鉴于C语言,支持 while 、 do /while 、 for 、 break 、 continue ,这些关键字的语义和C语言中的语义完全相同。 5. 流程控制语句: next语句是从文件中读取下一行,然后从头开始执行 awk 脚本。 exit 语句用于结束 awk 程序。它终止对记录的处理。但是不会略过END模块,如果 exit ()语句被赋值0--255之间的参数,如 exit (1),这个参数就被打印到命令行,以判断退出成功还是失败。 6. 数组: 因 为 awk 中数组的下标可以是数字和字母,数组的下标通常被称为关键字(key)。值和关键字都存储在内部的一张针对key /value 应用 hash 的表格 里。由于 hash 不是顺序存储,因此在显示数组内容时会发现,它们并不是按照你预料的顺序显示出来的。数组和变量一样,都是在使用时自动创建的, awk 也 同样会自动判断其存储的是数字还是字符串。一般而言, awk 中的数组用来从记录中收集信息,可以用于计算总和、统计单词以及跟踪模板被匹配的次数等等。 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 '{name[x++] = $2}; END{for (i = 0; i < NR; i++) print i, name[i]}' employees 0 Jones 1 Adams 2 Chang 3 Black 在上例中,数组name的下标是变量x。 awk 初始化该变量的值为0,在每次使用后自增1,读取文件中的第二个域的值被依次赋值给name数组的各个元素。在END模块中, for 循环遍历数组的值。因为下标是关键字,所以它不一定从0开始,可以从任何值开始。 #这里是用内置变量NR作为数组的下标了。 awk '{id[NR] = $3}; END {for (x = 1; x <= NR; x++) print id[x]}' employees 4424 5346 1654 1683 awk 中还提供了一种special for 的循环,见如下声明: for (item in arrayname) { print arrayname[item] } cat db Tom Jones Mary Adams Sally Chang Billy Black Tom Savage Tom Chung Reggie Steel Tommy Tucker awk '/^Tom/{name[NR]=$1}; END {for(i = 1;i <= NR; i++) print name[i]}' db Tom Tom Tom Tommy 从输出结果可以看出,只有匹配正则表达式的记录的第一个域被赋值给数组name的指定下标元素。因为用NR作为下标,所以数组的下标不可能是连续的,因 此在END模块中用传统的 for 循环打印时,不存在的元素就打印空字符串了。下面我们看看用special for 的方式会有什么样的输出。 awk '/^Tom/{name[NR]=$1};END{for(i in name) print name[i]}' db Tom Tom Tommy Tom 下面我们看一下用字符串作为下标的例子:(如果下标是字符串文字常量,则需要用双引号括起来) cat testfile2 tom mary sean tom mary mary bob mary alex awk ' /tom/ {count[ "tom" ]++}; /mary/ {count[ "mary" ]++}; END{print "There are " count[ "tom" ] \ " Toms and " count[ "mary" ] " Marys in the file." } testfile2 There are 2 Toms and 4 Marys in the file . 在上例中,count数组有两个元素,下标分别为tom和mary,每一个元素的初始值都是0,没有tom被匹配的时候,count[ "tom" ]就会加一,count[ "mary" ]在匹配mary的时候也同样如此。END模块中打印出存储在数组中的各个元素。 awk '{count[$1]++}; END{for(name in count) printf "%-5s%d\n",name, count[name]}' testfile2 mary 4 tom 2 alex 1 bob 1 sean 1 在上例中, awk 是以记录的域作为数组count的下标。 awk '{count[$1]++; if (count[$1] > 1) name[$1]++}; END{print "The duplicates were "; for(i in name) print i}' testfile2 The duplicates were mary tom 在上例中,如count[$1]的元素值大于1的时候,也就是当名字出现多次的时候,一个新的数组name将被初始化,最后打印出那么数组中重复出现的名字下标。 之前我们介绍的都是如何给数组添加新的元素,并赋予初值,现在我们需要介绍一下如何删除数组中已经存在的元素。要完成这一功能我们需要使用内置函数delete,见如下命令: awk '{count[$1]++}; \ END{ for (name in count) {\ if (count[name] == 1)\ delete count[name];\ } \ for (name in count) \ print name}' testfile2 mary tom 上例中的主要技巧来自END模块,先是变量count数组,如果数组中某个元素的值等于1,则删除该元素,这样等同于删除只出现一次的名字。最后用special for 循环打印出数组中仍然存在的元素下标名称。 最后我们来看一下如何使用命令行参数数组,见如下命令: awk 'BEGIN {for(i = 0; i < ARGC; i++) printf("argv[%d] is %s.\n",i,ARGV[i]); printf("The number of arguments, ARGC=%d\n",ARGC)}' testfile "Peter Pan" 12 argv[0] is awk . argv[1] is testfile. argv[2] is Peter Pan. argv[3] is 12. The number of arguments, ARGC=4 从输出结果可以看出,命令行参数数组ARGV是以0作为起始下标的,命令行的第一个参数为命令本身( awk ),这个使用方式和C语句main函数完全一致。 awk 'BEGIN{name=ARGV[2]; print "ARGV[2] is " ARGV[2]}; $1 ~ name{print $0}' testfile2 "bob" ARGV[2] is bob bob awk : (FILENAME=testfile2 FNR=9) fatal: cannot open file `bob' for reading (No such file or directory) 先解释一下以上命令的含义,name变量被赋值为命令行的第三个参数,即bob,之后再在输入文件中找到匹配该变量值的记录,并打印出该记录。 在输出的第二行报出了 awk 的处理错误信息,这主要是因为 awk 将bob视为输入文件来处理了,然而事实上这个文件并不存在,下面我们需要做进一步的处理来修正这个问题。 awk 'BEGIN{name=ARGV[2]; print "ARGV[2] is " ARGV[2]; delete ARGV[2]}; $1 ~ name{print $0}' testfile2 "bob" ARGV[2] is bob bob 从输出结果中我们可以看到我们得到了我们想要的结果。需要注意的是delete函数的调用必要要在BEGIN模块中完成,因为这时 awk 还没有开始读取命令行参数中指定的文件。 7. 内建函数: 字符串函数 sub(regular expression,substitution string); sub(regular expression,substitution string,target string); awk '{sub("Tom","Tommy"); print}' employees #这里使用Tommy替换了Tom。 Tommy Jones 4424 5 /12/66 543354 #当正则表达式Tom在第一个域中第一次被匹配后,他将被字符串"Tommy"替换,如果将sub函数的第三个参数改为$2,将不会有替换发生。 awk '{sub("Tom","Tommy",$1); print}' employees Tommy Jones 4424 5 /12/66 543354 gsub(regular expression,substitution string); gsub(regular expression,substitution string,target string); 和sub不同的是,如果第一个参数中正则表达式在记录中出现多次,那么gsub将完成多次替换,而sub只是替换第一次出现的。 index(string,substring) 该函数将返回第二个参数在第一个参数中出现的位置,偏移量从1开始。 awk 'BEGIN{print index("hello","el")}' 2 length(string) 该函数返回字符串的长度。 awk 'BEGIN{print length("hello")}' 5 substr(string,starting position) substr(string,starting position,length of string) 该函数返回第一个参数的子字符串,其截取起始位置为第二个参数(偏移量为1),截取长度为第三个参数,如果没有该参数,则从第二个参数指定的位置起,直到string的末尾。 awk 'BEGIN{name = substr("Hello World",2,3); print name}' ell match(string,regular expression) 该函数返回在字符串中正则表达式位置的索引,如果找不到指定的正则表达式就返回0.match函数设置内置变量RSTART为字符串中子字符串的开始位置,RLENGTH为到字字符串末尾的字符个数。 awk 'BEGIN{start=match("Good ole CHINA", /[A-Z]+$/); print start}' 10 上例中的正则表达式[A-Z]+$表示在字符串的末尾搜索连续的大写字母。在字符串 "Good ole CHINA" 的第10个位置找到字符串 "CHINA" 。 awk 'BEGIN{start=match("Good ole CHINA", /[A-Z]+$/); print RSTART, RLENGTH}' 10 5 RSTART表示匹配时的起始索引,RLENGTH表示匹配的长度。 awk 'BEGIN{string="Good ole CHINA";start=match(string, /[A-Z]+$/); print substr(string,RSTART, RLENGTH)}' CHINA 这里将match、RSTART、RLENGTH和substr巧妙的结合起来了。 toupper(string) tolower(string) 以上两个函数分别返回参数字符串的大写和小写的形式。 awk 'BEGIN {print toupper("hello"); print tolower("WORLD")}' HELLO world split (string,array,field seperator) split (string,array) 该函数使用作为第三个参数的域分隔符把字符串分隔为一个数组。如果第三个参数没有提供,则使用当前默认的FS值。 awk 'BEGIN{split("11/20/2011",date,"/"); print date[2]}' 20 variable = sprintf( "string with format specifiers " ,expr1,expr2,...) 该函数和 printf 的差别等同于C语言中 printf 和sprintf的差别。前者将格式化后的结果输出到输出流,而后者输出到函数的返回值中。 awk 'BEGIN{line = sprintf("%-15s %6.2f ", "hello",4.2); print line}' hello 4.20 时间函数: systime() 该函数返回当前时间距离1970年1月1日之间相差的秒数。 awk 'BEGIN{print systime()}' 1321369554 strftime() 时间格式化函数,其格式化规则等同于C语言中的strftime函数提供的规则,见以下列表: 数据格式 含义 %a Abbreviated weekday name %A Full weekday name %b Abbreviated month name %B Full month name %c Date and time representation appropriate for locale %d Day of month as decimal number (01 – 31) %H Hour in 24-hour format (00 – 23) %I Hour in 12-hour format (01 – 12) %j Day of year as decimal number (001 – 366) %m Month as decimal number (01 – 12) %M Minute as decimal number (00 – 59) %p Current locale's A.M. /P .M. indicator for 12-hour clock %S Second as decimal number (00 – 59) %U Week of year as decimal number, with Sunday as first day of week (00 – 53) %w Weekday as decimal number (0 – 6; Sunday is 0) %W Week of year as decimal number, with Monday as first day of week (00 – 53) %x Date representation for current locale %X Time representation for current locale %y Year without century, as decimal number (00 – 99) %Y Year with century, as decimal number awk 'BEGIN{ print strftime("%D",systime())}' 11 /15/11 awk 'BEGIN{ now = strftime("%T"); print now}' 23:17:29 内置数学函数: 名称 返回值 atan2(x,y) y,x范围内的余切 cos(x) 余弦函数 exp(x) 求幂 int(x) 取整 log(x) 自然对数 sin(x) 正弦函数 sqrt(x) 平方根 awk 'BEGIN{print 31/3}' 10.3333 awk 'BEGIN{print int(31/3)}' 10 自定义函数: 自定义函数可以放在 awk 脚本的任何可以放置模板和动作的地方。 function name(parameter1,parameter2,...) { statements return expression } 给函数中本地变量传递值。只使用变量的拷贝。数组通过地址或者指针传递,所以可以在函数内部直接改变数组元素的值。函数内部使用的任何没有作为参数传递 的变量都被看做是全局变量,也就是这些变量对于整个程序都是可见的。如果变量在函数中发生了变化,那么就是在整个程序中发生了改变。唯一向函数提供本地变 量的办法就是把他们放在参数列表中,这些参数通常被放在列表的最后。如果函数调用没有提供正式的参数,那么参数就初始化为空。 return 语句通常就返回 程序控制并向调用者返回一个值。 cat grades 20 10 30 20 40 30 cat add.sc function add(first,second) { return first + second } { print add($1,$2) } awk -f add.sc grades 30 50 70 一.基本介绍 1. awk : awk 是一个强大的文本分析工具,在对文本文件的处理以及生成报表, awk 是无可替代的。 awk 认为文本文件都是结构化的,它将每一个输入行定义为一个记录,行中的每个字符串定义为一个域(段),域和域之间使用分割符分割。 2.功能:流控制、数学运算、进程控制、内置的变量和函数、循环和判断 3.工作原理: awk 会把每行进行一个拆分,用相应的命令对拆分出来的“段”进行处理。 (1)行工作模式,读入文件的每一行,会把一行的内容,存到$0里 (2)使用内置的变量FS(段的分隔符,默认用的是空白字符),分割这一行,把分割出来的每个段存到相应的变量$(1-100) (3)输出的时候按照内置变量OFS(out FS),输出 (4)读入下一行继续操作 简单实例 [root@tx3 ~] # echo "this is a book" > awk.txt [root@tx3 ~] # awk '{print $2,$1,$3,$4}' awk.txt is this a book 4. Awk常用内置变量表: 1 $0 当前记录(作为单个变量) 2 $1~$n 当前记录的第n个字段,字段间由FS分隔 3 FS 输入字段分隔符 默认是空格 4 NF 当前记录中的字段个数,就是有多少列 5 NR 已经读出的记录数,就是行号,从1开始 6 RS 输入的记录他隔符默 认为换行符 7 OFS 输出字段分隔符 默认也是空格 8 ORS 输出的记录分隔符,默认为换行符 9 ARGC 命令行参数个数 10 ARGV 命令行参数数组 11 FILENAME 当前输入文件的名字 12 IGNORECASE 如果为真,则进行忽略大小写的匹配 13 ARGIND 当前被处理文件的ARGV标志符 14 CONVFMT 数字转换格式 %.6g 15 ENVIRON UNIX环境变量 16 ERRNO UNIX系统错误消息 17 FIELDWIDTHS 输入字段宽度的空白分隔字符串 18 FNR 当前记录数 19 OFMT 数字的输出格式 %.6g 20 RSTART 被匹配函数匹配的字符串首 21 RLENGTH 被匹配函数匹配的字符串长度 二.print的简单使用 例:打印整行: $0 [root@tx3 ~] # cp /etc/passwd p1 [root@tx3 ~] # awk '{print $0}' p1 例:打印每行的最后一个字段: $NF [root@tx3 ~] # awk -F : '{print $NF}' p1 例:打印第三个字段: $3 [root@tx3 ~] # awk -F : '{print $3}' p1 例:打印第一行NR==1 [root@tx3 ~] # awk 'NR==1{print $0}' p1 root:x:0:0:root: /root : /bin/bash 例:打印最后一行 [root@tx3 ~] # awk 'END{print $0}' p1 tx:x:500:500:tx: /home/tx : /bin/bash 例:打印第一行最后一个字段 [root@tx3 ~] # awk -F: 'NR==1{print $NF}' p1 /bin/bash 例:打印最后一行最后一个字段 [root@tx3 ~] #awk -F: 'END{print $NF}' p1 例:打印每行的倒数第二个字段,并在其后打印你好 [root@tx3 ~] # awk -F: '{print $(NF-1),"nihao"}' p1 /root nihao /bin nihao /sbin nihao 例:打印行号 [root@tx3 ~] # awk '{print NR,$0}' p1 1 root:x:0:0:root: /root : /bin/bash 2 bin:x:1:1:bin: /bin : /sbin/nologin 3 daemon:x:2:2:daemon: /sbin : /sbin/nologin 例:打印当前系统环境变量的某个特定值 [root@tx3 ~] # awk 'BEGIN{print ENVIRON["PATH"];}' /usr/kerberos/sbin : /usr/kerberos/bin : /usr/local/sbin : /usr/local/bin : /sbin : /bin : /usr/sbin : /usr/bin : /root/bin 例: 用:分割,删除第2个字段 [root@tx3 ~] # awk 'BEGIN{FS=":";OFS=":"}{print $1,$3,$4,$5,$6,$7}' p1 root:0:0:root: /root : /bin/bash bin:1:1:bin: /bin : /sbin/nologin daemon:2:2:daemon: /sbin : /sbin/nologin 三. printf 的使用 print format 生成报表 %d 十进制有符号整数 %u 十进制无符号整数 %f 浮点数 %s 字符串 %c 显示字符的ASCII码 %p 指针的值 %e 科学技术法显示数值 %x %X 无符号以十六进制表示的整数 %o 无符号以八进制表示的整数 %g %G 以科学计数法或浮点数的格式显示数值 %% 显示其自身 修饰符: -: 左对齐 +: 显示数值符号 N: 显示 -F 指定段的分隔符 例:(1)生成报表 例:(2)小数问题 对小数取保留位的时候,四舍五入 对小数取整,不进行四舍五入 [root@tx3 ~] # cat awk.1 23.3456 11.234 45.67 [root@tx3 ~] # awk '{printf "%.2f\t%.2f\t%.2f\n",$1,$2,$3}' awk.1 23.3511.2345.67 四. awk 的使用 (1)正则表达式 \(\) \{\} 不支持 . * ^ $ ? + [] | \< \> () 可以直接使用 例[root@tx3 ~] # awk '/^$/{print "this is an empty line"}' /etc/inittab this is an empty line this is an empty line this is an empty line this is an empty line this is an empty line this is an empty line this is an empty line this is an empty line this is an empty line 例[root@tx3 ~] # awk -F: '/^root/{print $1,$NF}' /etc/passwd root /bin/bash 例[root@tx3 ~] # awk -F: '!/^root/{print $1,$NF}' /etc/passwd|head -3 bin /sbin/nologin daemon /sbin/nologin adm /sbin/nologin (2)关系运算符 > < == != >= <= ~(匹配) !~(不匹配) 例[root@tx3 ~] # cp /etc/passwd p1 [root@tx3 ~] # awk -F: '$3 == 0 {print $1}' p1 Root 例[root@tx3 ~] # awk -F: '$3 != 0{ print $1}' p1 | head -2 bin Daemon 例[root@tx3 ~] # awk -F: '$3 < 2 {print $1}' p1 root bin (3)逻辑运算符 && || ! 与 或 非 例[root@tx3 ~] # awk -F: '$3 > 0 && $3 < 10 {print $1, $3}' p1 |head -2 bin 1 daemon 2 例[root@tx3 ~] # awk -F: '$3 > 10 || $3 < 5 {print $1,$3}' p1 |head -6 root 0 bin 1 daemon 2 adm 3 lp 4 operator 11 (4)算数运算符 + - * / %(取模(余数)) ^(幂运算) 例:输出名字,总成绩,平均成绩 [root@tx3 ~] # cat cj tx 90 86 86 tx1 89 78 85 tx2 79 80 85 [root@tx3 ~] # awk '{print $1,$2+$3+$4,($2+$3+$4)/3}' cj tx 262 87.3333 tx1 252 84 tx2 244 81.3333 [root@tx3 ~] # awk '{printf"%-5s %3d %.2f\n",$1,$2+$3+$4,($2+$3+$4)/3}' cj tx 262 87.33 tx1 252 84.00 tx2 244 81.33 (5)BEGIN END BEGIN{ 动作;动作;... } 在处理文件之前,要执行的动作;只执行一次 END{ 动作;动作;... } 在处理完文件之后,要执行的动作;只执行一次 BEGIN :可以给文件添加标题、定义变量、定义文件的分隔符 END:汇总的操作 getline可以从管道和标准输入读取输入,然后传递给变量。 例: [root@tx3 ~] # awk 'BEGIN{"date"| getline a}{print}END{print a}' cj tx 90 86 86 tx1 89 78 85 tx2 79 80 85 Thu Feb 7 12:39:25 CST 2013 五. awk 里的流控制和循环 (1)简单的条件判断 语法:(表达式 ? 值1 : 值2) 如果表达式成立,输出值1;否则输出值2 [root@tx3 ~] # cat num 2 8 9 8 4 6 3 5 7 [root@tx3 ~] # awk '{print ( $1 > $2 ? $1 : $2)}' num 8 8 5 (2) if 判断 语法: { if (表达式 { 动作1;动作2;... } } 如果表达式成立,那么执行动作。 [root@tx3 ~] # awk '{if ($2>=80 && $2 <=100) {print $1,"great"} else {print $1, "good"}}' cj tx great tx1 great tx2 good (2)多支判断 { if (表达式) { 动作1;动作2;...} else if (表达式) { 动作1;动作2;...} else if (表达式) { 动作1;动作2;...} ...... else { 动作1;动作2;...} } [root@tx3 ~] # cat cj tx 90 86 86 tx1 89 78 85 tx2 79 80 85 tx3 80 70 60 tx4 75 85 65 tx5 78 62 80 判断的标准: 90-100 A 80-89 B 70-79 C 60-69 D 0-59 E [root@tx3 ~] # awk '{ if ($2 >= 90 && $2 <= 100) {print $1,"A"} else if ($2 >= 80 && $2 < 90) {print $1,"B"} else if ($2 >= 70 && $2 < 80) {print $1,"C"} else if ($2 >= 60 && $2 < 70) {print $1,"D"} else {print $1,"E"} }' cj tx A tx1 B tx2 C tx3 B tx4 C tx5 C (3)循环 while 语法: 'var=初值;while (表达式){动作1;...更新变量的动作;}' 例: [root@tx3 ~] # awk -F: '{i=1; while (i<=NF) {print $i;i++}}' p1 | head -7 root x 0 0 root /root /bin/bash 例. 方法一 [root@tx3 ~] # awk -F: '{i=NF; while (i>=2) {printf $i ":";i--};print $1}' p1 /bin/bash : /root :root:0:0:x:root /sbin/nologin : /bin :bin:1:1:x:bin /sbin/nologin : /sbin :daemon:2:2:x:daemon /sbin/nologin : /var/adm :adm:4:3:x:adm 例. 方法二 [root@tx3 ~] # awk 'BEGIN { FS=":" } { i=NF; while (i>=2) {printf $i ":";i--} print $1}' p1 /bin/bash : /root :root:0:0:x:root /sbin/nologin : /bin :bin:1:1:x:bin /sbin/nologin : /sbin :daemon:2:2:x:daemon (4) for 循环 语法: { for (表达式) {动作1;...} } 表达式:分为3部分: (1)初始化表达式 i=1 (2)测试表达式 i<10 (3)更新测试表达式 i++ 语句: next 处理输入行的下一个输入行 exit 退出 continue 结束本次循环 break 跳出循环 例 [root@tx3 ~] # awk 'BEGIN {FS=":"} {for(i=NF;i>=2;i--) {printf $i ";"};print $1}' p1 /bin/bash ; /root ;root;0;0;x;root /sbin/nologin ; /bin ;bin;1;1;x;bin /sbin/nologin ; /sbin ;daemon;2;2;x;daemon /sbin/nologin ; /var/adm ;adm;4;3;x;adm 例 [root@tx3 ~] # cat num 2 8 9 8 4 6 3 5 7 [root@tx3 ~] # awk '{ max=0; i=1; while (i<=NF) { if (max<$i) {max=$i} i++} print max}' num 9 8 7 (5) awk 数组 例 例 使用变量作为数组下标 另外一种读取方式(这种是无序的,j是变量,a是数组) 数组有序 (6)函数 @1split 切割字符串 split ( "等待被切割的字符串" ,数组名, "切割用的分隔符" ) [root@tx3 ~] # awk 'BEGIN{split("2012/08/23",da,"/");print da[2],da[3],da[1]}' 08 23 2012 @2toupper() 小写转大写 tolower() 大写转小写 [root@tx3 ~] # awk '{print toupper($0)}' p1 |head -3 ROOT:X:0:0:ROOT: /ROOT : /BIN/BASH BIN:X:1:1:BIN: /BIN : /SBIN/NOLOGIN DAEMON:X:2:2:DAEMON: /SBIN : /SBIN/NOLOGIN @3sub() 局部替换 gsub() 全局替换 sub(/要替换的内容/, "替换成什么内容" ) gsub(/要替换的内容/, "替换成什么内容" ) gsub(/要替换的内容/, "替换成什么内容" ,指定字段如$7) 例: [root@tx3 ~] # awk -F: '{sub(/root/,"r00t");print}' p1 r00t:x:0:0:root: /root : /bin/bash 例: [root@tx3 ~] # awk -F: '{gsub(/root/,"r00t");print}' p1 r00t:x:0:0:r00t: /r00t : /bin/bash operator:x:11:0:operator: /r00t : /sbin/nologin 例: [root@tx3 ~] # awk -F[:/] '{gsub(/root/,"r00t",$7);print}' p1 root x 0 0 root r00t bin bash operator x 11 0 operator r00t sbin nologin @4.length() 计算字符串的长度 [root@tx3 ~] # awk -F: '{print length($1),$1}' p1 4 root 3 bin 6 daemon 3 adm @5. 数学计算 [root@tx3 ~] # awk 'BEGIN{print sin(30)}' -0.988032 [root@tx3 ~] # awk 'BEGIN{print cos(60)}' -0.952413 [root@tx3 ~] # awk 'BEGIN{print int(22/6)}' 3 [root@tx3 ~] # awk 'BEGIN{print sqrt(3)}' 1.73205 awk -F ':' '{print $1"\t"$7}' 账户和账户对应的shell,而账户与 awk 'NR==3' 读取第三行 awk '{print $NF}' 最后一列 awk 'NF>0 {print $0}' uptime.sh 去掉空行 awk '/SSH/' file .txt 查询包含SSH的行 awk '/SSH/ {print $1}' file .txt 查询包含SSH的行打印第一列 awk -F: '/SSH/ {print $1}' file .txt awk -F: '/SSH/ {print $1; print $2}' file .txt 每个字段单独打印一行 查看服务器连接状态并汇总 netstat -an| awk '/^tcp/{++s[$NF]}END{for(a in s)print a,s[a]}' sed '1~2N;s#\n#\t#' ip.txt | awk '{a[$1]=a[$1]?a[$1]","$2:$2} END{for(i in a)print i,a[i]}' awk 取奇数行 awk 'if{if(NR%2==0)}{print NR}' file awk 'NR%2' file awk '++i%2' file awk 取偶数行 awk 'if{if(NR%2==1)}{print NR}' file awk '!(NR%2)' file awk 'i++%2' file |
如对您有帮助,支持下呗!
微信

支付宝

【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· AI与.NET技术实操系列(六):基于图像分类模型对图像进行分类