【Linux进阶命令 02】awk(更加强大的文本分析工具)

简介: 【Linux进阶命令 02】awk(更加强大的文本分析工具)

文章目录

一、awk和grep比较

二、awk语法

三 awk变量

四、awk简单使用示例

4.1 分割文本

4.2 搜索并替换文本

4.3 数值计算

五、使用awk脚本

5.1 awk脚本的基本用法

5.2 进阶知识点

5.21 awk语句

5.22 awk运算

5.23 awk高级输入输出

5.24 awk函数

5.3 复杂awk脚本示例

六、为什么使用awk


awk是一种基于文本的编程语言,也是一种强大的文本处理工具。它通常用于批处理、文本挖掘和数据处理等任务,尤其对于需要对大型文件进行处理的情况,awk的速度和效率很高。awk提供了多种内置功能,例如:处理和转换文本、过滤器、数据匹配、聚合和计算等等,使得它可以快速处理大量的数据,灵活性是awk最大的优势。awk经过改进生成的新的版本nawk,gawk,现在默认linux系统下日常使用的是gawk。


一、awk和grep比较

上一篇文章已经介绍过grep:【Linux进阶命令 01】grep(文本的全局搜索与打印)

grep是一种基于模式匹配的搜索工具,可以帮助用户在文本文件中查找特定的字符串。grep可以很容易地筛选出某个字符串,从而快速筛选出满足条件的行,并将其输出到终端或另一个文件中。grep的优点是简单易用,用法非常简单。 缺点是 grep 只能进行过滤和搜索,不能进行更复杂的操作。


awk除了支持查找和过滤文本之外,还提供了更强大的功能。Awk可以命令行式组织和操作数据,例如分割文件单元、替换文本、进行计算、格式化输出等等。Awk还拥有更强大的处理和过滤文本的能力,包括使用正则表达式进行高级匹配,将多个文件或变量连接,从不同数据源聚合数据,从文本字段中提取数据等。Awk就像一种专门用于文本处理的程序语言,可以轻松处理数据文件中的各种计算和逻辑操作。


二、awk语法

awk命令的基本语法如下:

awk [选项] 'pattern {action}' [文件名]

常用的awk选项:


-F 指定字段分隔符。

-f 指定awk脚本文件。

-v 定义变量。

pattern表示匹配的模式,也即文本搜索条件,可以是字符串或者正则表达式,如果匹配成功,则会执行接下来的action命令。


awk命令中action命令非常灵活,可以是任何有效的awk语句,例如:


print 打印指定内容。

printf 格式化输出。

if-else 条件语句。

while 循环语句。

getline 读取下一行输入。


三 awk变量

AWK变量有以下几种:


1.内置变量:内置变量是由AWK本身定义的变量,例如FS,RS等。


2.用户自定义变量:用户自定义变量是由用户自己定义的变量,可以用来存储数据、计算结果等。


3.环境变量:环境变量是由操作系统提供的变量,可以被AWK程序访问和使用。


4.命令行参数变量:命令行参数变量是在执行AWK程序时通过命令行传递的变量,一般用来指定文件名、分隔符等参数。


5.数组变量:数组变量是AWK中一种特殊的变量类型,可以用来存储多个值,可以通过下标来访问数组中的元素。

常用的是内置变量:

  • $0:表示整个记录。
  • $1:表示第一个字段。(即第一列)
  • $2:表示第二个字段。
  • …:以此类推。
  • NF:表示当前记录中的字段数。(列数)
  • NR:表示已经读出的记录数。(行数)
  • FS:表示输入字段分隔符。
  • RS:表示输入记录分隔符。
  • OFS:表示输出字段分隔符。
  • ORS:表示输出记录分隔符。


更多:

$n : 当前记录的第n个字段,比如n为1表示第一个字段,n为2表示第二个字段。

$0 : 这个变量包含执行过程中当前行的文本内容。

ARGC : 命令行参数的数目。

ARGIND : 命令行中当前文件的位置(从0开始算)。

ARGV : 包含命令行参数的数组。

CONVFMT : 数字转换格式(默认值为%.6g)。

ENVIRON : 环境变量关联数组。

ERRNO : 最后一个系统错误的描述。

FIELDWIDTHS : 字段宽度列表(用空格键分隔)。

FILENAME : 当前输入文件的名。

NR : 表示记录数,在执行过程中对应于当前的行号

FNR : 同NR :,但相对于当前文件。

