Linux 和 Unix 系统中非常流行文本处理工具awk

avatar
作者
猴君
阅读量:0

awk 是一种强大的文本处理工具,在 Linux 和 Unix 系统中非常流行。它主要用于模式扫描和处理语言,可以读取输入文件、为数据行中的字段指定操作,并基于这些操作输出数据。awk 程序通常由一系列的模式和动作对组成,模式指定了哪些数据行应被处理,而动作则定义了在这些行上应执行的操作。

基本语法

awk 'pattern { action }' input_file  用法:awk [options]{print NR,$0}file -F   指定字段分隔符 NR   表示行号 $0   表示这一行的内容 $1   数字 某一列 $NF  最后一列  
  • pattern:是可选的,用于指定哪些行应该被处理。如果省略,则处理所有行。
  • { action }:是必需的,定义了当行匹配模式时应该执行的操作。
  • input_file:指定输入文件名。如果省略,则从标准输入读取数据。

示例

打印所有行
awk '{print}' filename 

或简单地

awk 1 filename 

这里,1 被视为总是为真的模式,因此所有行都会被打印。

打印第一列
awk '{print $1}' filename 

$1 表示第一列。

打印第1~7列

[root@localhost ~]# head -10 /etc/passwd | awk -F ":" '{print $1,$2,$3,$4,$5,$6,$7}' root x 0 0 root /root /bin/bash bin x 1 1 bin /bin /sbin/nologin daemon x 2 2 daemon /sbin /sbin/nologin adm x 3 4 adm /var/adm /sbin/nologin lp x 4 7 lp /var/spool/lpd /sbin/nologin sync x 5 0 sync /sbin /bin/sync shutdown x 6 0 shutdown /sbin /sbin/shutdown halt x 7 0 halt /sbin /sbin/halt mail x 8 12 mail /var/spool/mail /sbin/nologin operator x 11 0 operator /root /sbin/nologin  

打印当前记录(即整行)的内容

[root@localhost ~]# head -10 /etc/passwd | awk -F ":" '{print $0}' root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin adm:x:3:4:adm:/var/adm:/sbin/nologin lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin sync:x:5:0:sync:/sbin:/bin/sync shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown halt:x:7:0:halt:/sbin:/sbin/halt mail:x:8:12:mail:/var/spool/mail:/sbin/nologin operator:x:11:0:operator:/root:/sbin/nologin 

整个命令 head -10 /etc/passwd | awk -F “:” ‘{print $0}’ 的效果其实与仅执行 head -10 /etc/passwd 相同,因为 awk 命令在这里并没有对每行文本进行任何实质性的处理(除了指定了字段分隔符,但这个分隔符在 print $0 的上下文中并未被利用)

[root@localhost ~]# head -10 /etc/passwd | awk  '{FS=":"}{print $1,$2,$3,$4,$5,$6,$7}' root:x:0:0:root:/root:/bin/bash       bin x 1 1 bin /bin /sbin/nologin daemon x 2 2 daemon /sbin /sbin/nologin adm x 3 4 adm /var/adm /sbin/nologin lp x 4 7 lp /var/spool/lpd /sbin/nologin sync x 5 0 sync /sbin /bin/sync shutdown x 6 0 shutdown /sbin /sbin/shutdown halt x 7 0 halt /sbin /sbin/halt mail x 8 12 mail /var/spool/mail /sbin/nologin operator x 11 0 operator /root /sbin/nologin 

在您提供的命令 head -10 /etc/passwd | awk '{FS=":"}{print $1,$2,$3,$4,$5,$6,$7}' 中,存在一个常见的 awk 使用误区。FS(字段分隔符)应该在处理任何记录之前设置,而不是在每条记录的处理块中单独设置。当您在 {FS=":"} 这样的代码块中设置 FS 时,它实际上对已经读取到当前记录(即行)没有影响,因为 awk 在读取记录时就已经决定了如何根据 FS 分割这条记录。

因此,您的命令实际上不会按预期工作,因为它在尝试打印字段时并没有正确地使用冒号作为字段分隔符。

正确的做法是在 awk 程序开始时就设置 FS,然后处理记录。这里是修改后的命令:

head -10 /etc/passwd | awk -F: '{print $1, $2, $3, $4, $5, $6, $7}' 

注意,我已经将 -F: 直接传递给了 awk 命令,而不是在 awk 程序内部设置 FS。这样做可以在 awk 读取每行之前就将冒号设置为字段分隔符。

