文本处理三驾马车之 awk

2024-02-23 10:42:05 浏览数 (2)

Awk 是一个强大的文本分析工具,它每次读入一条记录,并把每条记录切分成字段后进行分析。Awk 官方文档是非常好的学习材料,通过man awk查看。

代码语言:javascript复制
awk 'BEGIN { action } pattern { action } END { action }'

Awk 程序通常是一系列 pattern {action}对:

pattern,表示模式匹配,只处理匹配的行。pattern 可以省略,表示匹配所有行

action,表示对匹配行所做的动作。{actions}可以省略,表示{ print }。BEGINEND的{action}不能省略

pattern 可能是:

BEGIN, 执行初始化操作,程序开始时执行一次

END,执行收尾工作,程序结束时执行一次

expression,一个表达式,既可以是判断语句,也可以是正则表达式

常用参数

  • -F value 设置域分隔符,相当于给 FS 内置变量赋值
  • -v var=value 将变量 value 的值赋给程序变量 var,-v 可以多次使用

记录与字段

记录是一次读入的内容,通常是文件的一行,保存在字段变量

0中,记录可以被分割成字段,保存在变量

1,

2,...,

NF 中。

表达式与操作符

Awk 表达式的符号与 C 语言的类似,基本的表达式有数字,字符串,变量,字段,数组以及函数调用。变量无需声明,它们在首次使用时被初始化为null

代码语言:javascript复制
assignment          =   =  -=  *=  /=  %=  ^=
conditional         ?  :
logical and         &&
logical or          ||
logical not         !
array membership    in
matching       		~   !~
relational          <  >   <=  >=  ==  !=
concatenation       (no explicit operator)
add ops                -
mul ops             *  /  %
unary                  -
exponentiation      ^
inc and dec            -- (both post and pre)
field               $

正则表达式

在 Awk 中语言中,通常测试一个记录、字段或字符串是否与一个正则表达式匹配,匹配返回 1,不匹配返回 0。正则表达式用两个反斜杠/包围。

代码语言:javascript复制
expr ~ /r/							 # 评估expr是否与r匹配。匹配的意思是expr的一个子串是否在正则表达式r定义的字符串集中。

/r/ { action }, $0 ~ /r/ { action }	 # 两者相同, /r/ 等于 $0 ~ /r/

任何表达式都可以放到~!~右边或者内建的需要正则表达式的地方。在必要的时候,该表达式会被转变成字符串,然后作为一个正则表达式来解释。以下三行 awk 命令完成同样的功能:输出第 5 列为 10 的的行。

代码语言:javascript复制
seq 20 | xargs -n5 > file
# cat file
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20

awk '$5 ~ /10/' file
awk '$5 ~ "10"' file
awk '$5 ~ 10' file

数组

Awk 支持一维数组。其表示方法为array[expr]expr在内部被统一转换成字符串类型,因此 A[1],与 A["1"]相同,事实上索引都是“1”。索引为字符串的数组被称为关联数组。expr in array用于判断数组元素 array[expr]是否存在。

代码语言:javascript复制
for ( var in array ) statement

控制语句

代码语言:javascript复制
if ( expr ) statement
if ( expr ) statement else statement
while ( expr ) statement
do statement while ( expr )
for ( opt_expr ; opt_expr ; opt_expr ) statement
for ( var in array ) statement
continue
break

内置变量

  • NR - 当前行数
  • NF - 当前行的列数
  • RS,行分隔符,默认是换行符
  • FS,列分隔符,默认是空格和制表符
  • ORS,输出行分隔符,默认为换行符
  • OFS,输出列分隔符,默认为空格
  • FILENAME,当前文件名

内置函数

字符串函数

sub()、substr()、gsub(),sprintf(),index(),length(), match(),split(),tolower(), toupper()

数学函数

sin(),cos(), ...

输入输出

有两个输出语句,printprintf

代码语言:javascript复制
print# 打印整条记录到标准输出,相当于print $0
print expr1, expr2, ..., exprn	# 打印指定字段到标准输出
printf format, expr-list	# C语言printf函数的重用

输入函数 getline 有以下几种形式:

代码语言:javascript复制
getline				# 读取下一条记录到 $0,更新NF,NR和FNR
getline var			# 读取下一条记录到var,更新NR和FNR
getline < file			# 从文件读取记录到 $0,更新NF
getline var < file		# 从文件读取记录到var
command | getline		# 通过管道传递command的结果到 $0,更新NF
command | getline var		# 通过管道传递command的结果到var
代码语言:javascript复制
seq 10 | awk '{print $0;getline}'# 显示奇数行
seq 10 | awk '{getline; print $0}'# 显示偶数行
seq 10 | awk '{getline tmp; print tmp; print $0}'# 奇偶行对调

awk 'BEGIN {"date" | getline;close("date");print $0}'# 得到系统当前时间

# fastq转换成fasta
awk '{getline seq; getline comment; getline quality; sub("@", ">", $0); print $0"n"seq}' file

示例

代码语言:javascript复制
awk '{print $0}' file	# 打印整行
awk '{print $1}' file	# 打印第一列
awk '{print $2}' file	# 打印第二列
awk '{print $NF}' file	# 打印最后一列
awk '{print $(NF-1)}' file#打印倒数第二列
awk -F ';' -v OFS='t''{print $1,$2,$NF}' file	# 读入的文件以逗号;分隔列,打印第1列,第2列和最后一列,并且打印时以制表符作为列的分隔符
number=10;awk -v n=$number'{print n}' file	# number的值被传给了程序变量n
awk '$2 > 100' file		# 打印第2列大于100的行
awk 'NR>1 && NR<4' file         # 打印第2~3行

awk '/EGFR/' file		# 打印含有EGFR的行,相当于grep EGFR file
awk '$1 ~ /EGFR/' file	        # 打印第1列含有EGFR的列

# 按指定列去除重复行
# cat file
1 2 3 4 5
6 2 8 9 10
11 12 13 14 15
16 17 18 19 20
awk '!a[$2]  ' file		# 第二列出现两次2,只保留第一次出现的那一行,结果如下:
1 2 3 4 5
11 12 13 14 15
16 17 18 19 20

awk '{sum =$1} END {print sum}' file	# 累加文件的第一列
awk '{sum =$1} END {print sum/NR}' file	# 求第一列的平均数

# 从含有多条fasta序列的文件中提取指定序列
 awk -v RS=">"'/chr1/ {print $0}' hg19.fa	# 提取chr1的序列
 awk -v RS=">"'/chr1|chr2/ {print $0}' hg19.fa	# 提取chr1和chr2的序列

0 人点赞