FS : 字段分隔符(默认是任何空格)。

IGNORECASE : 如果为真,则进行忽略大小写的匹配。

NF : 表示字段数,在执行过程中对应于当前的字段数。 print $NF答应一行中最后一个字段

OFMT : 数字的输出格式(默认值是%.6g)。

OFS : 输出字段分隔符(默认值是一个空格)。

ORS : 输出记录分隔符(默认值是一个换行符)。

RS : 记录分隔符(默认是一个换行符)。

RSTART : 由match函数所匹配的字符串的第一个位置。

RLENGTH : 由match函数所匹配的字符串的长度。

SUBSEP : 数组下标分隔符(默认值是34)。


四、awk简单使用示例

和grep一样,awk不会修改源文件内容。

data.txt文件内容(最左边是vim的行号,不是文件内容):

  1 活度0.7mCi粒子数,D90,活度0.8mCi粒子数,D90
  2 5,393.6,5,502.4
  3 10,1355.5,10,1497.3
  4 15,1869.7,15,2092.2
  5 20,2309.6,20,2635.8
  6 25,2815.4,25,3355.5
  7 30,3324.7,30,4300
  8 35,4094.2,35,5508.3
  9 40,4940.2,40,7560.6
 10 45,6097.5,45,9708
 11 50,7620.1,50,12203.7
 12 55,8720.4,,
 13 60,10899.8,,
 14 65,12453.7,,

下面使用awk对上述文件进行一些操作。

4.1 分割文本

从上述用逗号分隔的文件中提取第1列数据:

awk -F "," '{print $1}' data.txt

输出:

root@CQUPTLEI:~/Linux_test# awk -F "," '{print $1}' data.txt
活度0.7mCi粒子数
5
10
15
20
25
30
35
40
45
50
55
60
65

这里:选项是-F,pattern为空,action是print $1

4.2 搜索并替换文本

文件中查找所有包含15这个数字的行,并将它们替换为-1:

awk '/15/ {gsub(/\<15\>/,-1)}; /-1/' data.txt

输出:

root@CQUPTLEI:~/Linux_test# awk '/15/ {gsub(/\<15\>/,-1)}; /-1/' data.txt
-1,1869.7,-1,2092.2

这里,选项为空,pattern为正则表达式:/15/ {gsub(/\<15\>/,-1)},表示匹配含有15这个数字的行,并将所有15替换为-1.action为:/-1/,表示输出含有-1的行。gsub函数表示替换所有匹配的项,sub则只替换匹配到的第一个。

4.3 数值计算

计算文件中第一列数字的总和和平均值:

awk -F ","  '{sum+=$1} END {printf "第一列的总和为:%d,平均值为:%.2f\n",sum,sum/NR}' data.txt

输出:

root@CQUPTLEI:~/Linux_test# awk -F ","  '{sum+=$1} END {printf "第一列的总和为:%d,平均值为:%.2f\n",sum,sum/NR}' data.txt
第一列的总和为:455,平均值为:32.50

注意这里的NR

上面只是在命令行进行简单操作,但awk的功能远不止如此,还可以编写awk脚本,实现更加复杂的功能。(回想一下grep的规则文件,使用 `-f`参数)

五、使用awk脚本

5.1 awk脚本的基本用法

awk命令的-f参数用于执行指定的AWK脚本文件。通常,一个AWK脚本文件包含一个或多个AWK命令和一些描述性文本,也可以包含函数、条件语句等。

-f参数的语法如下:

awk -f scriptfile inputfile

其中,scriptfile是一个AWK脚本文件(.awk),inputfile是要处理的输入文件。

这是一个awk脚本文件:rule.awk

#!/usr/bin/awk -f
BEGIN {print "This is a test script."}
{split($0,tmp,",");print tmp[1]}
END {print"处理的行数为:", NR}

注:

第一行的#!/usr/bin/awk -f指定了该文件使用的AWK解释器和解释参数

BEGIN是一个模式,它表示在处理输入之前执行动作

同理:END是一个特殊的模式,它表示在处理完所有输入之后执行动作;

awk文件包含一个或多个awk命令。每个命令都由一个模式和一个动作组成,用大括号括起来。


也可以写成:

BEGIN {FS=","}
{split($0,a,","); print a[1]}

上面的脚本将data.txt用逗号分隔,并输出第一列,执行效果:

root@CQUPTLEI:~/Linux_test# awk -f rule.awk data.txt
This is a test script.
活度0.7mCi粒子数
5
10
15
20
25
30
35
40
45
50
55
60
65
处理的行数为: 14

这里仍然是一个简单的awk脚本,要编写功能更加复杂的awk脚本,还需要学习更多awk知识。

5.2 进阶知识点

awk还是一种编程语言,前面已经介绍过awk变量,本节将接收awk函数、运算、语句等。

5.21 awk语句

(1) for循环

for(变量 in 数组)  
{语句} 
for(变量;条件;表达式) 
{语句} 

(2)while循环

while(表达式) 
    {语句} 

(3) do…while循环

do  
{语句} while(条件) 

其他相关语句

  • break:退出程序循环
  • continue: 进入下一次循环
  • next:读取下一个输入行
  • exit:退出主输入循环,进入END,若没有END或END中有exit语句,则退出脚本。


5.22 awk运算

  • 算术运算:(+,-,*,/,&,!,……,++,–)

所有用作算术运算符进行操作时,操作数自动转为数值,所有非数值都变为0

  • 赋值运算:(=, +=, -=,*=,/=,%=,……=,**=)
  • 逻辑运算符: (||, &&)
  • 关系运算符:(<, <=, >,>=,!=, ==)
  • 正则运算符:(~,~!)(匹配正则表达式,与不匹配正则表达式)


   awk 'BEGIN{a="100testa";if(a ~ /^100*/){print "ok";}}'
   ok

5.23 awk高级输入输出

读取下一条记录:next 语句

awk中next语句使用:在循环逐行匹配,如果遇到next,就会跳过当前行,直接忽略下面语句。而进行下一行匹配。next语句一般用于多行合并:

root@CQUPTLEI:~/Linux_test# awk 'NR%2==1{next}{print NR,$0;}' data.txt
2 5,393.6,5,502.4
4 15,1869.7,15,2092.2
6 25,2815.4,25,3355.5
8 35,4094.2,35,5508.3
10 45,6097.5,45,9708
12 55,8720.4,,
14 65,12453.7,,

