4. awk 使用手册

作者@小郭

4. awk 使用手册

awk 介绍

awk 是一个强大的文本分析工具。

awk 更像一门编程语言,他可以自定义变量,有条件语句,有循环,有数组,有正则,有函数等。

awk 按行读取数据,根据给出的条件进行查找,并在找出来的行中进行操作。

awk 有三种形势,awk,gawk,nawk,平时所说的awk其实就是gawk。

awk 是其取了三位创始人 Alfred Aho,Peter Weinberger, 和 Brian Kernighan 的 Family Name 的首字符。

使用 awk 可以完成无数的任务,我们简单的罗列几条:

  • 文本处理
  • 生成格式化的文本报告
  • 运行一些简单的算术操作
  • 执行一些常见的字符串操作

awk 命令

awk 命令格式

awk [options] 'script' file(s) 
awk [options] -f scriptfile file(s) 
  1. script,定义如何处理数据。
  2. file,是 awk 处理的数据来源,awk 也可以来自其它命令的输出。
  3. -f scriptfile 从脚本文件中读取awk命令,每行都是一个独立的script

script 格式如下:

BEGIN { action }
pattern { action }
END { action }

脚本通常是被单引号或双引号包住,一个awk脚本通常由四部分组成:

  1. BEGIN { action } 语句块,awk 执行 pattern { action } 前要执行的脚本。

  2. pattern { action } 语句块,决定动作语句何时触发,可以是以下任意一种:

    • 正则表达式:使用通配符的扩展集。
    • 关系表达式:使用运算符进行操作,可以是字符串或数字的比较测试。
    • 模式匹配表达式:使用运算符~(匹配)和 ~!(不匹配)。
  3. END { action } 语句块,awk 执行 pattern { action } 后要执行的脚本。

  4. action部分,决定对数据如何处理,由一个或多个命令、函数、表达式组成,之间由换行符或分号隔开,并位于大刮号内。常见的action包括:变量或数组赋值、输出命令、内置函数、控制流语句。

BEGIN { action }pattern { action }END { action }都是可选项目。

awk 工作流

在这里插入图片描述

  • 第一步执行 BEGIN { commands } 语句块中的语句。

    在awk从输入输出流中读取行之前执行,通常在BEGIN语句块中执行如变量初始化,打印输出表头等操作。

  • 第二步:**从文件或标准输入中读取一行,然后执行 pattern { commands }语句块。**它逐行读取数据,从第一行到最后一行重复这个过程,直到读取完所有行。

    pattern语句块中的通用命令是最重要的部分,它也是可选的。如果没有提供pattern语句块,则默认执行{ print },即打印每一个读取到的行。

    {} 类似一个循环体,会对文件中的每一行进行迭代,通常将变量初始化语句放在BEGIN语句块中,将打印结果等语句放在END语句块中。

  • 第三步当读至输入流末尾时,执行 END { command }语句块。

    在awk从输入流中读取完所有的行之后执行,比如打印所有行的分析结果,它也是一个可选语句块。

awk 示例

示例文件

[root@server ~ 16:42:06]#  cat << 'EOF' > employee.txt 
1)  张三  技术部  23
2)  李四  人力部  22
3)  王五  行政部  23
4)  赵六  技术部  24
5)  朱七  客服部  23
EOF

示例1: 打印雇员信息。

[root@server ~ 16:43:25]# awk '{ print }' employee.txt 
1)  张三  技术部  23
2)  李四  人力部  22
3)  王五  行政部  23
4)  赵六  技术部  24
5)  朱七  客服部  23

示例2: 通过读取awk脚本,打印雇员信息。

[root@server ~ 16:43:57]# vim commands.awk
[root@server ~ 16:44:33]# cat commands.awk
{print}

[root@server ~ 16:44:37]# awk -f commands.awk employee.txt  
1)  张三  技术部  23
2)  李四  人力部  22
3)  王五  行政部  23
4)  赵六  技术部  24
5)  朱七  客服部  23

示例3: 输出特定隔行。

[root@server ~ 16:44:49]# awk '/张三/ {print}' employee.txt  
1)  张三  技术部  23
# 等同于
[root@server ~ 16:45:45]# awk '/张三/' employee.txt 
1)  张三  技术部  23

