grep -> 更适合单纯的查找或匹配文本
sed -> 更适合编辑匹配到的文本
awk -> 更适合格式化文本,对文本进行较复杂格式处理
首先来看下awk的基本用法及选项参数:
用法: awk [POSIX 或 GNU 风格选项] -f 脚本文件 [--] 文件 ...
用法: awk [POSIX 或 GNU 风格选项] [--] '程序' 文件 ...
POSIX 选项: GNU 长选项:
-f 脚本文件 --file=脚本文件
-F fs --field-separator=fs #指定分隔符,可以为字符串或正则表达式,例如 -F,
-v var=val --assign=var=val #给自定义的变量赋值
-m[fr] val
-O --optimize
-W compat --compat
-W copyleft --copyleft
-W copyright --copyright
-W dump-variables[=file] --dump-variables[=file]
-W exec=file --exec=file
-W gen-po --gen-po
-W help --help
-W lint[=fatal] --lint[=fatal]
-W lint-old --lint-old
-W non-decimal-data --non-decimal-data
-W profile[=file] --profile[=file]
-W posix --posix
-W re-interval --re-interval
-W source=program-text --source=program-text
-W traditional --traditional
-W usage --usage
-W use-lc-numeric --use-lc-numeric
-W version --version
例如存在这样的 ip.log 文件,里面记录的内容如下:
mike 127.0.0.1 8593
tomy 192.168.0.136 489
pony 10.200.123.256 5796
jack 10.121.20.236 17896
用法一:
awk '{[pattern] action}' {filenames} # 行匹配语句 awk '' 只能用单引号
实例: 每行按空格或tab切分并输出第一列和第三列的行
awk '{print $1,$3}' ip.log
awk '{printf "%-20s %-20s\n",$1,$3}' ip.log ##格式化输出
##输出结果
mike 8593
tomy 489
pony 5796
jack 17896
mike 8593
tomy 489
pony 5796
jack 17896
注意:
1、awk命令默认的分隔符是空格或tab;
2、awk中同时提供了print和printf两种打印输出的函数。其中print函数的参数可以是变量、数值或者字符串。字符串必须用双引号引用,参数用逗号分隔。如果没有逗号,参数就串联在一起而无法区分。这里,逗号的作用与输出文件的分隔符的作用是一样的,只是后者是空格而已。printf函数,其用法和c语言中printf基本相似,可以格式化字符串,输出复杂时,printf更加好用,代码更易懂。
用法二:
awk -F
实战: ip.log内容改成如下,取","分割输出第一、第三列
mike,127.0.0.1,8593
tomy,192.168.0.136,489
pony,10.200.123.256,5796
jack,10.121.20.236,17896
awk -F, '{print $1,$3}' ip.log
awk -F, '{printf "%-20s %-20s\n",$1,$3}' ip.log
##输出结果
mike 8593
tomy 489
pony 5796
jack 17896
mike 8593
tomy 489
pony 5796
jack 17896
当需要按照多个分隔符分隔时: 存在这样的文件 ip.log,需要按照"-"和"|"分隔
127.0.0.1-mike|8593
192.168.0.136-tomy|489
10.200.123.256-pony|5796
10.121.20.236-jack|17896
输出结果为:
127.0.0.1 mike 8593
192.168.0.136 tomy 489
10.200.123.256 pony 5796
10.121.20.236 jack 17896
延伸下: 如果需要把两个文件的同一行上的数据放在同一文件上,可以用 paste 命令
1.txt
1
2
3
2.txt
java
js
php
paste -d '#' 1.txt 2.txt > 3.txt #合并到3.txt文件中,并且以#分隔
##输出结果在 3.txt 文件中
1#java
2#js
3#php
用法三:
awk -v #添加变量
存在这样的文件 3.txt
1 2
2 3
3 4
awk -vx=1 -vy=2 '{printf "%-10s %-10s\n",$1+x,$2y}' 3.txt
输出结果为:
2 2a
3 3a
4 4a
使用正则匹配
awk '$1 ~ /mike/ {printf "%-10s %-10s\n",$1,$2}' ip.log
如上实例表示匹配第一列中包含 "mike" 的行,"~"表示开始匹配,"//"表示匹配的内容
awk '/s/ ' ip.log ##表示在ip.log文件中输出包含"s"的行
awk脚本
awk脚本的基本结构如下
{BEGIN……} {command} {END……}
BEGIN表示执行前的语句,command表示处理每一行的语句,END表示处理完所有行后执行的语句
实例: 存在如下的 statistic.txt
pony 2597 5698 1236
mike 2459 3564 5683
rose 3598 7456 5562
编写统计awk脚本 statistic.awk
BEGIN{
java=0
php=0
python=0
printf "name java php python total\n"
printf "----------------------------------------------------------------\n"
}
{
java+=$2
php+=$3
python+=$4
printf "%-10s %-10s %-10s %-10s %-10s\n",$1,$2,$3,$4,$2+$3+$4
}
END {
printf "----------------------------------------------------------------\n"
printf "total: %-10s %-10s %-10s\n",java,php,python
printf "average: %-10.2f %-10.2f %-10.2f\n",java/NR,php/NR,python/NR
}
编写test.sh
#!/bin/bash
awk -f statistic.awk statistic.txt
输出结果
name java php python total
----------------------------------------------------------------
pony 2597 5698 1236 9531
mike 2459 3564 5683 11706
rose 3598 7456 5562 16616
---------------------------------------------------
total: 8654 16718 12481
average: 2884.67 5572.67 4160.33