4 读取输入文件¶
4.1 分割输入文件¶
4.1.1 标准awk的记录分割¶
awk中默认的记录分隔符号是换行,也就是一行一个记录。如果我们不想使用默认的记录分割,可以指定RS.
[root@centos74 test]$ awk 'BEGIN {RS="u"} NR <= 3 {print $0 }' mail-list
Amelia 555-5553 amelia.zodiac
sq
e@gmail.com F
Anthony 555-3412 anthony.assert
[root@centos74 test]$ head -n 3 mail-list
Amelia 555-5553 amelia.zodiacusque@gmail.com F
Anthony 555-3412 anthony.asserturo@hotmail.com A
Becky 555-7685 becky.algebrarum@gmail.com A
NR<=3指定了如果当前记录数量小于等于3,RS代表记录分隔符。
4.1.2 gawk记录分割使用多个分隔符¶
使用大小字母去分割一个字符串为多个记录
[root@centos74 test]$ echo "recode 1 AAAA recode 2 BBBB recode 3" | awk 'BEGIN {RS="\n|( *[[:upper:]]+ *)"} {print $0}'
recode 1
recode 2
recode 3
4.2 测试字段¶
根据某个字段去作为判定条件
[root@centos74 test]$ awk '$1 ~ /li/ {print $0}' mail-list
Amelia 555-5553 amelia.zodiacusque@gmail.com F
Julie 555-6699 julie.perscrutabor@skeeve.com F
4.3 非恒定的字段个数¶
awk中内置了一个变量来存储单个记录的字段个数,NF(numer of filed)。
[root@centos74 test]$ df
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/sda3 50264616 18816916 28871316 40% /
devtmpfs 1001532 0 1001532 0% /dev
tmpfs 1015956 0 1015956 0% /dev/shm
tmpfs 1015956 17596 998360 2% /run
tmpfs 1015956 0 1015956 0% /sys/fs/cgroup
/dev/sda5 20027216 315120 18671712 2% /app
/dev/sda1 999320 192360 738148 21% /boot
tmpfs 203192 36 203156 1% /run/user/0
[root@centos74 test]$ df |awk '{print $NF}'
on
/
/dev
/dev/shm
/run
/sys/fs/cgroup
/app
/boot
我们可以看出来。 我想去导入第二列的时候, 不用数数这是第几个。NF存储的是记录的属性个数,$NF就是最后一个属性列
4.4 字段的一些运算¶
[root@centos74 test]$ awk ' {$6 = ($5 + $4 + 20 ) * 10 ; print $6}' inventory-shipped
4.5 指定字段分隔符¶
记录的默认分割符号是换行,字段的默认的分割符号是空格,当然也是可以修改的。
4.5.1 修改字段分隔符¶
修改默认的字符分割符号
[root@centos74 test]$ echo "a,b,c,d" | awk -F "," '{print $2}'
b
[root@centos74 test]$ echo "a,b,c,d" | awk 'BEGIN{FS=","}{print $2}'
b
第一种方式是通过命令行参数方式设定的,简单方便。
4.5.2 多个字段分割符号¶
有时候我们分割字段的时候,既想tab分割又想空格分割,可以考虑如下方案:
[root@centos74 test]$ echo "a,b,c d:f" | awk 'BEGIN{FS="[ ,]" } {print "$1="$1, "$2="$2 , "$3="$3,"$4="$4}'
$1=a $2=b $3=c $4=d:f
4.5.3 分割记录单个字符就是一个字段¶
有时候我们需要将一个单词拆成一个一个字符的。可以参考如下:
[root@centos74 test]$ echo "adsjfsdj" |awk 'BEGIN{FS=""} {print $1,$NF}'
a j
4.5.4 合并所有行为但一行, 每行作为一个属性字段¶
方法比较简单就是设定字段的分隔符号为`n`即可。
4.6 读取固定宽度的数据¶
4.6.1 处理固定宽度的数据¶
linux下好多命令输出都是固定宽度的,比如w命令,如何提取这些数据呢?
[root@centos74 test]$ w | awk 'BEw | awk 'BEGIN { FIELDWIDTHS="9 6 10 6 7 7 35"}
NR > 2 {
print $1 ,$2 $5
}'
root :0 Thu
root tty2 Fri
root pts/0 08:
root pts/1 09:
4.6.1 固定字段宽度的一些问题¶
我们固定了字段的宽度,但是输入数据刚刚好,那是非常好的, 有时候可能传过来的多了或者少了。这种情况gawk是如何处理的。
- 刚好的字段
- 如果FIELDWIDTHS=”2 3 4” ,输入记录是”aabbbcccc”,这样的话刚刚好,$1=”aa”, $2=”bbb”,$3=”cccc”
- 缺宽度的字段
- 如果FIELDWIDTHS=”2 3 4” ,输入记录是”aabbbccc”,这样的话刚刚好,$1=”aa”, $2=”bbb”,$3=”ccc”
- 多宽度的字段
- 如果FIELDWIDTHS=”2 3 4” ,输入记录是”aabbbccccdd”,这样的话刚刚好,$1=”aa”, $2=”bbb”,$3=”cccc”,多余的dd就被丢弃了。如果想使用可以最后一个字段使用*代替
4.7 csv文件的处理¶
这里有一个csv文件,想提取出来名字和带引号的字段。
Robbins,Arnold,"1234 A Pretty Street, NE",MyTown,MyState,12345-6789,USA
考虑到引号里面有,所以如果使用,去分割这个csv文件的时候会出错的。
[root@centos74 test]$ vim addresses.csv
[root@centos74 test]$ cat addresses.csv
Robbins,Arnold,"1234 A Pretty Street, NE",MyTown,MyState,12345-6789,USA
[root@centos74 test]$ vim addresses.awk
[root@centos74 test]$ cat addresses.awk
BEGIN {
FPAT="([^,]+)|(\"[^\"]+\")"
}
{
print "NF=" ,NF
for (i=1;i <=NF; i++){
printf("$%d =<%s>\n" ,i,$i)
}
}
[root@centos74 test]$ gawk -f addresses.awk addresses.csv
NF= 7
$1 =<Robbins>
$2 =<Arnold>
$3 =<"1234 A Pretty Street, NE">
$4 =<MyTown>
$5 =<MyState>
$6 =<12345-6789>
$7 =<USA>
上面的为何就是可以只能的识别出双引号中的逗号呢。 关键就是EPAT的正则表达式。简单说下这个正则表达式把。 “|”跟个2个部分,第二部分代表引号开头,中间是非引号多次,最后一个引号。
4.8 检查awk使用的字段分割方案¶
上面我们提到了几种分割方案
[root@centos74 test]$ echo "abc" |awk 'BEGIN{
if (PROCINFO["FS"] == "FS")
print "BASIC"
else if (PROCINFO["FS"] == "FIELDWIDTHS")
print "FIELDWIDTHS"
else if (PROCINFO["FS"] == "FPAT")
print "FPAT"
else
print "else"
}'
BASIC