$0,代表整行记录。

示例4: 统计满足特定条件的记录数。

AWK 中的所有变量都不需要初始化,并且会自动初始化为 0

[root@server ~ 16:48:42]# awk '
/术/ { count=count+1 } 
END { print "Count="count }' employee.txt

运行以上代码,输出结果如下:

Count=2

示例5: 输出总长度大于 10 的行。

AWK 提供了一个内建的函数 **length(arg)∗∗用于返回字符串‘arg)** 用于返回字符串 `arg)用于返回字符串arg` 的总长度。

如果要获取某行的总长度,可以使用下面的语法:length($0)

同样的,如果要获取某列/字段的总长度,可以使用语法: length($n)

如果要判断某行的字符是否大于/小于/等于 N ,可以使用下面的语法:length($0) > N

[root@server ~ 16:48:50]# awk 'length($0)>10 { print $0 }' employee.txt

因为所有的行的总长度都大于 18,因此输出结果如下:

1)  张三  技术部  23
2)  李四  人力部  22
3)  王五  行政部  23
4)  赵六  技术部  24
5)  朱七  客服部  23

awk 综合示例

雇员信息表如下:

[root@server ~ 16:49:55]# cat employee.txt 
1)  张三  技术部  23
2)  李四  人力部  22
3)  王五  行政部  23
4)  赵六  技术部  24
5)  朱七  客服部  23

示例文件结构:

  1. 每个雇员独占一行
  2. 每个雇员都包括以下字段:序号,名字,部门,年龄
  3. 每一行的多个字段之间使用空白作为分隔符,空白分隔符一般是空格 ( ) 或者制表符 \t
问题

我们想要获得以下输入结果

序号 姓名  部门   年龄
-------------------
1)  张三  技术部  23
2)  李四  人力部  22
3)  王五  行政部  23
4)  赵六  技术部  24
5)  朱七  客服部  23
-------------------
分析

从上面的结果中可以看出,整个输出结果分为三大部分

  1. 表头

    序号 姓名  部门   年龄
    -------------------
    
  2. 数据

    每个雇员一样,且有着以下的结构

    1)  张三  技术部  23
    2)  李四  人力部  22
    3)  王五  行政部  23
    4)  赵六  技术部  24
    5)  朱七  客服部  23
    
  3. 表尾

    -------------------
    

根据我们刚刚学到的知识,AWK 程序结构分为三大部分,BEGIN 和 END 只会执行一次,看起来刚好可以用来输出表头,而 AWK 主体代码,是针对每一行执行的,因此,刚好可以用来输出数据。

解答
表头

为了输入表头,我们可以使用下面的 Shell 语句

[root@server ~ 16:49:55]#  awk '
BEGIN { printf "序号\t名字\t部门\t年龄\n-------------------\n" }'

因为表头部分不需要处理输入文件,也不需要处理输入文件中的每一行,所以 AWK 主体代码都是可以忽略的,甚至包括输入文件都是可以忽略的。

运行以上代码,输出结果如下:

序号	名字	部门	年龄
-------------------
数据

对比想要的结果和输入的文件,可以看出输出结果并并没有对每一行做特殊处理,直接显示就好

因此,只需要在 BEGIN 块后面直接添加 { print } ,添加完代码如下:

[root@server ~ 16:49:55]#  cat employee.txt | awk '
BEGIN { printf "序号\t名字\t部门\t年龄\n-------------------\n" } 
{ print }
END {printf "-------------------\n"}'

print 用命令于输出当前行。

运行以上代码,输出结果如下:

序号	名字	部门	年龄
-------------------
1)  张三  技术部  23
2)  李四  人力部  22
3)  王五  行政部  23
4)  赵六  技术部  24
5)  朱七  客服部  23
-------------------

如果把 命令写入到脚本文件中,也可以这样执行:

[root@server ~ 16:49:55]#  vim commands.awk 
BEGIN { printf "序号\t名字\t部门\t年龄\n-------------------\n" } 
{ print }
END {printf "-------------------\n"}

[root@server ~ 16:49:55]#  awk -f commands.awk employee.txt 
表尾

最后,从想要的结果中可以看出,整个结果最后还有一行虚线,这个,我们可以通过 END 语句来实现。

