awk教程

AWK教程

本文内容是https://www.tutorialspoint.com/awk/的笔记

AWK工作流程如下图:

awk教程_第1张图片

Read

AWK从输入流(文件、 管道或 输入流)中读取一行,并将其存储在内存中。

Execute

所有AWK命令都按顺序应用于输入。默认情况下,AWK在每一行上执行命令。我们可以通过提供pattern来限制这一点。

Repeat

这个过程会重复,直到文件到达终点。

程序结构

从上面的工作流程上也能看出来,主要分为三部分:begin部分、body部分(中间循环的部分)、end部分

下面看看这三个部分每个部分的结构:

  • begin部分
    BEGIN {awk-commands}
    

    BEGIN {}都是命令格式的一部分,只有awk-commands是我们可以替换的命令。BEGIN是一个AWK关键字,因此它必须大写。这部分是可选的。

    这部分在程序启动时执行。它只执行一次。一般在这里进行初始化变量。

  • body部分
    /pattern/ {awk-commands}
    

    // {}都是命令格式的一部分。

    body在每个输入行上应用AWK命令。默认情况下,AWK在每行执行命令。可以通过提供pattern进行数据过滤,限制命令执行的次数。

    注意,body部分没有关键字。

  • end部分
    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教程_第2张图片

对照我们之前讲的awk,可以看到这里缺少了body部分的pattern

首先会执行BEGIN部分,输出一行*,后面是body部分,会针对输入文件的每一行执行,将每一行输出到输出流,最后是END部分,输出一行=

从上面例子也能看到BENGIN部分、END部分只执行了一次。body部分会执行多次。

awk也可以从文件中读取命令执行。

我们将下面的命令储存到文件中,比如文件名叫command.awk

BEGIN{print "**********************"} {print} END{print "======================"}

然后我们执行awk -f command.awk marks.txt ,也能看到同样的输出。

awk内置变量

使用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
}

Cjava等等是一样的,单个语句可以不加{}

示例如下:

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 $?获取到退出值。

你可能感兴趣的:(shell,awk)