有人说,相比一般的linux指令,awk更像是一门语言一样,有非常庞大的体系。awk和sed一样都是文本编辑器。awk最常见的范式如下:
awk [命令行参数选项] 'BEGIN{命令 } pattern{ 命令 } END{ 命令 }' 文件名
awk '{print}' employee.txt 等同于 cat emokiyee.txt
awk '/manager/ {print}' employee.txt 用来匹配manager的行。所以awk也有grep抽取过滤的功能
awk is meant for processing column-oriented text data, such as tables, presented to it on standard input. The variables $1, $2, and so forth are the contents of the first, second, etc. column of the current input line. For example, to print the second column of a file, you might use the following simple awk script:
awk < file '{ print $2 }'
打印file的第二列 $1就是第一列
awk < file '{ print $2, $3 }'
输出第二第三列,windows好像搞不了输入重定向 < (我用的是cygwin),可以cat file | awk '{$1,$2}'
。
-F 指定读取文件的分隔符,默认是空格,所以可以 -F "\t"表示分隔符改为制表符
如
echo '192.168.1.1' | awk -F "." '{print $2}'
;
awk是一种弱类型语言。所有数字都是浮点数。可以用awk进行算术运算
awk < file '{ print ($1-32)*(5/9) }'
可以把文件里的第一列所有数字都从华氏转为对应的摄氏写到result里。
seq 250 | shuf > numbers.txt
awk < numbers.txt '{print ($1 -32)*5/9 }' > results
echo 5 4 | awk '{ print $1 + $2 }' #输出的是9
echo 5 4 | awk '{ print $1 $2 }' #输出的是54,进行了字符串拼接。
awk 自建的变量:列的引用:$1 , $2 , … , $NF (引用最后一列,类似与python的-1)等,还有NF = # of fields,就是每行的列数。$0 表示整个输入行,也就是该行所有内容 cat awk.txt | awk '{print $0}'
等同于 cat awk.txt
.。除非是awk里保留的变量,你可以自定义变量,无须声明。
$0
当前记录(这个变量存放当前行的内容
n
当前记录的第n个字段,字段由分隔符FS分割
FS
输入字段分隔符,默认是空格或Tab
NF
当前记录中的字段个数,就是有多少列
NR
已经读出的记录数,就是行号,从1开始,如果有多个文件的话,这个值也是不断累加中
FNR
当前记录数,与NR不同的是,这个值是各自文件自己的行号
RS
输入的记录分隔符,默认是换行符
OFS
输出字段分隔符,默认也是空格
ORS
输出的记录分隔符,默认是换行符
FILENAME
当前输入文件的名字
awk还有其他自建的变量如下,复制自geekforgeek.
NR: NR command keeps a current count of the number of input records. Remember that records are usually lines. Awk command performs the pattern/action statements once for each record in a file. NR:表示当前处理的是第几行
NF: NF command keeps a count of the number of fields within the current input record.NF:表示当前行有多少个字段,因此$NF就代表最后一个字段
FS: FS command contains the field separator character which is used to divide fields on the input line. The default is “white space”, meaning space and tab characters. FS can be reassigned to another character (typically in BEGIN) to change the field separator.
RS: RS command stores the current record separator character. Since, by default, an input line is the input record, the default record separator character is a newline.
OFS: OFS command stores the output field separator, which separates the fields when Awk prints them. The default is a blank space. Whenever print has several parameters separated with commas, it will print the value of OFS in between each parameter.
ORS: ORS command stores the output record separator, which separates the output lines when Awk prints them. The default is a newline character. print automatically outputs the contents of ORS at the end of whatever it is given to print.
FILENAME: 正在被读取的文件的名称。(常用在多行脚本中 用于获取文件名) 当前文件名
OFMT:数字输出的格式,默认为%.6g。表示只打印小数点后6 位
awk '{print NR,$0}' employee.txt $0代表文件内容。awk是每行执行,所以每次会输出 行号加对应行内容
1 ajay manager account 45000
2 sunil clerk account 25000
3 varun manager sales 50000
4 amit manager account 47000
5 tarun peon sales 15000
6 deepak clerk sales 23000
7 sunil peon sales 13000
8 satvik director purchase 80000
用awk写简单的程序
seq 250 | shuf > numbers.txt
seq 250 | shuf > numbers2.txt
paste numbers.txt numbers2.txt > add_numbers.txt
awk < add_numbers.txt '{ tot=0; for (i=1; i<=NF; i++) tot += $i; print tot/NF; }'
接受file为输入,file的每行 算平均值 输出
awk有两个特殊的模式 BEGIN 和 END ,以下则是它们对应的含义:
BEGIN 模式:是指 awk 将在读取任何输入行之前立即执行BEGIN 中指定的动作。
END 模式:是指 awk 将在它正式退出前执行 END中指定的动作。
awk '{ tot += $1; n += 1; } END { print tot/n; }' 这个还是每行的第一列数相加,求平均值,但只在按行循环加完之后,才计算输出平均值!
可以看这里的解读
https://www.linuxprobe.com/awk-begin-end.html
两个中括号框起来就是一个block代码块,可以在block前加条件,满足条件才运行
awk ' $1==0 { print $2 }' 当第一列是0的时候,才输出第二列的值
awk ' /^test/ { print $2 }' 当该行匹配上正则表达式时,输出第二列的值
$ cat score.txt
tom 60 60 60
kitty 90 95 87
jack 72 84 99
$ awk '$2>=90{print NR $0}' score.txt #输出第二列大于90分的对应的那一行
kitty 90 95 87
awk支持if-else这样的条件。还是
seq 250 | shuf > numbers.txt
seq 250 | shuf > numbers2.txt
paste numbers.txt numbers2.txt > add_numbers.txt
awk '{if($1>40) $2 = 0 ; else $2=1} {print $0}' numbers.txt #第一列的数字如果大于40,第二列就赋值为0,否则赋值为1.并输出结果
The block conditions BEGIN and END are special and are run before processing any input, and after processing all input, respectively.
假如你在 awk 脚本中使用了特殊模式:BEGIN 和 END ,以下则是它们对应的含义:
awk '
BEGIN { actions }
/pattern/ { actions }
/pattern/ { actions }
……….
END { actions }
' filenames
awk脚本的常用结构就是这样:
BEGIN { print "File\tOwner"}
{ print $8, "\t", $3}
END { print " - DONE -" }
#these two words specify actions to be taken before any lines are read, and after the last line is read.
BEGIN 模式:是指 awk 将在读取任何输入行之前立即执行BEGIN 中指定的动作。通过begin,可以做一些预先事务,例如定义表头
awk 'BEGIN{print "姓名 语文 数学 英语"}{printf "%-8s%-5d%-5d%-5d\n",$1,$2,$3,$4}' score.txt
END 模式:是指 awk 将在它正式退出前执行 END中指定的动作。
结合一些数学计算操作,可以算总分、平均值等放在表的底部。来自知乎
```bash
awk 'BEGIN{print "姓名 语文 数学 英语 总成绩"; \
sum1=0;sum2=0;sum3=0;sumall=0} \
{printf "%5s%5d%5d%5d%5d\n",$1,$2,$3,$4,$2+$3+$4;\
sum1+=$2;sum2+=$3;sum3+=$4;sumall+=$2+$3+$4}\
END{printf "%5s%5d%5d%5d%5d\n","总成绩",sum1,sum2,sum3,sumall}'\
score.txt
```
作者:机智的程序员小熊
链接:https://zhuanlan.zhihu.com/p/68188159
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
awk 命令脚本的执行流程如下:
当在脚本中使用了 BEGIN 模式,则 BEGIN 中所有的动作都会在读取任何输入行之前执行。
然后,读入一个输入行并解析成不同的段。
接下来,每一条指定的非特殊模式都会和输入行进行比较匹配,当匹配成功后,就会执行模式对应的动作。对所有你指定的模式重复此执行该步骤。
再接下来,对于所有输入行重复执行步骤 2 和 步骤 3。
当读取并处理完所有输入行后,假如你指定了 END 模式,那么将会执行相应的动作。
当你使用特殊模式时,想要在 awk 操作中获得最好的结果,你应当记住上面的执行顺序。