END 语句和 BEGIN 语句类似,我们就直接给结果了。

[root@server ~ 16:49:55]#  cat employee.txt | awk '
BEGIN { printf "序号\t名字\t部门\t年龄\n-------------------\n" } 
      { print } 
END   { printf "-------------------\n" }' 

运行以上代码,输出结果如下:

序号	名字	部门	年龄
-------------------
1)  张三  技术部  23
2)  李四  人力部  22
3)  王五  行政部  23
4)  赵六  技术部  24
5)  朱七  客服部  23
-------------------

如果把 命令写入到脚本文件中,也可以这样执行:

[root@server ~ 16:49:55]#  vim commands.awk 
BEGIN { printf "序号\t名字\t部门\t年龄\n-------------------\n" } 
      { print } 
END   { printf "-------------------\n" }

[root@server ~ 16:49:55]# awk -f commands.awk employee.txt 

awk 命令选项

–help 选项

用于输出 awk 命令的帮助信息。

[laoma@shell ~]$ awk --help
Usage: awk [POSIX or GNU style options] -f progfile [--] file ...
Usage: awk [POSIX or GNU style options] [--] 'program' file ...
POSIX options:		GNU long options: (standard)
	-f progfile		--file=progfile
	-F fs			--field-separator=fs
	-v var=val		--assign=var=val
Short options:		GNU long options: (extensions)
	-b			--characters-as-bytes
	-c			--traditional
	-C			--copyright
	-d[file]		--dump-variables[=file]
	-D[file]		--debug[=file]
	-e 'program-text'	--source='program-text'
	-E file			--exec=file
	-g			--gen-pot
	-h			--help
	-i includefile		--include=includefile
	-l library		--load=library
	-L[fatal|invalid|no-ext]	--lint[=fatal|invalid|no-ext]
	-M			--bignum
	-N			--use-lc-numeric
	-n			--non-decimal-data
	-o[file]		--pretty-print[=file]
	-O			--optimize
	-p[file]		--profile[=file]
	-P			--posix
	-r			--re-interval
	-s			--no-optimize
	-S			--sandbox
	-t			--lint-old
	-V			--version

