通常在过滤匹配字符串的时候,我们会使用grep
命令,而挑选打印出匹配行的某列,又会去结合awk
,例如筛选出以下xml中的IP地址,如果采用grep
命令过滤出ip行再传递给awk
处理就非常raw了,特别是需要多次过滤。
<?xml version="1.0" encoding="utf-8"?>
<rsp>
<code>200</code>
<msg>successful</msg>
<data>
<ips list="true">
<item>
<ip>192.168.1.9</ip>
<vlan_id>1234</vlan_id>
<network>public</network>
</item>
<item>
<ip>192.168.1.101</ip>
<vlan_id>1234</vlan_id>
<network>public</network>
</item>
<item>
<ip>192.168.1.193</ip>
<vlan_id>1234</vlan_id>
<network>public</network>
</item>
<item>
<ip>192.168.1.2</ip>
<vlan_id>1234</vlan_id>
<network>public</network>
</item>
</ips>
</data>
</rsp>
awk
其实支持几乎所有的grep
功能,其搜索字符串非常高效,以下是处理方法:
awk -F "[<>]" '/ip/ && /[0-9]./ {print $3}' ip.xml
说明:
/XXXX/
表示搜索XXXX
字符串&&
符号表示同时满足两个搜索条件,即字符串中既包含"ip"又包含"数字+.";如果要表示或
逻辑,就使用||
- 支持正则表达
[]
再举个简单的例子,假如要读取一个配置文件 config.ini
中键值对,并累加计数,即读取出数值是1的时候,加上1等于2再回写配置文件
val=`awk -F= "/^$key=/{print \\$2}" $CONFIG_FILE`
if [ -z "$val" ]; then
val=1
echo "$key=$val" >> $CONFIG_FILE
else
let val+=1
sed -i 's/^\('$key'=\).*$/\1'$val'/' $CONFIG_FILE
fi
案例文件内容
Medicine,200
Grocery,500
Rent,900
Grocery,800
Medicine,600
输出大于500
的行
awk -F, '$2>500' file
输出大于500
且包含Medicine
的行
awk -F, '/Medicine/ && $2>500' file
输出包含Medicine
或值大于600
的行
awk -F, '/Medicine/ || $2>600' file
上述大于值的过滤在 print line only if number in third field is greater than X [duplicate] 也有一个类似查看磁盘容量大于某个值的查询
lsblk -bio KNAME,TYPE,SIZE,MODEL| awk '/disk/ && $3> 300000000000 || NR==1'
上述
NR==1
是为了保留输出的头部第一行
举例,我的虚拟机
$lsblk -bio KNAME,TYPE,SIZE,MODEL
KNAME TYPE SIZE MODEL
vda disk 42949672960
vda1 part 42948607488
vdb disk 536870912000
vdb1 part 249999392768
则执行
lsblk -bio KNAME,TYPE,SIZE,MODEL | awk '/disk/ && $3> 300000000000 || NR==1'
输出结果
KNAME TYPE SIZE MODEL
vdb disk 536870912000
remove lines where a field's value is less than or equal to 3 - sed or awk?
awk '(NR>1) && ($8 > 2 ) ' foo > bar
对于
类似grep -i linux file
可以匹配Linux
和lINux
这样的字符串,awk
也提供内建的变量表达:
awk '/linux/' IGNORECASE=1 file
类似grep -c Unix file
,awk
提供如下计算方法
awk '/Unix/{x++;}END(print x)' file
这里变量就是"Unix"字符串匹配时候自增量的变量,最后END
时候输出变量x
就计算出匹配"Unix"的次数。
类似grep -l AIX file*
(这里grep
的-l
不打印匹配字符串,而只是打印包含匹配字符串的文件名),对应awk
提供了如下解决方法:
awk '/AIX/{print FILENAME;nextfile}' file*
awk
有一个特殊的变量FILNAME
包含当前工作的文件的文件名。所以,当匹配时候打印这个变量就是列出了匹配字符串的文件的文件名。nextfile
是awk
的命令表示退出当前文件并开始在新文件上工作。如果不使用nextfile
命令,如果这个匹配字符串在文件中出现2次,则文件名会被打印2次。
grep
命令有一个参数-n
可以打印出匹配的字符串的行号,例如:
grep -n Unix file
输出显示
1:Unix
7:Unix
对应awk
可以使用内建的NR
变量来输出行号:
awk '/Unix/{print NR":"$0}' file
使用grep
的参数-E
可以启用正则表达式匹配,例如:
grep -E 'Linux|Solaris' file
可以匹配输出如下
Linux
Solaris
对应awk
是直接支持正则表达式,无需任何参数:
awk '/Linux|Solaris/' file
如果要输出所有不包含Linux
字符串的行
greo -v Linux file
这里grep
命令的-v
参数表示inverse
对应awk
命令可以使用!
表示取反
awk '!/Linux/' file
grep
命令的参数-A1
表示匹配行和之后(After
)1行
grep -A1 Linux file
输出是
Linux
Solaris
在awk
中,提供了getline
命令表示从缓存中获取下一行并保存在变量$0
中,所以这里在getline
命令之后再print
就会打印出下一行。当然,在getline
命令之前的print
就是打印匹配行
awk '/Linux/{print;getline;print}' file
grep
命令的参数-B1
表示匹配行和之前(Before
)1行
grep -B1 Solaris file
输出是
Linux
Solaris
对应在awk
中,有一个变量x
,当匹配上字符串的时候,这个变量x
中存储的是上一行,所以,当打印这个x
之后,再使用next
指令将指针移动到下一行,此时把$0
也就是匹配行复制给x
再打印一次,就会打印出当前匹配行:
awk '/Solaris/{print x;print;next}{x=$0;}' file
grep
的-C1
参数可以打印匹配行前后行:
grep -C1 Solaris file
输出是
Linux
Solaris
AIX
对应awk
命令则结合前面两个案例如下:
awk '/Solaris/{print x;print;getline;print;next}{x=$0}' file
awk '{s+=$1} END {print s}' mydatafile
因为需要结合awk数据结果和特定字符串,所以希望awk输出结果后不换行
awk '{sum+=$3}; END {printf "%f",sum/NR}' ${file}_${f}_v1.xls >> to-plot-p.xls
printf
- 过滤出使用
cpu 24
的进程,也就是匹配字段4中数字是24
的列以后打印匹配行的2列内容
ps -TA -o tid,pid,ppid,psr,cmd | awk '{if($4=='24') print $1" "$5}' | tee cpu_24