正则表示法与文件格式化处理
先来介绍一些特殊的符号:
尤其上表中的[:alnum:], [:alpha:], [:upper:], [:lower:], [:digit:] 这几个一定要知道代表什么意思,因为他要比 a-z 或 A-Z 的用途要确定的很!好了,底下就让我们开始来玩玩进阶版的grep 吧!
[root@www ~]# grep [-A] [-B] [--color=auto] '搜寻字符串' filename
选项与参数:
-A :后面可加数字,为 after 的意思,除了列出该行外,后续的 n 行也列出来;
-B :后面可加数字,为 befer 的意思,除了列出该行外,前面的 n 行也列出来;
--color=auto 可将正确的那个撷取数据列出颜色
范例一:用 dmesg 列出核心讯息,再以 grep 找出内含 eth 那行
[root@www ~]# dmesg | grep 'eth'
eth0: RealTek RTL8139 at 0xee846000, 00:90:cc:a6:34:84, IRQ 10
eth0: Identified 8139 chip type 'RTL-8139C'
eth0: link up, 100Mbps, full-duplex, lpa 0xC5E1
eth0: no IPv6 routers present
# dmesg 可列出核心产生的讯息!透过 grep 来撷取网络卡相关信息 (eth) ,
# 就可发现如上信息。不过没有行号与特殊颜色显示!看看下个范例吧!
范例二:承上题,要将捉到的关键词显色,且加上行号来表示:
[root@www ~]# dmesg | grep -n --color=auto 'eth'
247:eth0: RealTek RTL8139 at 0xee846000, 00:90:cc:a6:34:84, IRQ 10
248:eth0: Identified 8139 chip type 'RTL-8139C'
294:eth0: link up, 100Mbps, full-duplex, lpa 0xC5E1
305:eth0: no IPv6 routers present
# 你会发现除了 eth 会有特殊颜色来表示之外,最前面还有行号喔!
范例三:承上题,在关键词所在行的前两行与后三行也一起捉出来显示
[root@www ~]# dmesg | grep -n -A3 -B2 --color=auto 'eth'
245-PCI: setting IRQ 10 as level-triggered
246-ACPI: PCI Interrupt 0000:00:0e.0[A] -> Link [LNKB] ...
247:eth0: RealTek RTL8139 at 0xee846000, 00:90:cc:a6:34:84, IRQ 10
248:eth0: Identified 8139 chip type 'RTL-8139C'
249-input: PC Speaker as /class/input/input2
250-ACPI: PCI Interrupt 0000:00:01.4[B] -> Link [LNKB] ...
251-hdb: ATAPI 48X DVD-ROM DVD-R-RAM CD-R/RW drive, 2048kB
Cache, UDMA(66)
# 如上所示,你会发现关键词 247 所在的前两行及 248 后三行也都被显示出来!
# 这样可以让你将关键词前后数据捉出来进行分析啦!
在关键词的显示方面,grep 可以使用 --color=auto 来将关键词部分使用颜色显示。 这可是个很不错的功能啊!但是如果每次使用 grep 都得要自行加上 --color=auto 又显的很麻烦~ 此时那个好用的 alias 就得来处理一下啦!你可以在 ~/.bashrc 内加上这行:『alias grep='grep --color=auto'』再以『 source ~/.bashrc 』来立即生效即可喔! 这样每次执行 grep 他都会自动帮你加上颜色显示啦!
搜寻特定字符串
搜寻特定字符串很简单吧?假设我们要从刚刚的档案当中取得 the 这个特定字符串,最简单的方式就是这样:
[root@www ~]# grep -n 'the' regular_express.txt
8:I can't finish the test.
12:the symbol '*' is represented as start.
15:You are the best is mean you are the no. 1.
16:The world <Happy> is the same with "glad".
18:google is the best tools for search keyword.
那如果想要『反向选择』呢?也就是说,当该行没有 'the' 这个字符串时才显示在屏幕上,那就直接使用:
[root@www ~]# grep -vn 'the' regular_express.txt
你会发现,屏幕上出现的行列为除了 8,12,15,16,18 五行之外的其他行列! 接下来,如果你想要取得不论大小写的 the 这个字符串,则:
[root@www ~]# grep -in 'the' regular_express.txt
8:I can't finish the test.
9:Oh! The soup taste good.
12:the symbol '*' is represented as start.
14:The gd software is a library for drafting programs.
15:You are the best is mean you are the no. 1.
16:The world <Happy> is the same with "glad".
18:google is the best tools for search keyword.
除了多两行 (9, 14行) 之外,第 16 行也多了一个 The 的关键词被撷取到喔!
例题二、利用中括号 [] 来搜寻集合字符
如果我想要搜寻 test 或 taste 这两个单字时,可以发现到,其实她们有共通的 't?st' 存在~这个时候,我可以这样来搜寻:
[root@www ~]# grep -n 't[ae]st' regular_express.txt
8:I can't finish the test.
9:Oh! The soup taste good.
了解了吧?其实 [] 里面不论有几个字符,他都仅代表某『一个』字符, 所以,上面例子说明了,我需要的字符串是『tast』或『test』两个字符串而已! 而如果想要搜寻到有 oo 的字符时,则使用:
[root@www ~]# grep -n 'oo' regular_express.txt
1:"Open Source" is a good mechanism to develop programs.
2:apple is my favorite food.
3:Football game is not use feet only.
9:Oh! The soup taste good.
18:google is the best tools for search keyword.
19:goooooogle yes!
但是,如果我不想要 oo 前面有 g 的话呢?此时,可以利用在集合字符的反向选择 [^] 来达成:
[root@www ~]# grep -n '[^g]oo' regular_express.txt
2:apple is my favorite food.
3:Football game is not use feet only.
18:google is the best tools for search keyword.
19:goooooogle yes!
再来,假设我 oo 前面不想要有小写字符,所以,我可以这样写 [^abcd....z]oo , 但是这样似乎不怎么方便,由于小写字符的 ASCII 上编码的顺序是连续的, 因此,我们可以将它简化为底下这样:
[root@www ~]# grep -n '[^a-z]oo' regular_express.txt
3:Football game is not use feet only.
那么如果我们的要求字符串是数字与英文呢? 呵呵!就将他全部写在一起,变成:[a-zA-Z0-9]。例如,我们要取得有数字的那一行,就这样:
[root@www ~]# grep -n '[0-9]' regular_express.txt
5:However, this dress is about $ 3183 dollars.
15:You are the best is mean you are the no. 1.
但由于考虑到语系对于编码顺序的影响,因此除了连续编码使用减号『 - 』之外, 你也可以使用如下的方法来取得前面两个测试的结果:
[root@www ~]# grep -n '[^[:lower:]]oo' regular_express.txt
# 那个 [:lower:] 代表的就是 a-z 的意思!请参考前两小节的说明表格
[root@www ~]# grep -n '[[:digit:]]' regular_express.txt
这样对于[] 以及 [^] 以及 [] 当中的 - ,还有关于前面表格提到的特殊关键词有了解了吗?^_^!
行首与行尾字符 ^ $
我们在例题一当中,可以查询到一行字符串里面有 the 的,那如果我想要让 the 只在行首列出呢? 这个时候就得要使用制表符了!我们可以这样做:
[root@www ~]# grep -n '^the' regular_express.txt
12:the symbol '*' is represented as start.
此时,就只剩下第 12 行,因为只有第 12 行的行首是 the 开头啊~此外, 如果我想要开头是小写字符的那一行就列出呢?可以这样:
[root@www ~]# grep -n '^[a-z]' regular_express.txt
2:apple is my favorite food.
4:this dress doesn't fit me.
10:motorcycle is cheap than car.
12:the symbol '*' is represented as start.
18:google is the best tools for search keyword.
19:goooooogle yes!
20:go! go! Let's go.
你可以发现我们可以捉到第一个字符都不是大写的!只不过 grep 列出得关键词部分不只有第一个字符, grep 是列出一整个字 (word) 说!同样的,上面的指令也可以用如下的方式来取代的:
[root@www ~]# grep -n '^[[:lower:]]' regular_express.txt
好!那如果我不想要开头是英文字母,则可以是这样:
[root@www ~]# grep -n '^[^a-zA-Z]' regular_express.txt
1:"Open Source" is a good mechanism to develop programs.
21:# I am VBird
# 指令也可以是: grep -n '^[^[:alpha:]]' regular_express.txt
注意到了吧?那个 ^ 符号,在字符集合符号(括号[])之内与之外是不同的! 在 [] 内代表『反向选择』,在 [] 之外则代表定位在行首的意义!要分清楚喔! 反过来思考,那如果我想要找出来,行尾结束为小数点 (.) 的那一行,该如何处理:
[root@www ~]# grep -n '\.$' regular_express.txt
1:"Open Source" is a good mechanism to develop programs.
2:apple is my favorite food.
3:Football game is not use feet only.
4:this dress doesn't fit me.
10:motorcycle is cheap than car.
特别注意到,因为小数点具有其他意义(底下会介绍),所以必须要使用跳脱字符(\)来加以解除其特殊意义,该行并没有输入任何数据,该如何搜寻?
[root@www ~]# grep -n '^$' regular_express.txt
任意一个字符 . 与重复字符 *
. (小数点):代表『一定有一个任意字符』的意思;
* (星星号):代表『重复前一个 0 到无穷多次』的意思,为组合形态
限定连续 RE 字符范围 {}
[root@www ~]# grep -n 'o\{2\}' regular_express.txt
1:"Open Source" is a good mechanism to develop programs.
2:apple is my favorite food.
3:Football game is not use feet only.
9:Oh! The soup taste good.
18:google is the best tools for search keyword.
19:goooooogle yes!
假设我们要找出 g 后面接 2 到 5 个 o ,然后再接一个 g 的字符串,他会是这样:
[root@www ~]# grep -n 'go\{2,5\}g' regular_express.txt
18:google is the best tools for search keyword
那么,如果我想要的是 2 个 o 以上的 goooo....g 呢?除了可以是 gooo*g ,也可以是:
[root@www ~]# grep -n 'go\{2,\}g' regular_express.txt
基础正则表示法字符汇整 (characters)
再次强调:『正则表示法的特殊字符』与一般在指令列输入指令的『通配符』并不相同, 例如,在通配符当中的 * 代表的是『 0 ~ 无限多个字符』的意思,但是在正则表示法当中, * 则是『重复 0 到无穷多个的前一个 RE 字符』的意思~使用的意义并不相同,不要搞混了!
sed 工具
[root@www ~]# sed [-nefr] [动作]
选项与参数:
-n :使用安静(silent)模式。在一般 sed 的用法中,所有来自 STDIN 的数据一般都会被列出到屏幕上。但如果加上 -n 参数后,则只有经过 sed 特殊处理的那一行(或者动作)才会被列出来。
-e :直接在指令列模式上进行 sed 的动作编辑;
-f :直接将 sed 的动作写在一个档案内, -f filename 则可以执行 filename 内的sed 动作;
-r :sed 的动作支持的是延伸型正则表示法的语法。(预设是基础正的表示法语法)
-i :直接修改读取的档案内容,而不是由屏幕输出。
动作说明: [n1[,n2]]function
n1, n2 :不见得会存在,一般代表『选择进行动作的行数』,举例来说,如果我的动作是需要在 10 到 20 行之间进行的,则『 10,20[动作行为] 』
function 有底下这些咚咚:
a :新增,a 的后面可以接字符串,而这些字符串会在新的一行出现(目前的下一行)~
c :取代, c的后面可以接字符串,这些字符串可以取代 n1,n2 之间的行!
d :删除,因为是删除啊,所以 d 后面通常不接任何咚咚;
i :插入, i 得后面可以接字符串,而这些字符串会在新的一行出现(目前的上一行);
p :打印,亦即将某个选择的数据印出。通常 p 会与参数 sed -n 一起运作~
s :取代,可以直接进行取代的工作哩!通常这个 s 的动作可以搭配正则表示法!例如 1,20s/old/new/g 就是啦!
sed 光是用看的是看不懂的啦!所以又要来练习了!先来玩玩删除与新增的功能吧!
范例一:将 /etc/passwd 的内容列出并且打印行号,同时,请将第 2~5 行删除!
[root@www ~]# nl /etc/passwd | sed '2,5d'
1 root:x:0:0:root:/root:/bin/bash
6 sync:x:5:0:sync:/sbin:/bin/sync
7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
.....(后面省略).....
范例二:承上题,在第二行后(亦即是加在第三行)加上『drink tea?』字样!
[root@www ~]# nl /etc/passwd | sed '2a drink tea'
1 root:x:0:0:root:/root:/bin/bash
2 bin:x:1:1:bin:/bin:/sbin/nologin
drink tea
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
.....(后面省略).....
增加一行很简单,那如果是要增将两行以上呢?
范例三:在第二行后面加入两行字,例如『Drink tea or .....』与『drink beer?』
[root@www ~]# nl /etc/passwd | sed '2a Drink tea or ......\
> drink beer ?'
1 root:x:0:0:root:/root:/bin/bash
2 bin:x:1:1:bin:/bin:/sbin/nologin
Drink tea or ......
drink beer ?
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
.....(后面省略).....
以行为单位的取代和显示功能
刚刚是介绍如何新增与删除,那么如果要整行取代呢?看看底下的范例吧:
范例四:我想将第2-5行的内容取代成为『No 2-5 number』呢?
[root@www ~]# nl /etc/passwd | sed '2,5c No 2-5 number'
1 root:x:0:0:root:/root:/bin/bash
No 2-5 number
6 sync:x:5:0:sync:/sbin:/bin/sync
.....(后面省略).....
sed 可以简单的直接取出你想要的那几行!是透过行号来捉的喔!看看底下的范例先:
范例五:仅列出 /etc/passwd 档案内的第 5-7 行
[root@www ~]# nl /etc/passwd | sed -n '5,7p'
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
6 sync:x:5:0:sync:/sbin:/bin/sync
7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
上述的指令中有个重要的选项『 -n 』,按照说明文件,这个 -n 代表哦是『安静模式』! 那么为什么要使用安静模式呢?你可以自行下达 sed '5,7p' 就知道了 (5-7 行会重复输出)! 有没有加上 -n 的参数时,输出的数据可是差很多的喔!
部分数据的搜寻并取代的功能
基本上 sed 的搜寻与取代的与 vi 相当的类似!他有点像这样: sed 's/要被取代的字符串/新的字符串/g'
步骤一:先观察原始讯息,利用 /sbin/ifconfig 查询 IP 为何?
[root@www ~]# /sbin/ifconfig eth0
eth0 Link encap:Ethernet HWaddr 00:90:CC:A6:34:84
inet addr:192.168.1.100 Bcast:192.168.1.255 Mask:255.255.255.0
inet6 addr: fe80::290:ccff:fea6:3484/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
.....(以下省略).....
# 因为我们还没有讲到 IP ,这里你先有个概念即可啊!我们的重点在第二行,
# 也就是 192.168.1.100 那一行而已!先利用关键词捉出那一行!
步骤二:利用关键词配合 grep 撷取出关键的一行数据
[root@www ~]# /sbin/ifconfig eth0 | grep 'inet addr'
inet addr:192.168.1.100 Bcast:192.168.1.255 Mask:255.255.255.0
# 当场仅剩下一行!接下来,我们要将开始到 addr: 通通删除,就是像底下这样:
# inet addr:192.168.1.100 Bcast:192.168.1.255 Mask:255.255.255.0
# 上面的删除关键在于『 ^.*inet addr: 』啦!正则表示法出现! ^_^
步骤三:将 IP 前面的部分予以删除
[root@www ~]# /sbin/ifconfig eth0 | grep 'inet addr' | \
> sed 's/^.*addr://g'
# .*连在一起就意味着任意数量的不包含换行的字符
192.168.1.100 Bcast:192.168.1.255 Mask:255.255.255.0
# 仔细与上个步骤比较一下,前面的部分不见了!接下来则是删除后续的部分,亦即:
# 192.168.1.100 Bcast:192.168.1.255 Mask:255.255.255.0
# 此时所需的正则表示法为:『 Bcast.*$ 』就是啦!
步骤四:将 IP 后面的部分予以删除
[root@www ~]# /sbin/ifconfig eth0 | grep 'inet addr' | \
> sed 's/^.*addr://g' | sed 's/Bcast.*$//g'
192.168.1.100
让我们再来继续研究 sed 与正则表示法哦配合练习!假设我只要 MAN 存在的那几行数据, 但是含有 # 在内的批注我不想要,而且空白行我也不要!此时该如何处理呢?可以透过这几个步骤来实作看看:
步骤一:先使用 grep 将关键词 MAN 所在行取出来
[root@www ~]# cat /etc/man.config | grep 'MAN'
# when MANPATH contains an empty substring), to find out where the
cat
# MANBIN pathname
# MANPATH manpath_element [corresponding_catdir]
# MANPATH_MAP path_element manpath_element
# MANBIN /usr/local/bin/man
# Every automatically generated MANPATH includes these fields
MANPATH /usr/man
....(后面省略)....
步骤二:删除掉批注之后的数据!
[root@www ~]# cat /etc/man.config | grep 'MAN'| sed 's/#.*$//g'
MANPATH /usr/man
....(后面省略)....
# 从上面可以看出来,原本批注的数据都变成空白行啦!所以,接下来要删除掉空白行
[root@www ~]# cat /etc/man.config | grep 'MAN'| sed 's/#.*$//g' | \
> sed '/^$/d'
MANPATH /usr/man
MANPATH /usr/share/man
MANPATH /usr/local/man
....(后面省略)....
延伸正则表示法
grep -v '^$' regular_express.txt | grep -v '^#'
需要使用到管线命令来搜寻两次!那么如果使用延伸型的正则表示法,我们可以简化为:
egrep -v '^$|^#' regular_express.txt
此外,grep 预设仅支持基础正则表示法,如果要使用延伸型正则表示法,你可以使用 grep -E ,不过更建议直接使用 egrep !直接区分指令比较好记忆!其实 egrep 与 grep -E
是类似命令别名的关系啦!
文件的格式化与相关处理
格式化打印: printf
[root@www ~]# printf '打印格式' 实际内容
选项与参数:
关于格式方面的几个特殊样式:
\a 警告声音输出
\b 退格键(backspace)
\f 清除屏幕 (form feed)
\n 输出新的一行
\r 亦即 Enter 按键
\t 水平的 [tab] 按键
\v 垂直的 [tab] 按键
\xNN NN 为两位数哦数字,可以转换数字成为字符。
关于 C 程序语言内,常见的变数格式
%ns 那个 n 是数字, s 代表 string ,亦即多少个字符;
%ni 那个 n 是数字, i 代表 integer ,亦即多少整数字数;
%N.nf 那个 n 与 N 都是数字, f 代表 floating (浮点),如果有小数字数,假设我共要十个位数,但小数点有两位,即为 %10.2f 啰!
范例一:将刚刚上头数据的档案 (printf.txt) 内容仅列出姓名与成绩:(用 [tab] 分隔)
[root@www ~]# printf '%s\t %s\t %s\t %s\t %s\t \n' $(cat printf.txt)
Name Chinese English Math Average
DmTsai 80 60 92 77.33
VBird 75 55 80 70.00
Ken 60 90 70 73.33
既然每个字段的长度不固定会造成上述的困扰,那我将每个字段固定就好啦!没错没错!这样想非常好! 所以我们就将数据给他进行固定字段长度的设计吧!
范例二:将上述资料关于第二行以后,分别以字符串、整数、小数点来显示:
[root@www ~]# printf '%10s %5i %5i %5i %8.2f \n' $(cat printf.txt |\
> grep -v Name)
DmTsai 80 60 92 77.33
VBird 75 55 80 70.00
Ken 60 90 70 73.33
%10s 代表的是一个长度为 10 个字符的字符串字段,%5i 代表的是长度为 5 个字符的数字字段,至于那个 %8.2f 则代表长度为 8 个字符的具有小数点的字段,其中小数点有两个字符宽度。我们可以使用底下的说明来介绍 %8.2f 的意义:
字符宽度: 12345678
%8.2f意义:00000.00
如上所述,全部的宽度仅有 8 个字符,整数部分占有 5 个字符,小数点本身 (.) 占一位,小数点下的位数则有两位。
printf 除了可以格式化处理之外,他还可以依据 ASCII 的数字与图形对应来显示数据喔(注3)! 举例来说 16 进位的 45 可以得到什么 ASCII 的显示图 (其实是字符啦)?
范例三:列出 16 进位数值 45 代表的字符为何?
[root@www ~]# printf '\x45\n'
E
# 这东西也很好玩~他可以将数值转换成为字符,如果你会写 script 的话,
# 可以自行测试一下,由 20~80 之间的数值代表的字符是啥喔! ^_^
awk:好用的数据处理工具
awk 也是一个非常棒的数据处理工具!相较于 sed 常常作用于一整个行的处理, awk 则比较倾向于一行当中分成数个『字段』来处理。因此,awk 相当的适合处理小型的数据数据处理呢!awk 通常运作的模式是这样的:
[root@www ~]# awk '条件类型1{动作1} 条件类型2{动作2} ...' filename
awk 后面接两个单引号并加上大括号 {} 来设定想要对数据进行的处理动作。 awk 可以处理后续接的档案,也可以读取来自前个指令的 standard output 。 但如前面说的, awk 主要是处理『每一行的字段内的数据』,而默认的『字段的分隔符为 "空格键" 或 "[tab]键" 』!举例来说,我们用 last 可以将登入者的数据取出来,结果如下所示:
[root@www ~]# last -n 5 <==仅取出前五行
root pts/1 192.168.1.100 Tue Feb 10 11:21 still logged in
root pts/1 192.168.1.100 Tue Feb 10 00:46 - 02:28 (01:41)
root pts/1 192.168.1.100 Mon Feb 9 11:41 - 18:30 (06:48)
dmtsai pts/1 192.168.1.100 Mon Feb 9 11:41 - 11:41 (00:00)
root tty1 Fri Sep 5 14:09 - 14:10 (00:01)
若我想要取出账号与登入者的 IP ,且账号与 IP之间以 [tab] 隔开,则会变成这样:
[root@www ~]# last -n 5 | awk '{print $1 "\t" $3}'
root 192.168.1.100
root 192.168.1.100
root 192.168.1.100
dmtsai 192.168.1.100
root Fri
另外,由上面这个例子你也会知道,在每一行的每个字段都是有变量名称的,那就是 $1, $2... 等变量名称。以上面的例子来说, root 是 $1 ,因为他是第一栏嘛!至于192.168.1.100 是第三栏, 所以他就是 $3 啦!后面以此类推~呵呵!还有个变数喔!那就是 $0 ,$0 代表『一整列资料』的意思~以上面的例子来说,第一行的 $0 代表的就是『root .... 』那一行啊! 由此可知,刚刚上面五行当中,整个 awk 的处理流程是:
1. 读入第一行,并将第一行的资料填入 $0, $1, $2.... 等变数当中;
2. 依据 "条件类型"的限制,判断是否需要进行后面的"动作";
3. 做完所有的动作与条件类型;
4. 若还有后续的『行』的数据,则重复上面 1~3 的步骤,直到所有的数据都读完为止。
那么 awk 怎么知道我到底这个数据有几行?有几栏呢?这就需要 awk 的内建变量的帮忙啦~
我们继续以上面 last -n 5 的例子来做说明,如果我想要:
· 列出每一行的账号(就是 $1);
· 列出目前处理的行数(就是 awk 内的 NR 变量)
· 并且说明,该行有多少字段(就是 awk 内的 NF 变量)
则可以这样:
[root@www ~]# last -n 5| awk '{print $1 "\t lines: " NR "\t columes: " NF}'
root lines: 1 columes: 10
root lines: 2 columes: 10
root lines: 3 columes: 10
dmtsai lines: 4 columes: 10
root lines: 5 columes: 9
# 注意喔,在 awk 内的 NR, NF 等变量要用大写,且不需要有钱字号 $ 啦!
假设我有一个薪资数据表档名为 pay.txt ,内容是这样的:
Name 1st 2nd 3th
VBird 23000 24000 25000
DMTsai 21000 20000 23000
Bird2 43000 42000 41000
如何帮我计算每个人的总额呢?而且我还想要格式化输出喔!我们可以这样考虑:
· 第一行只是说明,所以第一行不要进行加总 (NR==1 时处理);
· 第二行以后就会有加总的情况出现 (NR>=2 以后处理)
[root@www ~]# cat pay.txt | \
> awk 'NR==1{printf
"%10s %10s %10s %10s %10s\n",$1,$2,$3,$4,"Total" }
NR>=2{total = $2 + $3 + $4
printf "%10s %10d %10d %10d %10.2f\n", $1, $2, $3, $4, total}'
Name 1st 2nd 3th Total
VBird 23000 24000 25000 72000.00
DMTsai 21000 20000 23000 64000.00
Bird2 43000 42000 41000 126000.00
上面的例子有几个重要事项应该要先说明的:
· awk 的指令间隔:所有 awk 的动作,亦即在 {} 内的动作,如果有需要多个指令辅助时,可利用分号『;』间隔, 或者直接以 [Enter] 按键来隔开每个指令,例如上面的范例中,鸟哥共按了三次 [enter] 喔!
· 逻辑运算当中,如果是『等于』的情况,则务必使用两个等号『==』!
· 格式化输出时,在 printf 的格式设定当中,务必加上 \n ,才能进行分行!
· 与bash shell 的变量不同,在 awk 当中,变量可以直接使用,不需加上 $ 符号。