To report bugs, see node `Bugs' in `gawk.info'
which is section `Reporting Problems and Bugs' in the
printed version.  This same information may be found at
https://www.gnu.org/software/gawk/manual/html_node/Bugs.html.
PLEASE do NOT try to report bugs by posting in comp.lang.awk,
or by using a web forum such as Stack Overflow.

gawk is a pattern scanning and processing language.
By default it reads standard input and writes standard output.

Examples:
	awk '{ sum += $1 }; END { print sum }' file
	awk -F: '{ print $1 }' /etc/passwd
-F 选项

**作用:**用于定义awk程序的分隔符。awk程序的分隔符,是用于分割同一行数据的分割符号。默认分隔符是:空格。

语法:-F fs 或者 --field-separator=fs

**示例:**打印用户名和家目录

[root@server ~ 16:52:51]# head -n1 /etc/passwd
root:x:0:0:root:/root:/bin/bash

[root@server ~ 16:52:51]# head -n1 /etc/passwd | awk -F : '{ print $1" "$6 }'
root /root
-v 选项

**作用:**用于预定义一些变量。这些预定义变量会在执行AWK 程序之前就定义好,准确的说,在 BEGIN 语句之前就已经定义。

示例:

  1. 通过 awk-v 参数,将 Shell 变量 VAR 的值传递到 awk 脚本中并使用

    [root@server ~ 16:54:42]# VAR=10000
    [root@server ~ 16:54:42]# echo | awk -v VARIABLE=$VAR '{ print VARIABLE }'
    10000
    #echo |:通过 echo 输出一个空行,作为 awk 的输入(因为 awk 默认需要读取输入才能执行 {...} 中的逻辑,空行不影响变量输出,仅触发 awk 执行)
    #$VAR:取 Shell 变量 VAR 的值(即 10000),通过 -v 传递给 awk 的 VARIABLE 变量
    
  2. 定义内部变量接收外部变量。

    [root@server ~ 16:56:24]# var1="aaa"
    [root@server ~ 16:56:24]# var2="bbb"
    [root@server ~ 16:56:24]# echo | awk '{ print v1,v2 }' v1=$var1 v2=$var2
    aaa bbb
    
    # 输入来自文件时
    [root@server ~ 16:56:24]# awk '{ print v1,v2 }' v1=$var1 v2=$var2 /etc/hostname
    aaa bbb
    
补充:后面为什么要加上文件?

直接原因:让 awk 有 “触发执行的输入”,避免脚本 “没机会运行”。

  1. awk 的执行规则(关键!)
    awk 的脚本逻辑(比如 {print v1,v2}),默认会 对每一行输入执行一次:
    如果不给 awk 传输入(既没文件,也没管道),它会一直等待终端输入(敲回车才执行),非常不实用;
    如果给 awk 传文件(比如 /etc/hostname),awk 会自动读取文件的每一行,每读一行就执行一次脚本,执行完后自动退出。
-p 选项

**作用:**用于将当前的 awk 程序代码格式化并且输出到 file 文件中。

格式:--profile[=file] 或者 -p[file]

awk默认导出的 awk 程序代码格式化代码到 awkvars 文件中。

示例:

[root@server ~ 17:03:52]# awk --profile '
BEGIN { printf"---|Header|--\n" }
{ print } 
END { printf"---|Footer|---\n" }' employee.txt > /dev/null 

运行上面的 awk 程序,awkprof.out 内容如下:

	# gawk profile, created Wed Aug 20 11:36:46 2025

	# BEGIN block(s)

	BEGIN {
		printf "---|Header|--\n"
	}

	# Rule(s)

	{
		print $0
	}

	# END block(s)

	END {
		printf "---|Footer|---\n"
	}

awk 内置变量

NR行号

NF 行中列个数

$N 第几个区域,$0整行

FS 域分隔符

示例:

在这里插入图片描述

[root@server ~ 15:37:22]# echo 0. : $(top -b -n1 |awk 'NR==1 {print $(NF-2),$(NF-1),$NF}')
0. : 0.99, 0.97, 0.79

[root@server ~ 15:41:20]# echo 1. CPU : $( cat top.out | awk 'NR==3 {print 100-$8}')
1. CPU : 33.3

[root@server ~ 15:43:10]# echo 2. Mem :$( cat top.out |awk 'NR==4  {print $8/$4}')
2. Mem :0.0407917

[root@server ~ 15:43:54]# echo 3.user :$(cat top.out |awk 'NR==1  {print $6 ,$7}')
3.user :2 users,

[root@server ~ 15:44:05]# echo 4.  : $(cat top.out |awk 'NR==2 {print $(NF-1) ,$NF }')
4. : 0 zombie



示例:
[root@server ~ 09:16:30]# df -h | grep -e '^/dev' -e Filesystem
Filesystem               Size  Used Avail Use% Mounted on
/dev/mapper/centos-root   50G  1.6G   49G   4% /
/dev/sda1               1014M  139M  876M  14% /boot
/dev/mapper/centos-home  146G   33M  146G   1% /home



[root@server ~ 10:23:30]# df -h | grep -e '^/dev' -e Filesystem | awk '{print $1"\t" $(NF-1)"\t" $NF}' | sed 's/Mounted/Use/'
Filesystem	Use	on
/dev/mapper/centos-root	4%	/
/dev/sda1	14%	/boot
/dev/mapper/centos-home	1%	/home



[root@server ~ 10:24:18]# df -h | grep -e '^/dev' -e Filesystem | awk '{print $1"\t" $(NF-1)"\t" $NF}' | sed -e  's/Mounted/Use/' -e 's/on/ Mounted/'
Filesystem	Use	 Mounted
/dev/mapper/centos-root	4%	/
/dev/sda1	14%	/boot
/dev/mapper/centos-home	1%	/home


[root@server ~ 10:25:07]# df -h | grep -e '^/dev' -e Filesystem | awk '{print $1"\t" $(NF-1)"\t" $NF}' | sed -e  's/Mounted/Use/' -e 's/on/Mounted on/'
Filesystem	Use	Mounted on
/dev/mapper/centos-root	4%	/
/dev/sda1	14%	/boot
/dev/mapper/centos-home	1%	/home

awk 运算符

运算符描述
=、+=、-=、*=、/=、%=、^=、**=**赋值运算符:**直接赋值、加赋值、减赋值、乘赋值、除赋值、求余赋值、求幂赋值
+、-、*、/、%、^、**算数运算符:**加、减、乘、除、求余、求幂
++、–**自增和自减运算符:**自增1、自减1,作为前缀或后缀
+、-**一元运算符:**一元加、一元减
<、<=、>、>=、==、!=**关系运算符:**小于、小于等于、大于、大于等于、等于、不等于
~、!~**正则表达式运算符:**匹配和不匹配
&&、||、!**逻辑运算符:**逻辑与、逻辑或、逻辑非

正则表达式运算符

AWK 支持正则表达式,而且为正则表达式提供了两种匹配方式。

匹配运算符 ~

语法:"string" ~ "patten"

AWK 使用一个 波浪线 ( ~ ) 作为正则表达式匹配运算。

匹配运算符用于在给定的字符串中查找要匹配的字符串,如果找到,则返回 true;否则返回 false。

例如下面的 awk 命令,在每一行中查找字符串 ,如果找到则输出当前行。

[root@server ~ 17:03:52]#  awk '$0 ~ "四"' employee.txt

运行上面的 awk 命令,输出结果如下

2)  李四  人力部  22
不匹配运算符 !~

语法:"string" !~ "patten"

AWK 使用一个 感叹号波浪线 ( ~ ) 作为正则表达式不匹配运算符 ( !~ ) 。

不匹配运算符用于在给定的字符串中查找要匹配的字符串,如果没有找到,则返回 true;否则返回 false。

例如下面的 awk 命令,在每一行中查找字符串 ,如果没有发现则输出当前行。

[root@server ~ 17:03:52]#  awk '$0 !~ "四"' employee.txt

运行上面的 awk 命令,输出结果如下

1)  张三  技术部  23
3)  王五  行政部  23
4)  赵六  技术部  24
5)  朱七  客服部  23
正则表达式

AWK 早早的就支持正则表达式了。

虽然支持的模式并没有 Perl 或 Python 那么强大,但是,作为行处理器,也足够使用了。

正则表达式最重要的作用,就是可以使用简单的语句完成复杂的任务。

字符描述
[…]匹配 […] 中的任意一个字符
[^…]匹配除了 […] 中字符的所有字符
[a-z]匹配所有小写字母。
[A-Z]匹配所有大写字母。
[0-9]匹配所有数字。
.匹配除换行符(\n、\r)之外的任何单个字符,相等于 [\^\n\r]
\将下一个字符标记为或特殊字符、或原义字符、或向后引用、或八进制转义符。例如, ‘n’ 匹配字符 ‘n’。‘\n’ 匹配换行符。序列 ‘\’ 匹配 “”,而 ‘(’ 则匹配 “(”。
|指明两项之间的一个选择。要匹配 |,请使用 |。

字符集

选项描述
[[:digit:]]数字: 0 1 2 3 4 5 6 7 8 9 等同于[0-9]
[[:xdigit:]]十六进制数字: 0 1 2 3 4 5 6 7 8 9 A B C D E F a b c d e f
[[:lower:]]小写字母:在 C 语言环境和ASCII字符编码中,对应于**[a-z]**
[[:upper:]]大写字母:在 C 语言环境和ASCII字符编码中,对应于[A-Z]
[[:alpha:]]字母字符:[[:lower:]和[[:upper:]];在C语言环境和ASCII字符编码中,等同于**[A-Za-z]**
[[:alnum:]]字母数字字符:[:alpha:]和[:digit:];在C语言环境和ASCII字符编码中,等同于**[0-9A-Za-z]**
[[:blank:]]或者[[:space:]]空白字符:在 C 语言环境中,它对应于制表符、换行符、垂直制表符、换页符、回车符和空格。
[[:punct:]]标点符号:在C语言环境和ASCII字符编码中,它对应于!" # $ % &'()*+,-./:;<=>?@[]^_`{|}~
[[:print:]]或者 [[:graph:]]可打印字符: [[:alnum:]]、[[:punct:]]。
[[:cntrl:]]控制字符。在 ASCII中, 这些字符对应八进制代码000到037和 177 (DEL)。