这个命令将输出 /etc/passwd 文件前10行中每行的前七个字段(如果存在的话)。这些字段通常包括用户名、密码占位符(通常是 x,表示密码存储在 /etc/shadow 中)、用户ID(UID)、组ID(GID)、用户全名或注释、家目录和登录Shell。不过,请注意,并非所有用户的记录都会有七个字段,特别是如果用户全名或注释字段为空或不存在时。但是,awk 会按照指定的字段数打印出内容,对于不存在的字段,它会打印空字符串。

对每行的第一个字段求和
awk '{sum += $1} END {print sum}' filename 

这个命令会遍历文件中的每一行,将第一列的值累加到变量 sum 中,并在处理完所有行后打印总和。

过滤特定行

打印文件中第二列值大于 10 的所有行:

awk '$2 > 10 {print}' filename 
[root@localhost ~]# vi score.txt Marry   2143 78 84 77 Jack    2321 66 78 45 Tom     2122 48 77 71 Mike    2537 87 97 95 Bob     2415 40 57 62 Bigmao  8899 99 100 98  -- 计算总成绩shell角本 vi cat_call.awk #!/bin/awk -f #运行前 BEGIN {     math = 0     english = 0     computer = 0     printf "NAME    NO.   MATH  ENGLISH  COMPUTER   TOTAL\n"     printf "---------------------------------------------\n" } #运行中 {     math+=$3     english+=$4     computer+=$5     printf "%-6s %-6s %4d %8d %8d %8d\n", $1, $2, $3,$4,$5, $3+$4+$5 } #运行后 END {     printf "---------------------------------------------\n"     printf "  TOTAL:%10d %8d %8d \n", math, english, computer     printf "AVERAGE:%10.2f %8.2f %8.2f\n", math/NR, english/NR, computer/NR }  [root@localhost ~]# awk -f cat_call.awk score.txt NAME    NO.   MATH  ENGLISH  COMPUTER   TOTAL --------------------------------------------- Marry  2143     78       84       77      239 Jack   2321     66       78       45      189 Tom    2122     48       77       71      196 Mike   2537     87       97       95      279 Bob    2415     40       57       62      159 Bigmao 8899     99      100       98      297 ---------------------------------------------   TOTAL:       418      493      448  AVERAGE:     69.67    82.17    74.67 
使用 BEGIN 和 END 块
awk 'BEGIN {print "Start processing file..."} {print} END {print "File processing complete."}' filename 

BEGIN 块在处理任何输入行之前执行,而 END 块在所有输入行处理完毕后执行。

[root@localhost ~]# head -10 /etc/passwd | awk  'BEGIN{FS=":";OFS="****"}{print $1,$2,$3,$4,$5,$6,$7}' root****x****0****0****root****/root****/bin/bash bin****x****1****1****bin****/bin****/sbin/nologin daemon****x****2****2****daemon****/sbin****/sbin/nologin adm****x****3****4****adm****/var/adm****/sbin/nologin lp****x****4****7****lp****/var/spool/lpd****/sbin/nologin sync****x****5****0****sync****/sbin****/bin/sync shutdown****x****6****0****shutdown****/sbin****/sbin/shutdown halt****x****7****0****halt****/sbin****/sbin/halt mail****x****8****12****mail****/var/spool/mail****/sbin/nologin operator****x****11****0****operator****/root****/sbin/nologin  [root@localhost ~]# head -10 /etc/passwd | awk  'BEGIN{FS=":"}{print $NF}' /bin/bash /sbin/nologin /sbin/nologin /sbin/nologin /sbin/nologin /bin/sync /sbin/shutdown /sbin/halt /sbin/nologin /sbin/nologin 
使用外部变量
awk -v var=100 '{if ($1 > var) print $0}' filename 

这里,-v var=100 定义了一个名为 var 的外部变量,并将其值设置为 100。然后,在 awk 程序内部使用这个变量来比较第一列的值。

进阶用法

awk 还可以进行更复杂的文本处理,如字符串操作、数组使用、自定义函数等。这些功能使得 awk 成为处理文本数据的强大工具。

注意事项

  • 字段默认由空格或制表符分隔。可以通过 -F 选项更改字段分隔符。
  • awk 程序中的 { action } 可以包含多个语句,语句之间用分号分隔。
  • 变量名区分大小写。

awk 的功能远不止于此,通过结合其内置函数和灵活的语法,你可以完成几乎任何文本处理任务。

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!