使用awk命令处理一个或多个文件时,它会依次读取文件的每一行内容,然后对其进行处理,awk命令默认从stdin标准输入获取文件内容,awk使用一对单引号来表示一些可执行的脚本代码,在可执行脚本代码里,使用一对花括号来表示一段可执行代码块。awk的每个花括号内同时又可以有多个指令,每一个指令用分号分隔。
awk默认的分隔符: 空格和制表符
内置特殊变量
- NR: 表示文件中的行号,即当前是第几行
- NF: 表示文件中每一行的列数
- $0: 这个变量包含执行过程中当前行的文本内容
- $1: 表示文本行被分隔后的第1个字段列
- $2: 表示文本行被分隔后的第2个字段列
- $N: 表示文本行被分隔后的第N个字段列
- FILENAME: 表示当前文件的文件名称
常规操作
# 打印分隔后的第N列
ls -al | awk '{print $9}'
awk '{print $1}' mail.txt
# 自定义分隔符
awk -F : '{print $1}' mail.txt
# 自定义多个分隔符
awk -F [:+] '{print $1}' linux.doc
# 打印分隔后的指定列
awk -F [:+] '{print $1,$2,$3}' linux.doc
awk -F [:+] '{print $1$2$3}' linux.doc
PS:
其中加入逗号表示插入输出分隔符,也就是默认的空格
# 对输出列进行重新赋值
awk '{$1="java";print $1,$2}' mail.txt
# 对输出内容进行格式化
awk '{print $1 "\t" $2}' mail.txt
awk '{print $1 "-" $2}' mail.txt
内置变量用法
# 打印每一行的行号
awk '{print NR ": " $2}' mail.txt
# 打印每一行的列数
awk '{print NF ": " $2}' mail.txt
# 打印分隔后每一行的最后一列
awk '{print $NF}' mail.txt
# 打印每一行的倒数第二列
awk '{print $(NF-1)}' mail.txt
# 打印当前文件的文件名
awk '{print FILENAME ": " $NF}' mail.txt
BEGIN & END
awk 'BEGIN{print "start awk"} {print $0} END{print "end awk."}' mail.txt
- 在脚本代码段前使用BEGIN关键字时,它会在开始读取一个文件之前,运行一次 BEGIN关键字后面的脚本代码段,BEGIN后面的脚本代码段只会执行一次。
- awk的END指令和BEGIN恰好相反,在awk读取并且处理完文件的所有内容之后, 才会执行END后面的脚本代码段。
高级使用
# 声明变量并使用
awk '{str="hello ";print str "\t" $1}' mail.txt
awk 'BEGIN{str="hello "}{print str "\t" $1}' mail.txt
# 使用数学运算
awk '{a=12;b=13;print a+b}' mail.txt
awk '{a=12;b=13;print "a+b="a+b}' mail.txt
awk 'BEGIN{a=12;b=13;print "a+b="a+b}' mail.txt
# 使用条件判断
awk '$1=="java"{print $0}' mail.txt
awk '{if($1!="linux")print $0}' mail.txt
# 使用正则表达式
awk '/linux/{print $0}' mail.txt
awk '/^linux/{print $0}' mail.txt
# 打印文件中第M到N行(收尾包括)
awk 'NR==3,NR==5' mail.txt
# 使用for循环
awk 'BEGIN {for(i=0;i<5;i++)print i}'
# BEGIN & for & END
seq 1 | awk 'BEGIN{print "start."}{for(i=0;i<5;i++)print i}END{print "end!"}'
# 使用seq 1是为了for循环代码只会执行一次
# shell脚本中,使用`\`可以很方便地将单行命令拆解成多行
行转列
#!/usr/bin/env bash
name="Jaemon"
score="150"
awk -v name=${name} -v score=${score} '
BEGIN{
printf "name=%-30s score=%30d\n", name,score
}
{
for(i=1;i<=NF;i++)
a[i,NR]=$i
}
END{
for(i=1;i<=NF;i++) {
for(j=1;j<=NR;j++)
printf a[i,j] "\t\t";
print ""
}
}' ./list.txt
-
-v
: 将shell脚本中的变量值传递到awk中 -
BEGIN & END
中的代码只执行一次
书名 作者 日期
java Jame 2020
linux kob 2021
输出结果
name=Jaemon score= 150
书名 java linux
作者 Jame kob
日期 2020 2021