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

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

基本语法

bash 复制代码
awk 'pattern { action }' input_file

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

示例

打印所有行
bash 复制代码
awk '{print}' filename

或简单地

bash 复制代码
awk 1 filename

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

打印第一列
bash 复制代码
awk '{print $1}' filename

$1 表示第一列。

打印第1~7列

bash 复制代码
[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

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

bash 复制代码
[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 的上下文中并未被利用)

bash 复制代码
[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,然后处理记录。这里是修改后的命令:

bash 复制代码
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 会按照指定的字段数打印出内容,对于不存在的字段,它会打印空字符串。

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

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

过滤特定行

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

bash 复制代码
awk '$2 > 10 {print}' filename
bash 复制代码
[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 块
bash 复制代码
awk 'BEGIN {print "Start processing file..."} {print} END {print "File processing complete."}' filename

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

bash 复制代码
[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
使用外部变量
bash 复制代码
awk -v var=100 '{if ($1 > var) print $0}' filename

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

进阶用法

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

注意事项

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

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

相关推荐
记得开心一点嘛13 分钟前
在Linux系统上使用Docker部署javaweb项目
linux·运维·docker
Tak1Na39 分钟前
2024.9.18
linux·运维·服务器
A^mber44 分钟前
828华为云征文|云服务器Flexus X实例|Ubunt部署Vue项目
运维·服务器·华为云
安得权1 小时前
Ubuntu 20.04 部署 NET8 Web - Systemd 的方式 达到外网访问的目的
linux·前端·ubuntu
让学习成为一种生活方式1 小时前
解析药用植物重楼甾体皂苷生物合成中的连续糖基化及其抗真菌作用-文献精读49
linux·数据库·算法·天然产物化学
凯哥是个大帅比2 小时前
ubuntu20.04 GLIBC从2.35降级到2.31
linux
iHero2 小时前
【Ubuntu】在 Ubuntu 22.04.3 LTS 安装 davfs2 通过 Nextcloud WebDAV 挂载到 Ubuntu 的目录上
linux·ubuntu·nextcloud
清园暖歌2 小时前
Ubuntu 不重装系统增加交换空间大小
linux·运维·ubuntu·交换空间
黎相思2 小时前
操作系统迁移(CentOs -> Ubuntu)
linux·ubuntu·gitee·centos
写bug如流水2 小时前
在Ubuntu 20.04上安装pgAdmin 4
linux·运维·ubuntu