文章目录
awk是一种编程语言,用于在linux/unix下对文本和数据进行处理。数据可以来自标准输入(stdin)、一个或多个文件,或其它命令的输出。它支持用户自定义函数和动态正则表达式等先进功能,是linux/unix下的一个强大编程工具。它在命令行中使用,但更多是作为脚本来使用。awk有很多内建的功能,比如数组、函数等,这是它和C语言的相同之处,灵活性是awk最大的优势。
1. 语法与选项
-
语法:
awk [可选项] '模式操作 | 模式操作 | 模式操作
-
说明
- 可选项:
-F '分隔符'
:默认分隔符是"空白键" 或 “\t键”,可以不用 -F 指定-v
:用于将外部变量值传递给awk。比如:temp=10 awk -v a=$temp '{print $1,$1+a}' log.txt
-f
:scriptfile 从脚本文件中读取awk命令
- 模式与操作
- 模式:模式可以是以下任意一种
① 正则表达式:使用通配符的扩展集
② 关系表达式:使用运算符进行操作,可以是字符串或数字的比较测试
③ 模式匹配表达式:用运算符~(匹配)和~!不匹配
③BEGIN 语句块
,pattern语句块
,END语句块
- 操作:操作由一个或多个命令、函数、表达式组成,之间由换行符或分号隔开,并位于大刮号内,主要部分是:变量或数组赋值、输出命令、内置函数、控制流语句。
- 模式:模式可以是以下任意一种
- 可选项:
-
awk最常用的模式操作是:
awk [可选项] 'BEGIN{ commands } pattern{ commands } END{ commands }' file_name
接下来详细介绍这个。
2. awk执行过程
AWK 工作流程可分为三个部分:
-
读输入文件之前执行的代码段(由BEGIN关键字标识)。
-
读取文件时主循环逐行执行的代码段。(partter, 如果没有提供pattern语句块,则默认执行
{ print }
,即打印每一个读取到的行。)细节:BEGIN使用
print
或printf
输出的字符串,不会在这个模块被处理。
-
读取数据完毕之后执行的代码段(由END关键字标识)。
通常我们会将变量初始化语句放在BEGIN语句块中,将打印结果等语句放在END语句块中。通过一个例子理解:
1、先创建一个名为 marks.txt 的文件。其中包括序列号、学生名字、课程名称与所得分数。
1) 张三 语文 80
2) 李四 数学 90
3) 王五 英语 87
2、接下来,我们将使用 AWK 脚本来显示输出文件中的内容,同时输出表头信息。
awk 'BEGIN{printf "序号\t名字\t课程\t分数\n"} {print}' marks.txt
执行结果如下:
序号 名字 课程 分数
1) 张三 语文 80
2) 李四 数学 90
3) 王五 英语 87
3. 变量
3.1 内置变量
-
指定列:
$0
:选中所有列$1
:选中第一列$1, $2, $3
:同时选中多列$NF
:选中最后一列
-
NF
: 表示字段数,在执行过程中对应于当前的字段数。print $NF
打印一行中最后一个字段 -
NR
: 表示记录数,在执行过程中对应于当前的行号 -
FS
:输入时的分隔符变量,可以是任意字符或者正则表达式。(默认是以空格
或\t
做分隔)# 可以通过可选项 -F 指定分隔符 awk -F '\t' 'print $1' # 也可以通过设置 FS 指定分隔符 awk 'BEGIN{FS="\t"}{print $1}'
如果两者同时指定,以
FS
为准。 -
OFS
:输入时的分隔符变量,可以是任意字符或者正则表达式。主要是会影响print
和printf
。()默认以空格为分隔
)$ awk -F':' 'BEGIN{OFS="=";} {print $3,$4;}' /etc/passwd 41=41 100=101 101=102 103=7 105=111 110=116 111=117 112=11
-
RS(Record Separator)
定义了一行记录。读取文件时,默认将一行作为一条记录。 下面的例子以 student.txt 作为输入文件,记录之间用两行空行分隔,并且每条记录的每个字段用一个换行符分隔:cat student.txt Jones 2143 78 84 77 Gondrol 2321 56 58 45
$ cat student.txt | awk BEGIN { RS="\n\n"; FS="\n"; } { print $1,$2; } # 输出: Jones 2143 Gondrol 2321 RinRao 2122 Edwin 2537 Dayan 2415
-
FILENAME
: 当前输入文件的名字
3.2 引入外部变量
通过可选参数-v
,其实前面以及说明过:
temp=10
awk -v a=$temp '{print $1,$1+a}' log.txt
3.3 数组
(1) 一维数组
AWK 可以使用关联数组这种数据结构,索引可以是数字
或字符串
。AWK关联数 组也不需要提前声明其大小,因为它在运行时可以自动的增大或减小。
和java语法一样:
- 创建数组&添加元素&查看数组
awk 'BEGIN { sites["runoob"]="www.runoob.com"; sites["google"]="www.google.com"; print sites["runoob"] "\n" sites["google"] }'
- 删除数组元素
awk 'BEGIN { sites["runoob"]="www.runoob.com"; // 定义数组,并添加元素 delete sites["runoob"]; // 删除元素 }'
(2) 多维数组
AWK 本身不支持多维数组,不过我们可以很容易地使用一维数组模拟实现多维数组。
awk 'BEGIN {
array["0,0"] = 100;
array["0,1"] = 200;
array["0,2"] = 300;
array["1,0"] = 400;
array["1,1"] = 500;
array["1,2"] = 600;
# 输出数组元素
print "array[0,0] = " array["0,0"];
print "array[0,1] = " array["0,1"];
print "array[0,2] = " array["0,2"];
print "array[1,0] = " array["1,0"];
print "array[1,1] = " array["1,1"];
print "array[1,2] = " array["1,2"];
}'
4. awk运算
- 算术运算:(+,-,*,/,&,!,……,++,–)所有用作算术运算符进行操作时,操作数自动转为数值,所有非数值都变为0
- 赋值运算:(=, +=, -=,*=,/=,%=,……=,**=)
- 逻辑运算符: (||, &&)
- 关系运算符:(<, <=, >,>=,!=, ==)
- 正则运算符:(~,~!)(匹配正则表达式,与不匹配正则表达式)awk 'BEGIN{a=“100testa”;if(a ~ /^100*/){print “ok”;}}'ok
5. 控制语句
5.1 分支语句
和Java代码一样,语法如下:
if (condition1) {
action1;
action2;
...
}
else if (condition2) {
action1;
action2;
...
}
else {
action1;
action2;
...
}
细节:
- 和java一样,单代码块中只有一条语句时,可以省略花括号。
- 语句以封号结尾。
例子:
awk 'BEGIN {
num = 11;
if (num % 2 == 0) printf "%d 是偶数\n", num;
else printf "%d 是奇数\n", num
}'
5.2 循环语句
也是和java一样,语法如下:
-
for循环:
awk 'BEGIN { for (i = 1; i <= 5; ++i) print i }'
细节:这里不需要定义数据类型
-
while循环:
awk 'BEGIN {i = 1; while (i < 6) { print i; ++i} }'
细节:这里不需要定义数据类型
-
break语句:
awk 'BEGIN { sum = 0; for (i = 0; i < 20; ++i) { sum += i; if (sum > 50) break; else print "Sum =", sum } }'
-
Continue语句:
awk 'BEGIN { for (i = 1; i <= 20; ++i) { if (i % 2 == 1) continue ; else print i } }'
for循环
for(变量 in 数组)
{语句}
for(变量;条件;表达式)
{语句}
while循环
while(表达式)
{语句}
do…while循环
do
{语句} while(条件)
其他相关语句
break:退出程序循环
continue: 进入下一次循环
next:读取下一个输入行
exit:退出主输入循环,进入END,若没有END或END中有exit语句,则退出脚本。
6. 内置函数
https://www.runoob.com/w3cnote/awk-built-in-functions.html
7. 常用组合
\t
切分后,用#
拼接,然后输出cat /xxxx | awk -F'\t' '{gsub(/\t/, "#"); print $0}' | more
- 切分后,依次打印所有列
echo "A B C D E F" | awk '{for(i=1;i<=NF;i++) print $i}' # 输出: A B C D E F