转义字符

字符描述
\cx匹配由x指明的控制字符。例如, \cM 匹配一个 Control-M 或回车符。x的值必须为 A-Z 或 a-z 之一。否则,将 c 视为一个原义的 ‘c’ 字符。
\f匹配一个换页符。等价于 \x0c 和 \cL。
\n匹配一个换行符。等价于 \x0a 和 \cJ。
\r匹配一个回车符。等价于 \x0d 和 \cM。
\s匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。注意 Unicode 正则表达式会匹配全角空格符。
\S匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。
\w匹配字母、数字、下划线。等价于 [A-Za-z0-9_]
\W匹配任何非单词字符。等价于[^A-Za-z0-9_]
\t匹配一个制表符。等价于 \x09 和 \cI。
\v匹配一个垂直制表符。等价于 \x0b 和 \cK。

限定次数

字符描述
*匹配前面的子表达式零次或多次。例如,zo*能匹配"z"以及"zoo"。
+匹配前面的子表达式一次或多次。例如,'zo+'能匹配"zo"以及"zoo"。
?匹配前面的子表达式零次或一次。例如,"do(es)?“可以匹配"do”、“does"中的"does”、“doxy"中的"do”。?等价于{0,1}。
{n}n是一个非负整数。匹配确定的n次。例如,'o{2}‘不能匹配"Bob"中的’o’,但是能匹配"food"中的两个o。
{n,}n是一个非负整数。**至少匹配n次。*例如,'o{2,}‘不能匹配"Bob"中的’o’,但能匹配"foooood"中的所有o。'o{1,}‘等价于’o+’。'o{0,}'则等价于’o’。
{,m}m是一个非负整数。**最多匹配m次。**例如,'o{,2}‘不能匹配"Booob"中的’o’,但能匹配"food"中的所有o。'o{,2}‘等价于’o{0,2}’。
{n,m}m和n均为非负整数,其中n<=m。**最少匹配n次且最多匹配m次。**例如,"o{1,3}"将匹配"fooooood"中的前三个o。'o{0,1}‘等价于’o?’。请注意在逗号和两个数之间不能有空格。
()标记一个子表达式的开始和结束位置。**子表达式可以获取供以后使用。**要匹配这些字符,请使用 ( 和 )。

