awk文本处理工具使用

44 阅读1分钟

命令格式

awk option 'function(...){} pattern {action}' input_file

option

这里列举一些常用的option:

  1. -F 指定分隔符,比如以冒号(:)作为字段分隔符,并打印 /etc/passwd 文件的每行的第一个字段。

    1. awk -F: '{print $1}' /etc/passwd
      
  2. -v 为自定义变量赋值

    1. awk -v name="yuhan" '{print name}' filename
      
  3. -f 指定一个包含 awk 脚本的文件,而不是在命令行中直接写出脚本。

    1. awk -f script.awk input_file
      

内置变量

这里列举一些常用的内置变量:

  1. RS:record separator,默认是换行符
  2. FS:field separator,每个record会被FS分割成多个field,默认是空格和制表符的任意组合
  3. NR:number of record,到现在为止读入了的record数量,常用来标记行号
  4. NF:record中field的数量

Pattern

awk的pattern有下面几种模式:

  • BEGIN:一个特殊的模式,用于执行 awk 开始读取输入之前的操作。

  • END:另一个特殊的模式,用于在 awk 处理完所有输入行后执行操作。

  • /regular expression/:用于匹配输入行的正则表达式或条件表达式。

  • 条件表达式:<, <=, >, >=, ==, !=

    •   比如,从第二行开始输出第二列的值
    • awk 'NR > 1 {print $2}' data.txt
      

Action

{action} 定义当模式匹配时执行的命令或操作。

包括操作符和一些内置函数

操作符

$

Field 引用 $0, $1, $2...

~,!~

这两种操作符后跟正则表达式,代表匹配/不匹配后面的正则表达式,例如

$1 ~ /foo/

还有的操作符和其他语言中的类似,就不在这里列出了

控制语句

if () {} else {}
while () {}
do {} while()
for (exp1; exp2; exp3) {}
for (key in arr) {}
break
continue
delete arr[index]
delete arr # 删除所有元素,但不删除数组本身
exit [experssion] # 退出

使用exit的例子:

awk -F, '{if($2 ~ /foo/){exit 0}} END{print "end"}' input_file

上面的例子当第二列匹配到foo时直接退出,END中的代码仍然会执行

IO statement

close(file)

关闭文件,管道

getline

  1. getline

将下一次输入赋值给$0

  1. getline var

将下一次输入赋值给var

String function

split(s, a [, r])

分割字符串s为数组a,r 是正则表达式,指定了分割符,a索引从1开始。

substr( s , i [ , n] )

返回字符串s从i开始的最多n个字符,i从1开始。

Function

可以定义自己的函数,在执行时调用,函数的语法是

function name ( parameter list ) { statements } 

例子

假设有如下数据data.txt

ID,Name,Age,Score,Country
1,John Doe,28,85,USA
2,Jane Smith,32,90,UK
3,Franz Kafka,40,78,Germany
4,Diane Rios,25,95,USA
5,Akira Toriyama,65,88,Japan
6,Lee Min,22,90,South Korea
7,Patricia Luna,29,85,Mexico
8,Marco Rossi,52,73,Italy
9,Chen Wei,34,82,China
10,Ivan Ivanov,47,69,Russia

下面每个例子通过:awk -f read.awk data.txt 执行

打印每个国家的第一个出现的记录

# read.awk
BEGIN {
    FS = ","
}
# seen 数组索引可以是字符串,数字...
NR > 1 && !seen[$5]++ {
    print
}
END {
    
}

# 执行:awk -f read.awk file

按国家分组,计算每个国家人员的平均年龄

BEGIN {
    FS = ","
}
NR > 1 {
    totalAge[$5]+=$3
    cnt[$5]++
}
END {
    # country代表索引
    for (country in totalAge) {
        averageAge = totalAge[country] / cnt[country]
        print country ", " averageAge
    }
}

对所有记录按分数从高到低排序并输出

BEGIN {
    FS = ",";
}

NR > 1 {
    print $0 | "sort -t, -k4,4nr";  # 将记录传递给 sort 命令
}

END {
    close("sort -t, -k4,4nr");  # 关闭 sort 命令的管道
}

为每个国家生成一个单独的文件,文件名格式为 Country.csv,内容包含该国家的所有记录

BEGIN {
    FS = ",";
    head = ""
}

NR == 1 {
    head = $0  # 保存标题行
}

NR > 1 {
    country = $5
    fname = country ".csv"
    if (!seen[country]++) {
        print head > fname  # 对于每个国家的第一条记录,打印标题行
    }
    print $0 >> fname  # 使用追加模式将记录添加到文件
}

END {
    
}