命令格式

  1. awk '{pattern + action}' {filenames}
  2. awk '条件1{动作1}条件2{动作2}...' 文件名

eg

  1. awk '{print $0}' /etc/passwd

调用 awk时,我们指定/etc/passwd 作为输入文件。执行 awk时,它依次对/etc/passwd 中的每一行执行 print 命令。所有输出都发送到 stdout,所得到的结果与执行 cat /etc/passwd 完全相同。

awk会根据空格和制表符,将每一行分成若干字段,依次用$1、$2、$3代表第一个字段、第二个字段、第三个字段等等。

  1. #! /bin/bash
  2. echo "hello world" | awk '{print $2}'

输出结果

  1. world

内置参数/变量

内置参数 说明
$0 表示整个当前行
$1 每行第一个字段
$2 每行第二个字段
NR number of Row 行号,当前处理的文本行的行号。
NF number of Field,当前行的字段的个数(即当前行被分割成了几列),字段数量
FILENAME 正在处理的文件名
FS 输入字段分隔符, 默认为空白字符
OFS 输出字段分隔符, 默认为空白字符
ARGC 命令行参数的个数
ARGV 数组,保存的是命令行所给定的各参数

NF

变量NF表示当前行有多少个字段,因此$NF就代表最后一个字段。$(NF-1)代表倒数第二个字段。

  1. #! /bin/bash
  2. echo 'hello world' | awk '{print $NF}'
  3. echo 'hello world' | awk '{print $(NF-1)}'

输出结果

  1. world
  2. hello

NR

测试文件demo.txt

  1. 123 abc
  2. 456 def
  3. 789 ghi

bash内容

  1. #! /bin/bash
  2. awk '{print "["NR"]",$0}' demo.txt

输出结果

  1. [1] 123 abc
  2. [2] 456 def
  3. [3] 789 ghi

FNR

各文件分别计数的行号
准备两个测试文件
a.txt

  1. a1 b1
  2. c2 d2

b.txt

  1. good study
  2. day up

执行

  1. #! /bin/bash
  2. awk '{print "["NR"]",$0}' a.txt b.txt

输出结果

  1. [1] a1 b1
  2. [2] c2 d2
  3. [3] good study
  4. [4] day up

执行FNR

  1. #! /bin/bash
  2. awk '{print "["FNR"]",$0}' a.txt b.txt

输出结果如下,当awk处理多个文件时,FNR分别对每个文件的行数进行计数。

  1. [1] a1 b1
  2. [2] c2 d2
  3. [1] good study
  4. [2] day up

RS

RS是输入行分隔符,如果不指定,默认的”行分隔符”就是我们所理解的”回车换行”。
,我们不想以默认的”回车换行”作为”行分隔符”,而是想使用空格作为所谓的行分隔符,也就是说,我们想让awk认为,每遇到一个空格,就换行,换句话说,我们想让awk以为每次遇到一个空格就是新的一行。

  1. a1 b1
  2. c2 d2

执行

  1. #! /bin/bash
  2. awk -v RS=' ' '{print "["NR"]",$0}' a.txt

输出结果如下,指定使用空格作为”行分隔符”时,在awk解析文本时,每当遇到空格,awk就认为遇到的空格是换行符,于是awk就将文本换行了,而文本本身的”回车换行”,对于awk来说并不是所谓的换行符,所以才会出现上图中第3行的现象,

  1. [1] a1
  2. [2] b1
  3. c2
  4. [3] d2

ARGV

ARGV内置变量表示的是一个数组,这个数组中保存的是命令行所给定的参数,其中ARGV[0]表示awk本身

  1. #! /bin/bash
  2. awk 'BEGIN{print ARGV[1],ARGV[2]}' a b

输出结果

  1. a b

ARGC

则表示参数的数量

  1. awk 'BEGIN{print ARGV[1],ARGV[2],ARGC}' a b

输出结果

  1. 3

自定义环境变量

方法1 -v varname=value 变量名区分字符大小写。
方法2 在program中直接定义。

  1. #! /bin/bash
  2. v='abc'
  3. awk -v myvar=$v 'BEGIN{print myvar}'

或者变量定义与动作之间需要用分号”;”隔开

  1. awk 'BEGIN{myvar="abc"; print myvar}'

分隔符

分隔符 说明
输入分隔符field separator(FS) 默认以空白字符为分隔符对每一行进行分割。
输出分割符output field separator(0FS) 默认的输出分割符也是空格。

输入分隔符

默认分隔符是空格 -F 指定分隔符

  1. awk -F ':' '{print $1}' /etc/passwd
  2. awk -F ':' '{print "Line: " NR, "Col: " NF,"User: " $1}' /etc/passwd
  3. awk -F ':' '{printf("Line:%s Col:%s User:%s\n",NR,NF,$1)}' /etc/passwd
  4. awk -F ':' '{if ($3>100) print "User:" $1}' /etc/passwd

准备测试文件test.txt

root:x:0:0:root:/root:/usr/bin/zsh
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync

shell 文件

#! /bin/bash
awk -F ':' '{print $1}' test.txt

输出结果

root
daemon
bin
sys
sync

awk内置变量FS可以用于指定输入分隔符,但是在使用变量时,需要使用-v选项,-v表示设置变量值
测试文件demo.txt

123#abc
456#def
789#ghi

shell 测试文件

#! /bin/bash
awk -v FS='#' '{print $1,$2}' demo.txt

输出结果

123 abc
456 def
789 ghi

输出分隔符

内置变量OFS来设定awk的输出分隔符,使用内置变量的需要配合使用-v选项

#! /bin/bash
awk -v FS='#' -v OFS='*' '{print $1,$2}' demo.txt

输出结果

123*abc
456*def
789*ghi

取消分隔符
awk ‘{print $1 $2}’ 表示每行分割后,将第一列(第一个字段)和第二列(第二个字段)连接在一起输出。
awk ‘{print $1,$2}’ 表示每行分割后,将第一列(第一个字段)和第二列(第二个字段)以输出分隔符隔开后显示。

#! /bin/bash
awk -v FS='#'  '{print $1$2}' demo.txt

输出结果

123abc
456def
789ghi

逻辑判断

语法

awk '条件 动作' 文件名

==,!=,<,>判断逻辑表达式

awk -F ':' '$3>100{print $1,$3}' /etc/passwd

函数

  • tolower():字符转为小写。
  • length():返回字符串长度。
  • substr():返回子字符串。
  • sin():正弦。
  • cos():余弦。
  • sqrt():平方根。
  • rand():随机数

参考

https://www.zsythink.net/archives/tag/awk