定位符,使您能够匹配行首或行尾,单词内、单词开头或者单词结尾。

字符描述
^**匹配行首位置。**例如,^laoma,匹配以laoma开头的行。
$**匹配行末位置。**例如,laoma$,匹配以laoma结尾的行。
\b匹配一个单词边界,即字与空格间的位置。
\B非单词边界匹配。
<匹配一个单词左边界。
>匹配一个单词右边界。

示例:

  • . 点号。

    [root@server ~ 17:09:41]# echo -e "cat\nbat\nfun\nfin\nfan"
    # 输出结果如下
    cat
    bat
    fun
    fin
    fan
    
    [root@server ~ 17:10:08]# echo -e "cat\nbat\nfun\nfin\nfan" | awk '/f.n/'
    # 输出结果如下
    fun
    fin
    fan
    
  • ^ 行首和 $ 行位

    [root@server ~ 17:10:08]# echo -e "cat\nbat\nfun\nfin\nfan" | awk '/^fin/'
    # 输出结果如下
    fin
    
    [root@server ~ 17:10:08]# echo -e "cat\nbat\nfun\nfin\nfan" | awk '/fin$/'
    # 输出结果如下
    fin
    
  • [][^]

    [root@server ~ 17:10:08]# echo -e "cat\nbat\nfun\nfin\nfan" | awk '/f[ai]n/'
    # 输出结果如下
    fin
    fan
    [root@server ~ 17:10:08]# echo -e "cat\nbat\nfun\nfin\nfan" | awk '/f[^ai]n/'
    # 输出结果如下
    fun
    
  • | 多选1

    [root@server ~ 17:10:08]# echo -e "cat\nbat\nfun\nfin\nfan" | awk '/fan|cat/'
    # 输出结果如下
    cat
    fan
    
  • ? 0 次或 1 次

    [root@server ~ 17:10:08]# echo -e "Colour\nColor" | awk '/Colou?r/'
    # 输出结果如下
    Colour
    Color
    
  • * 任意次数

    [root@server ~ 17:10:08]# echo -e "ca\ncat\ncatt" | awk '/cat*/'
    # 输出结果如下
    ca
    cat
    catt
    
  • + 1 次以上

    [root@server ~ 17:10:08]# echo -e "111\n22\n123\n234\n456\n222"  | awk '/2+/'
    # 输出结果如下
    22
    123
    234
    222
    
  • () 子串

    [root@server ~ 17:10:08]# echo -e "Apple Juice\nApple Pie\nApple Tart\nApple Cake" | awk '/Apple (Juice|Cake)/'
    # 输出结果如下
    Apple Juice
    Apple Cake
    

