本文内容是https://www.tutorialspoint.com/awk/的笔记
AWK从输入流(文件、 管道或 输入流)中读取一行,并将其存储在内存中。
所有AWK命令都按顺序应用于输入。默认情况下,AWK在每一行上执行命令。我们可以通过提供pattern
来限制这一点。
这个过程会重复,直到文件到达终点。
从上面的工作流程上也能看出来,主要分为三部分:begin部分、body部分(中间循环的部分)、end部分。
下面看看这三个部分每个部分的结构:
BEGIN {awk-commands}
BEGIN {
和}
都是命令格式的一部分,只有awk-commands
是我们可以替换的命令。BEGIN
是一个AWK
关键字,因此它必须大写。这部分是可选的。
这部分在程序启动时执行。它只执行一次。一般在这里进行初始化变量。
/pattern/ {awk-commands}
/
、/
、 {
、}
都是命令格式的一部分。
body
在每个输入行上应用AWK
命令。默认情况下,AWK
在每行执行命令。可以通过提供pattern
进行数据过滤,限制命令执行的次数。
注意,body
部分没有关键字。
END {awk-commands}
END {
和}
都是命令格式的一部分,只有awk-commands
是我们可以替换的命令。END
是一个AWK
关键字,因此它必须大写。这部分是可选的。
这部分在程序结束时执行。它只执行一次。
下面我们看几个例子:
我们首先创建一个marks.txt
的文本文件。内容如下:
1) Amit Physics 80
2) Rahul Maths 90
3) Shyam Biology 87
4) Kedar English 85
5) Hari History 89
我们执行下面的命令
awk 'BEGIN{print "**********************"} {print} END{print "======================"}' marks.txt
我们会看到如下的输出:
对照我们之前讲的awk
,可以看到这里缺少了body
部分的pattern
。
首先会执行BEGIN
部分,输出一行*
,后面是body
部分,会针对输入文件的每一行执行,将每一行输出到输出流,最后是END
部分,输出一行=
。
从上面例子也能看到BENGIN
部分、END
部分只执行了一次。body
部分会执行多次。
awk
也可以从文件中读取命令执行。
我们将下面的命令储存到文件中,比如文件名叫command.awk
BEGIN{print "**********************"} {print} END{print "======================"}
然后我们执行awk -f command.awk marks.txt
,也能看到同样的输出。
使用awk --dump-variables ''
命令可以输出awk
中内置变量及默认值。会输出到awkvars.out
文件中。
也可以使用awk --dump-variables=a.txt ''
的方式,指定输出文件名。
下面列出一些常用的变量及说明。
ARGC
: 表示参数的数量。
awk 'BEGIN {print "Arguments =", ARGC}' One Two Three Four
会输出Arguments = 5
。其中awk
是第一个参数。
ARGV
: 表示参数数组。范围是从0到ARGC-1
awk 'BEGIN {
for (i = 0; i < ARGC - 1; ++i) {
printf "ARGV[%d] = %s\n", i, ARGV[i]
}
}' one two three four
执行上面的脚本就能看到打印出了所有参数。
FILENAME
: 表示当前脚本的文件名
awk 'END {print FILENAME}' marks.txt
会输出marks.txt
。
FS
: 表示输入字段的分割符。默认是空格。可以使用-F
选项更改。
echo "a:b:c" | awk -F: '{ print $1 }'
如上,我们指定了:
分隔符,就会输出a
。(当然对于没有:
的行,也会输出)
NF
: 它表示当前记录中的字段数量。
echo "a:b:c" | awk -F: '{ print NF }'
如上,就会输出3
NR
: 输出当前记录的行号。如果有多个文件,会一直累积。
echo -e "One Two\nOne Two Three\nOne Two Three Four" | awk '/Three/ {print NR " = " $0}'
如上,就会输出如下内容。
2 = One Two Three
3 = One Two Three Four
FNR
: 和NR
相似,不同点在于每个文件都会从编号1开始。
OFS
: 表示输出字段的分割符。默认是空格
ORS
: 表示输出记录的分割符。默认是换行符。
echo -e "One Two\nOne Two Three\nOne Two Three Four" | awk 'BEGIN{ORS="***" } /Three/ {print NR " = " $0}'
如上,我们指定输出记录分割符为***
,就会看到在一行输出。各个记录用***
进行了分割。
RS
: 表示输入记录的分割符。默认是换行符。
$0
: 表示输入的整行记录。
$n
:表示分割后的第n
个字段。如$1、$2。
awk
也支持各种算术运算,如下面的示例:
# 加
awk 'BEGIN { a = 50; b = 20; print "(a + b) = ", (a + b) }'
# 取余
awk 'BEGIN { a = 50; b = 20; print "(a % b) = ", (a % b) }'
# 自增
awk 'BEGIN { a = 10; b = ++a; printf "a = %d, b = %d\n", a, b }'
# 相等判断
awk 'BEGIN { a = 10; b = 10; if (a == b) print "a == b" }'
# 小于等于
awk 'BEGIN { a = 10; b = 20; if (a <= b) print "a <= b" }'
字符串拼接:
awk 'BEGIN { str1 = "Hello, "; str2 = "World"; str3 = str1 str2; print str3 }'
乘方:
awk 'BEGIN { a = 10; a = a ^ 2; print "a =", a }'
awk 'BEGIN { a = 10; a = a**2; print "a =", a }'
正则表达式操作:
# 匹配ca t出现0次到多次
echo -e "ca\ncat\ncatt\naaa" | awk '/cat*/'
# 匹配 2 出现1次到多次的情况
echo -e "111\n22\n123\n234\n456\n222" | awk '/2+/'
数组处理:
awk 'BEGIN {
fruits["mango"] = "yellow";
fruits["orange"] = "orange"
print fruits["orange"] "\n" fruits["mango"]
}'
awk 'BEGIN {
fruits["mango"] = "yellow";
fruits["orange"] = "orange";
delete fruits["orange"];
print fruits["orange"]
}'
多维数组
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 elements
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"];
}'
awk
控制流if
语句块:if (condition)
action
if (condition) {
action-1
action-1
.
.
action-n
}
和C
、java
等等是一样的,单个语句可以不加{}
。
示例如下:
awk 'BEGIN {num = 10; if (num % 2 == 0) printf "%d is even number.\n", num }'
也可以有else分支
if (condition)
action-1
else
action-2
示例如下:
awk 'BEGIN {
num = 11; if (num % 2 == 0) printf "%d is even number.\n", num;
else printf "%d is odd number.\n", num
}'
也可以有else if
分支
示例如下:
awk 'BEGIN {
a = 30;
if (a==10)
print "a = 10";
else if (a == 20)
print "a = 20";
else if (a == 30)
print "a = 30";
}'
for
循环语句快for (initialization; condition; increment/decrement)
action
示例如下:
awk 'BEGIN { for (i = 1; i <= 5; ++i) print i }'
while
循环语句块while (condition)
action
示例如下:
awk 'BEGIN {i = 1; while (i < 6) { print i; ++i } }'
do-while
循环语句块do
action
while (condition)
示例如下:
awk 'BEGIN {i = 1; do { print i; ++i } while (i < 6) }'
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 == 0) print i ; else continue
}
}'
exit
语句示例如下
awk 'BEGIN {
sum = 0; for (i = 0; i < 20; ++i) {
sum += i; if (sum > 50) exit(10); else print "Sum =", sum
}
}'
可以使用
echo $?
获取到退出值。