说明: 跳过奇数行。下面的print NR,$0也不会执行。下一行开始,程序继续判断NR%2值。这个时候记录行号是偶数 ,就会执行下面语句块:`print NR,$0


读取一行记录:getline 语句


awk getline用法:输出重定向需用到getline函数。getline从标准输入、管道或者当前正在处理的文件之外的其他输入文件获得输入。它负责从输入获得下一行的内容,并给NF,NR和FNR等内建变量赋值。如果得到一条记录,getline函数返回1,如果到达文件的末尾就返回0,如果出现错误,例如打开文件失败,就返回-1。

语法格式:getline var 变量var包含了特定行的内容

用法说明:

当其左右无重定向符时|,<时:getline作用于当前文件,读入当前文件的第一行给其后跟的变量var或$0(无变量),应该注意到,由于awk在处理getline之前已经读入了一行,所以getline得到的返回结果是隔行的。

当其左右有重定向符时|,<时:getline则作用于定向输入文件,由于该文件是刚打开,并没有被awk读入一行,只是getline读入,那么getline返回的是该文件的第一行,而不是隔行。


5.24 awk函数

(1)算术函数

格式 描述
atan2( y, x ) 返回 y/x 的反正切。
cos( x ) 返回 x 的余弦;x 是弧度。
sin( x ) 返回 x 的正弦;x 是弧度。
exp( x ) 返回 x 幂函数。
log( x ) 返回 x 的自然对数。
sqrt( x ) 返回 x 平方根。
int( x ) 返回 x 的截断至整数的值。
rand( ) 返回任意数字 n,其中 0 <= n < 1。
srand( [expr] ) 将 rand 函数的种子值设置为 Expr 参数的值,或如果省略 Expr 参数则使用某天的时间。返回先前的种子值。

(2)字符串函数

格式 描述
gsub( Ere, Repl, [ In ] ) 除了正则表达式所有具体值被替代这点,它和 sub 函数完全一样地执行。
sub( Ere, Repl, [ In ] ) 用 Repl 参数指定的字符串替换 In 参数指定的字符串中的由 Ere 参数指定的扩展正则表达式的第一个具体值。sub 函数返回替换的数量。出现在 Repl 参数指定的字符串中的 &(和符号)由 In 参数指定的与 Ere 参数的指定的扩展正则表达式匹配的字符串替换。如果未指定 In 参数,缺省值是整个记录($0 记录变量)。
index( String1, String2 ) 在由 String1 参数指定的字符串(其中有出现 String2 指定的参数)中,返回位置,从 1 开始编号。如果 String2 参数不在 String1 参数中出现,则返回 0(零)。
length [(String)] 返回 String 参数指定的字符串的长度(字符形式)。如果未给出 String 参数,则返回整个记录的长度($0 记录变量)。
blength [(String)] 返回 String 参数指定的字符串的长度(以字节为单位)。如果未给出 String 参数,则返回整个记录的长度($0 记录变量)。
substr( String, M, [ N ] ) 返回具有 N 参数指定的字符数量子串。子串从 String 参数指定的字符串取得,其字符以 M 参数指定的位置开始。M 参数指定为将 String 参数中的第一个字符作为编号 1。如果未指定 N 参数,则子串的长度将是 M 参数指定的位置到 String 参数的末尾 的长度。
match( String, Ere ) 在 String 参数指定的字符串(Ere 参数指定的扩展正则表达式出现在其中)中返回位置(字符形式),从 1 开始编号,或如果 Ere 参数不出现,则返回 0(零)。RSTART 特殊变量设置为返回值。RLENGTH 特殊变量设置为匹配的字符串的长度,或如果未找到任何匹配,则设置为 -1(负一)。
tolower( String ) 返回 String 参数指定的字符串,字符串中每个大写字符将更改为小写。大写和小写的映射由当前语言环境的 LC_CTYPE 范畴定义。
toupper( String ) 返回 String 参数指定的字符串,字符串中每个小写字符将更改为大写。大写和小写的映射由当前语言环境的 LC_CTYPE 范畴定义。
sprintf(Format, Expr, Expr, . . . ) 根据 Format 参数指定的 printf 子例程格式字符串来格式化 Expr 参数指定的表达式并返回最后生成的字符串。

说明: Ere都可以是正则表达式。

(3)时间函数

格式 描述
mktime( YYYY MM dd HH MM ss[ DST]) 生成时间格式
strftime([format [, timestamp]]) 格式化时间输出,将时间戳转为时间字符串 具体格式,见下表.
systime() 得到时间戳,返回从1970年1月1日开始到当前时间(不计闰年)的整秒数

5.3 复杂awk脚本示例

还是前文的data.txt文件:写一个awk脚本,将第一列数据中小于30的数据替换文这一列的平均值;将第二列中的数字的小数部分去掉,将第3、4列中缺失的数据用0补全。最后输出修改后的文件以及文件的行数和列数

rule2.awk:

#!/bin/awk -f
BEGIN {
    FS=",";
    OFS=FS;
    avg1=0;
    avg2=0;
    avg3=0;
    count=0;
}
NR==1 {
    print;
}
NR>1 {
    if ($1<30) {
        sum1+=30;
        count1++;
        $1=30;
    } else {
        sum1+=$1;
        count1++;
    }
    $2=sprintf("%.0f",$2);
    if ($2=="") {
        $2=0;
    }
    if ($3=="") {
        $3=0;
        count2++;
    } else {
        sum2+=$3;
        count2++;
    }
    if ($4=="") {
        $4=0;
        count3++;
    } else {
        sum3+=$4;
        count3++;
    }
    print;
}
END {
    avg1=sum1/count1;
    avg2=sum2/count2;
    avg3=sum3/count3;
    print "行数:" NR;
    print "列数:" NF;
}

运行:

root@CQUPTLEI:~/Linux_test# awk -f rule2.awk data.txt
活度0.7mCi粒子数,D90,活度0.8mCi粒子数,D90
30,394,5,502.4
30,1356,10,1497.3
30,1870,15,2092.2
30,2310,20,2635.8
30,2815,25,3355.5
30,3325,30,4300
35,4094,35,5508.3
40,4940,40,7560.6
45,6098,45,9708
50,7620,50,12203.7
55,8720,0,0
60,10900,0,0
65,12454,0,0
行数:14
列数:4

六、为什么使用awk

在不知道或者不掌握awk时,我们可能经常使用python(或者office、matlab等)进行文本、数据处理。

拿awk与Python做一个比较:

awk和Python都是流行的脚本语言,它们都有自己的优缺点。


awk的优点包括:

  • awk是一种非常快速和高效的文本处理工具,它可以轻松地处理大型文本文件。
  • awk具有强大的文本处理功能,包括模式匹配、正则表达式、字段分隔符等
  • awk是一种非常灵活的语言,可以轻松地编写简单的脚本来完成各种任务。


awk的缺点包括:

    awk不是一种通用编程语言,它主要用于文本处理和数据转换。

    awk的语法可能比其他编程语言更难学习和理解。

    awk不支持面向对象编程。


Python的优点包括:

    Python是一种通用编程语言,可以用于各种任务,包括Web开发、数据分析、机器学习等。

    Python具有简单易学的语法,使得它成为初学者入门编程的理想选择。

    Python有一个庞大的社区和生态系统,提供了许多有用的库和工具。


Python的缺点包括:

    Python可能比其他编程语言更慢,因为它是解释性语言。

    Python可能不如其他编程语言那么适合处理大型数据集。

    Python可能不如其他编程语言那么适合高性能计算。

很显然,awk能完成的工作,Python完全能够胜任,但在某些场合,写个awk或许更加简单、快捷(前提是你掌握awk)。


选择哪种工具取决于您要完成的任务以及您对这些工具的熟悉程度。


相关文章
|
1月前
|
Linux 网络安全 数据安全/隐私保护
Linux 超级强大的十六进制 dump 工具:XXD 命令,我教你应该如何使用!
在 Linux 系统中,xxd 命令是一个强大的十六进制 dump 工具,可以将文件或数据以十六进制和 ASCII 字符形式显示,帮助用户深入了解和分析数据。本文详细介绍了 xxd 命令的基本用法、高级功能及实际应用案例,包括查看文件内容、指定输出格式、写入文件、数据比较、数据提取、数据转换和数据加密解密等。通过掌握这些技巧,用户可以更高效地处理各种数据问题。
98 8
|
17天前
|
Linux Shell
Linux 10 个“who”命令示例
Linux 10 个“who”命令示例
45 14
Linux 10 个“who”命令示例
|
6天前
|
Ubuntu Linux
Linux 各发行版安装 ping 命令指南
如何在不同 Linux 发行版(Ubuntu/Debian、CentOS/RHEL/Fedora、Arch Linux、openSUSE、Alpine Linux)上安装 `ping` 命令,详细列出各发行版的安装步骤和验证方法,帮助系统管理员和网络工程师快速排查网络问题。
65 20
|
6天前
|
网络协议 Linux 应用服务中间件
kali的常用命令汇总Linux
kali的常用命令汇总linux
27 7
|
26天前
|
Linux 数据库
Linux中第一次使用locate命令报错?????
在Linux CentOS7系统中,使用`locate`命令时出现“command not found”错误,原因是缺少`mlocate`包。解决方法是通过`yum install mlocate -y`或`apt-get install mlocate`安装该包,并执行`updatedb`更新数据库以解决后续的“can not stat”错误。
31 9
|
24天前
|
监控 网络协议 Linux
Linux netstat 命令详解
Linux netstat 命令详解
|
1月前
|
运维 监控 网络协议
运维工程师日常工作中最常用的20个Linux命令,涵盖文件操作、目录管理、权限设置、系统监控等方面
本文介绍了运维工程师日常工作中最常用的20个Linux命令,涵盖文件操作、目录管理、权限设置、系统监控等方面,旨在帮助读者提高工作效率。从基本的文件查看与编辑,到高级的网络配置与安全管理,这些命令是运维工作中的必备工具。
119 3
|
1月前
|
存储 运维 Linux
如何在 Linux 系统中使用 envsubst 命令替换环境变量?
`envsubst` 是 Linux 系统中用于替换文本中环境变量值的实用工具。本文分三部分介绍其工作原理、使用方法及实际应用,包括配置文件替换、脚本执行中环境变量替换和动态生成文件等场景,帮助用户高效利用 `envsubst` 进行开发和运维工作。
52 4
|
1月前
|
Linux
在 Linux 系统中,`find` 命令
在 Linux 系统中,`find` 命令
36 1
|
关系型数据库 MySQL Linux
linux 的实用工具分享
做开发用Linux感觉比Windows在一些地方要好用(只是个人感觉,不想引战),在Linux中没有烦人的广告弹窗,没有动不动给你惊喜的Windows强制更新,而且Linux相对Windows要流畅,在低配的电脑上也很少卡顿.现在很多开发软件都有Linux版本,使用起来也算方便.当然,要是玩游戏等娱乐使用,还是Windows牛逼.我现在写代码基本都使用Linux.我用的Ubuntu18.04。
2072 0