Shell手册-awk

资料来源

awk知识点总结 | 骏马金龙
精通awk系列 | 骏马金龙
linux awk 命令使用详解 | 元宇宙-Metaverse
Linux awk 命令 | runoob

基础知识

格式化文本文件,对文本文件进行更复杂的加工处理、分析
Awk自动地搜索输入文件,并把每一个输入行切分成字段。许多工作都是自动完成的,例如读取每个输入行、字段分割、存储管理、初始化等。在AWK中不需声明变量数据类型,它内置字符串类型和数值类型。

awk [选项参数] 'script' var=value file(s)

awk [选项参数] -f scriptfile var=value file(s)

awk -F':' '$7 == "/bin/bash"{print "who use bash shell: ",$1}' /etc/passwd
这个 awk 命令用于查找使用 bash shell 的用户。下面是具体解释:

  • -F':' 表示使用冒号作为字段分隔符。
  • $7 == "/bin/bash" 表示匹配第 7 个字段等于 /bin/bash 的行。
  • {print "who use bash shell: ",$1} 表示打印符合条件的行的第 1 个字段,即用户名,以及带提示信息的字符串 "who use bash shell: "。
  • /etc/passwd 是需要处理的文件路径。
    假设有一个 /etc/passwd 文件,内容如下:
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
testuser:x:1000:1000:testuser:/home/testuser:/bin/bash

结果如下:

who use bash shell: root
who use bash shell: testuser

可以看到,输出了使用 bash shell 的用户,即root和testuser。

(指定一个符号或者正则为分隔字段的标志(-F':'),设定好匹配字段需要匹配的文本。用大括号区分执行命令,输入执行要求和字段(如{print $1,$2}),最后输入需要匹配文本的文件。)

如果action为print $1 $5,则结果会将"$1"和"$5"拼接在一起,因为空格是AWK中的拼接字符。例如变量赋值name = "abc" "bcd"等价于name="abcbcd"。其实不算是拼接符,而是因为awk会忽略任何不被引号包围的空白。

选项参数

  • -F--field-separator:指定字段分隔符,默认使用空格或制表符作为分隔符。
  • -v--assign:定义变量并赋值。
  • -f--file:指定 awk 脚本文件。
  • -W--word-regexp:指定模式匹配时,只匹配整个单词而不是单词片段。
  • -i--ignore-case:忽略大小写进行匹配。
  • -v--version:显示 awk 版本信息。
  • -h--help:显示 awk 帮助信息。
  • -c--traditional:使用传统 awk 语法模式。
  • -m--bignum:支持大整数运算。
  • -M--non-decimal-data:支持八进制和十六进制数值。
  • -S--sandbox:启用沙箱模式。
  • -Wlint:启用警告模式,检查 awk 脚本中的潜在问题。
  • -Wposix:启用 POSIX 兼容模式。
  • -Wsource:显示 awk 脚本的源代码。
  • -Wno-xxx:禁用某个警告或特性。
  • -Werror=xxx:将某个警告视为错误。
  • -Wfatal-errors:任何警告都将视为致命错误。
  • -Wp,-xxx:传递预处理器选项给 awk
  • -Wp,-Dxxx:定义预处理器宏。
  • -Wp,-Uxxx:取消定义预处理器宏。
  • -Wp,-Ixxx:指定预处理器头文件搜索路径。
  • -Wp,-H:显示预处理器搜索路径。
  • -Wp,-P:不使用预处理器。
  • -Wp,-C:不将注释传递给预处理器。
  • -Wp,-w:关闭所有预处理器警告。
  • -Wp,-pedantic:启用严格的 ANSI C 标准模式。
  • -Wp,-traditional-cpp:使用传统 C 风格的预处理器。
  • -Wp,-traditional-cpp-defined:使用传统 C 风格的宏定义方式。
  • -Wp,-trigraphs:启用三字符解释模式。
  • -Wp,-undef:启用未定义宏警告。
  • -Wp,-nostdinc:不使用标准头文件搜索路径。
  • -Wp,-nostdlib:不使用标准库搜索路径。
  • -Wp,-nostddefs:不使用标准宏定义。

工作流程

AWK 工作流程可分为三个部分:

  • 读输入文件之前执行的代码段(由BEGIN关键字标识)。
  • 主循环执行输入文件的代码段。
  • 读输入文件之后的代码段(由END关键字标识)。