逻辑运算符

逻辑运算符包括 逻辑与( && )、逻辑或( || )、逻辑非 ( ! )

逻辑与( && )

逻辑与运算符使用两个 & 表示。

语法:expr1 && expr2

逻辑与( && )运算符的计算结果遵循以下规则:

  1. 如果 expr1 和 expr2 的计算结果都为 true,则结果为 true; 否则返回 false。
  2. 当且仅当 expr1 的计算结果为 true 时,才会计算 expr2。
[root@server ~ 17:10:08]# awk '
BEGIN {
   num=5
   if (num>=0 && num<=7) 
   { print "0<="num"<=7" }
}'

运行上面的 awk 命令,输出结果为

0<=5<=7
逻辑或( || )

逻辑或运算符使用 || 表示。

语法:expr1 || expr2

逻辑或( || )运算符的计算结果遵循以下规则

  1. 如果 expr1 和 expr2 的计算结果只要有一个为 true,则结果为 true; 否则返回 false
  2. 当且仅当 expr1 的计算结果为 false 时,才会计算 expr2
[root@server ~ 17:10:08]# awk '
BEGIN {
  ch="\n"
  if (ch==" " || ch=="\t" || ch=="\n") 
  { print "Current character is whitespace." }
}'

运行上面的 awk 命令,输出结果如下:

Current character is whitespace
逻辑非 ( ! )

逻辑非运算符使用 感叹号( !) 表示。

语法:! expr1

逻辑非运算符返回 expr1 的逻辑补语,也就是说如果 expr1 的计算结果为 true,则返回 0; 否则返回 1。

例如下面的 AWK 命令,因为 name 为空字符串,所以 length(name) 的结果为 0,对 0 执行逻辑非运算,则为 true。

[root@server ~ 17:10:08]# awk '
BEGIN { 
  site = ""
  if (! length(site))
  { print "site is empty string." }
}'

运行上面的 awk 命令,输出结果如下:

site is empty string.

awk 数组

AWK 中的数组,既可以是普通数组,也可以是关联数组。也就是说,数组的索引/下标不必是连续的数字。

AWK 中的数组不用事先声明数组的大小,在运行时动态的增长。

创建和访问数组

AWK 中创建数组的语法很简单,创建数组和给数组添加/修改元素的方式语法一样。

语法:array_name[index] = value

  1. array_name 是数组的名字。
  2. index 是数组的索引。
  3. value 是分配给 index 下标/索引的值。

访问数组元素,也是通过下标。

语法:array_name[index]

**示例1:**以水果作为键,以水果颜色作为值。

[root@server ~ 17:10:08]# awk '
BEGIN {
  colour["芒果"] = "橘色";
  colour["橘子"] = "黄色";
  colour["苹果"] = "红色";
  print colour["芒果"],colour["橘子"],colour["苹果"]
}'

运行以上 awk 命令,输出结果如下:

橘色 黄色 红色

从上面的代码中可以看出,访问数组的方式也很简单,就是使用 array_name[index]

打印数组所有元素

**示例1:**使用无序下标循环输出。

[root@server ~ 17:10:08]# awk 'BEGIN {
  colour["芒果"] = "橘色"
  colour["橘子"] = "黄色"
  colour["苹果"] = "红色"
  for (i in colour)
  { print i": "colour[i]}
}'

运行以上 awk 命令,输出结果如下:

苹果: 红色
芒果: 橘色
橘子: 黄色

**示例2:**使用有序下标循环输出。

