Linux学习笔记(十三)

正则表示法与文件格式化处理

先来介绍一些特殊的符号:

尤其上表中的[:alnum:], [:alpha:], [:upper:], [:lower:], [:digit:] 这几个一定要知道代表什么意思,因为他要比 a-z 或 A-Z 的用途要确定的很!好了,底下就让我们开始来玩玩进阶版的grep 吧! 

[root@www ~]# grep [-A] [-B] [--color=auto] '搜寻字符串' filename 

选项与参数: 

-A :后面可加数字,为 after 的意思,除了列出该行外,后续的 行也列出来; 

-B :后面可加数字,为 befer 的意思,除了列出该行外,前面的 行也列出来; 

--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 前面有 的话呢?此时,可以利用在集合字符的反向选择 [^] 来达成:

[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 

 

任意一个字符 . 与重复字符 

. (小数点):代表『一定有一个任意字符』的意思; 

* (星星号):代表『重复前一个 到无穷多次』的意思,为组合形态 

限定连续 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! 

假设我们要找出 后面接 到 个 ,然后再接一个 的字符串,他会是这样: 

[root@www ~]# grep -n 'go\{2,5\}g' regular_express.txt 

18:google is the best tools for search keyword

那么,如果我想要的是 个 以上的 goooo....g 呢?除了可以是 gooo*g ,也可以是: 

[root@www ~]# grep -n 'go\{2,\}g' regular_express.txt 

 

基础正则表示法字符汇整 (characters)

再次强调:『正则表示法的特殊字符』与一般在指令列输入指令的『通配符』并不相同, 例如,在通配符当中的 代表的是『 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   :新增,的后面可以接字符串,而这些字符串会在新的一行出现(目前的下一行)~ 

c   :取代, c的后面可以接字符串,这些字符串可以取代 n1,n2 之间的行! 

d   :删除,因为是删除啊,所以 后面通常不接任何咚咚; 

i   :插入, 得后面可以接字符串,而这些字符串会在新的一行出现(目前的上一行); 

p   :打印,亦即将某个选择的数据印出。通常 会与参数 sed -n 一起运作~ 

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 为两位数哦数字,可以转换数字成为字符。 

关于 程序语言内,常见的变数格式 

       %ns   那个 是数字, 代表 string ,亦即多少个字符; 

       %ni   那个 是数字, 代表 integer ,亦即多少整数字数; 

       %N.nf 那个 与 都是数字, 代表 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 代表的是长度为 个字符的数字字段,至于那个 %8.2f 则代表长度为 个字符的具有小数点的字段,其中小数点有两个字符宽度。我们可以使用底下的说明来介绍 %8.2f 的意义: 

字符宽度: 12345678 

%8.2f意义:00000.00 

如上所述,全部的宽度仅有 个字符,整数部分占有 个字符,小数点本身 (.) 占一位,小数点下的位数则有两位。 

printf 除了可以格式化处理之外,他还可以依据 ASCII 的数字与图形对应来显示数据喔(3)! 举例来说 16 进位的 45 可以得到什么 ASCII 的显示图 (其实是字符啦)? 

范例三:列出 16 进位数值 45 代表的字符为何? 

[root@www ~]# printf '\x45\n' 

这东西也很好玩~他可以将数值转换成为字符,如果你会写 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 当中,变量可以直接使用,不需加上 符号。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值