awk 'BEGIN{ commands } pattern{ commands } END{ commands }'

  1. 通过关键字 BEGIN 执行 BEGIN 块的内容,即 BEGIN 后花括号 {} 的内容。
  2. 完成 BEGIN 块的执行,开始执行body块。
  3. 读入有 \n 换行符分割的记录。
  4. 将记录按指定的域分隔符划分域,填充域,$0 则表示所有域(即一行内容),$1 表示第一个域,$n 表示第 n 个域。
  5. 依次执行各 BODY 块,pattern 部分匹配该行内容成功后,才会执行 awk-commands 的内容。
  6. 循环读取并执行各行直到文件结束,完成body块执行。
  7. 开始 END 块执行,END 块可以输出最终结果。
BEGIN{actions}
END{actions}
expr{actions}
/regexp/{actions}:可被regexp匹配的行才执行actions
expr1,expr2{actions}:表示范围,从满足expr1的行开始,到满足expr2的行结束

awk处理文本内容模式

  • awk默认以空格为分隔符,且多个空格也识别为一个空格,作为分隔符;
  • awk按行处理文件,一行处理完毕之后,再处理下一行;
  • awk可以根据用户指定的分隔符去工作,没有指定,则默认为空格;

格式化输出 print和printf

print对文本进行简单的输出,但是并不能美化或者修改输出格式

printf与print的几点区别:

  • printf 需要指定format
  • format 用于指定后面的每个 item输出格式
  • printf 语句不会自动打印换行符; \n ; print 默认添加换行符

准备一个txt文件
echo test{1..50} > test.txt
vim test.txt调整为如下

test1 test2 test3 test4 test5 
test6 test7 test8 test9 test10 
test11 test12 test13 test14 test15 
test16 test17 test18 test19 test20 
test21 test22 test23 test24 test25 
test26 test27 test28 test29 test30 
test31 test32 test33 test34 test35 
test36 test37 test38 test39 test40 
test41 test42 test43 test44 test45 
test46 test47 test48 test49 test50
awk '{printf $0}' test.txt

test1 test2 test3 test4 test5 test6 test7 test8 test9 test10 test11 test12 test13 test14 test15 test16 test17 test18 test19 test20 test21 test22 test23 test24 test25 test26 test27 test28 test29 test30 test31 test32 test33 test34 test35 test36 test37 test38 test39 test40 test41 test42 test43 test44 test45 test46 test47 test48 test49 test50

awk '{printf "%s\n", $0}' test.txt

test1 test2 test3 test4 test5 
test6 test7 test8 test9 test10 
test11 test12 test13 test14 test15 
test16 test17 test18 test19 test20 
test21 test22 test23 test24 test25 
test26 test27 test28 test29 test30 
test31 test32 test33 test34 test35 
test36 test37 test38 test39 test40 
test41 test42 test43 test44 test45 
test46 test47 test48 test49 test50

awk '{printf "第一列:%s   第二列:%s   第三列:%s   第四列:%s   第五列:%s\n" ,$1,$2,$3,$4,$5}' test.txt

第一列:test1   第二列:test2   第三列:test3   第四列:test4   第五列:test5
第一列:test6   第二列:test7   第三列:test8   第四列:test9   第五列:test10
第一列:test11   第二列:test12   第三列:test13   第四列:test14   第五列:test15
第一列:test16   第二列:test17   第三列:test18   第四列:test19   第五列:test20
第一列:test21   第二列:test22   第三列:test23   第四列:test24   第五列:test25
第一列:test26   第二列:test27   第三列:test28   第四列:test29   第五列:test30
第一列:test31   第二列:test32   第三列:test33   第四列:test34   第五列:test35
第一列:test36   第二列:test37   第三列:test38   第四列:test39   第五列:test40
第一列:test41   第二列:test42   第三列:test43   第四列:test44   第五列:test45
第一列:test46   第二列:test47   第三列:test48   第四列:test49   第五列:test50

分隔符

  • -F " ":默认会压缩所有前导空白,包括制表符和空格。
  • -F " :":当空格后跟一个冒号时作为分隔符。会压缩前导空格,但不会匹配制表符,更不会压缩制表符。
  • -F "[ ]':只表示一个空格,不压缩任何空白。
  • -F "|":指定竖线作为分隔符。
  • -F ",[ \t]|[ \t]+":逗号后跟0或多个空白,或者只有1或多个空白时作为分隔符。