[root@server ~ 17:10:08]# awk 'BEGIN {
  colour[0] = "橘色"
  colour[1] = "黄色"
  colour[2] = "红色"
  lens=length(colour)
  for (i=0;i<lens;i++)
  { print i": "colour[i]}
}'

说明: 版本够高的awk可以直接使用方法length()得到数组长度。如果传给length的变量是一个字符串,那么length返回的则字符串的长度。

运行以上 awk 命令,输出结果如下:

0: 橘色
1: 黄色
2: 红色

示例3: 统计文件/etc/profile中出现频率最高的10个单词,并显示对应数量。

#方法一
[root@server ~ 17:10:08]# cat commands.awk
{
  for (i=1;i<=NF;i++){
    count[$i]++
  }
}
END {
  for (i in count){
  print i" "count[i]
  }
}

#
[root@server ~ 19:03:15]# for num in 1 2 3 4 5
> do echo $num
> done
1
2
3
4
5

#“提取 /etc/profile 关键词→统计出现次数→按次数降序→过滤纯标点单词→取前 10 条”
[root@server ~ 17:10:08]# cat /etc/profile | awk -f commands.awk | sort -nr -k2 | awk '$1 !~ "^[[:punct:]]+"'| head
then 8
if 8
fi 8
pathmunge 6
in 6
to 5
for 5
else 5
umask 3
export 3
#正则 ^[[:punct:]]+:^ 行首、[[:punct:]] 匹配所有标点、+ 一个或多个;$1 !~ 正则:第 1 列(单词)不匹配 “以标点开头”,才保留该行

分步解释:

  1. cat /etc/profile
    • 作用:读取 /etc/profile 文件的内容并输出到标准输出(控制台)。
    • /etc/profile 是系统级的环境变量配置文件,包含环境变量、别名等系统初始化设置。
  2. awk -f commands.awk
    • 作用:调用 awk 工具,执行 commands.awk 脚本文件中的处理逻辑。
    • commands.awk 是一个自定义的 awk 脚本(需提前创建),通常功能未知,但通常用于:
      • 提取文件中的特定字段(如单词、关键字);
      • 统计数据(如出现次数);
      • 按格式输出内容(例如 单词 次数 的两列格式)。
  3. sort -nr -k2
    • 作用:对前一步输出的内容进行排序。
    • 选项解析:
      • -n:按数字大小排序(而非字符串字典序);
      • -r:逆序排序(从大到小);
      • -k2:以第 2 列作为排序依据。
    • 假设 commands.awk 输出格式为 字段1 数字,这一步会按第 2 列的数字从大到小排序。
  4. awk '$1 !~ "^[[:punct:]]+"'
    • 作用:过滤掉第一列以标点符号开头的行。
    • 正则解析:
      • $1:表示当前行的第 1 列;
      • !~:表示 “不匹配”;
      • ^[[:punct:]]+:匹配 “以一个或多个标点符号开头” 的字符串([:punct:] 是正则中表示标点符号的字符类)。
    • 目的:排除无效数据(如纯符号、以符号开头的干扰项)。
  5. head
    • 作用:默认显示前 10 行结果(可通过 -n 选项指定行数,如 head -n 5 显示前 5 行)。

#方法二:
[root@server ~ 13:47:32]# cat /etc/profile |sed  -nr 's/[[:punct:]]+/ /gp'| sed -nr 's/\s+/\n/gp' | sed '/^$/d' |sort -n |uniq -c |sort -nr|head
     12 usr
      8 then
      8 if
      7 bin
      6 pathmunge
      6 in
      6 id
      5 to
      5 PATH
      5 i

 

length 函数

作用: 用于返回一个字符串的总字节数。。

语法: length(str)

语法说明: str,要统计的字符串。

示例1: 英文字符串

[root@server ~ 15:51:27]# awk 'BEGIN {
   str="Hello, World !"
   print "\""str"\"", "的长度为:", length(str)
}'

运行以上 awk 命令,输出结果如下:

"Hello, World !" 的长度为: 14

示例2: 中文字符串

[root@server ~ 18:59:41]# awk 'BEGIN {
   str="你好!"
   print "\""str"\"", "的长度为:", length(str)
}'

运行以上 awk 命令,输出结果如下:

"你好!" 的长度为: 3
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值