awk内置变量

  • ARGV:命令行参数数组。从0开始计数直到ARGC-1。
  • ARGC:ARGV数组元素的个数。
  • FILENAME:当前处理的文件名。
  • FNR:当前处理文件的记录号。(file record num)
  • NR:已处理的总记录数。多个文件时不重置。(record num)
  • NF:当前记录的字段总数。(field num)
  • FS:输入的字段分隔符。默认为空白。(file separate)
  • OFS:输出的字段分隔符。默认为空白。(output record separate)
  • RS:输入流的记录分隔符。默认为"\n"。(record separate)
  • ORS:输出流的记录分隔符。默认为"\n"。(output record separate)
  • OFMT:printf输出数值转换成字符串输出时的格式。默认为"%.6g"。
  • CONVFMT:printf输出数值转换成字符串输出时的格式。会被OFMT覆盖。默认为"%.6g"。
  • RLENGTH:被match函数匹配的字符串的长度。
  • RSTART:被match函数匹配的字符串的开始位置。
  • SUBSEP:下标分隔符。默认为"\034",ASCII中034代表的是双引号'"'。

内置函数

算术函数:

  • cos(x):取x的余弦。
  • sin(x):取x的正弦。
  • sqrt(x):取x的平方根。
  • rand():返回一个随机数r,其中0<=r<1。
  • srand(x):设置rand()的种子值为x。种子值相同时,rand()的结果相同。可print srand()输出当前种子值。
  • int(x):取x的整数部分。

字符串函数:
建议下面的所有regexp都使用"//"包围。

  • index(str1,str2):返回子串str2在字符串str1中第一次出现的位置。如果没有指定str1,则返回0。
  • length(str1):返回字符串str1的长度。如果未给定str1,则表示计算"$0"的长度。
  • substr(str1,p):返回str1中从p位置开始的后缀字符串。
  • substr(str1,p,n):返回str1中从p位置开始,长度为n的子串。
  • match(str1,regexp):如果regexp能匹配str1,则返回匹配起始位置。否则返回0。它会设置内置变量RSTART和RLENGTH的值。
  • split(str1,array,sep):使用字段分隔符sep将str1分割到数组array中,并返回数组的元素个数。如果未指定sep则采用FS的值。因此该函数用于切分字段到数组中,下标从1开始。
  • sprintf(fmt,expr):根据printf的格式fmt,返回格式化后的expr。
  • sub(regexp,rep,str2):将str2中第一个被regexp匹配的字符串替换成rep,替换成功则返回1(表示替换了1次),否则返回0。注意是贪婪匹配。
  • sub(regexp,rep):将"$0"中第一个被regexp匹配的字符串替换成rep,替换成功则返回1,否则返回0。注意是贪婪匹配。
  • gsub(regexp,rep,str2):将str2中所有被regexp匹配的内容替换成rep,并返回替换的次数。
  • gsub(regexp,rep):将"$0"中所有被regexp匹配的内容替换成rep,并返回替换的次数。
  • toupper(str):将str转换成大写字母,并返回新串。
  • tolower(str):将str转换成小写字母,并返回新串。

自定义变量

awk -v var="111" 'NR==1{printf "%d %s\n",var,$0}' test.txt

111 test1 test2 test3 test4 test5

自定义函数

function name(parameter-list) {
    statements
}

流程控制语句

if (expression) statements
if (expression) statements else statements
while (expression) statements
for (expression; expression; expression) statements
for (expression in array) statements
do statements while (expression)

break # 退出循环。
continue # 退出当前循环,进入下一个循环
next # 读入下一行,并awk程序的顶端从头开始。这个awk程序是PATTERN{action}这部分,不包括BEGIN{action}。
exit code # 直接进入END,若本就在END中,则直接退出awk。如果END中的exit没有定义code,则采用前一个exit的code。
PATTERN {if (test_cmd){cmd1;cmd2;...}else {cmd3;cmd4...}}

PATTERN {
   if (test_cmd){
      cmd1
      cmd2
      ......
      }
   else
      cmd3
}

PATTERN {
    if (test_cmd){cmd_list1}
    else if {cmd_list2}
    else if {cmd_list3}
    else {cmd_list}
}
PATTERN{cmd1;while (test_cmd){cmd1;cmd2}}

PATTERN {
    cmd1
    while (test_cmd){
        cmd2
        cmd3
        ....
    }
}
PATTERN {
    do{
        cmd1
        cmd2
    } while (test_cmd)
}
PATTERN {
    for (i=1;i<=10;++i){
    cmd1
    cmd2
    }
}
posted @ 2023-06-02 22:23  Mugetsukun  阅读(38)  评论(0编辑  收藏  举报