第十一章 正规表示法与文件格式化处理(一)

1.管线命令(pipe)

学习正规表示法之前,让我们先了解一下管线命令(pipe)。

1.1 获取命令:cut、grep

cut

功能简介:

[~]$ cut -d "分割字符" -f fields 
[~]$ cut -c 字符区间

选项与参数:
-d :后面加分割字符。与-f一起只用;
-f  :依据-d的分割字符将一段讯息分区为数段,用-f是取出第几段的意思;
-c :以字符的单位取出固定字符区间;

示例1:将PATH变量取出,找出第3个路径
[~]$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library/Frameworks/Python.framework/Versions/3.7/bin:/usr/local/mysql/bin
[~]$ echo $PATH | cut -d ":" -f 3   ##如果取多个路径用","分割

示例2:将export输出的讯息,取得第12字符以后的所有字符串
[~]$ export | cut -c 12-

示例3:用last将显示的登入者的信息,仅留下用户名
[~]$ last | cut -d ' ' -f 1

grep

cut是将一行讯息取出某部分我们想要的,而grep则是分析一行讯息,若当中有我们需要的,就将该行取出来。

功能简介:

[~]$ grep [-acinv] [--color=auto] '字符串' filename

选项与参数:
-a :将binary文件以text文件的方式搜索数据;
-c :计算找到"字符串"的次数;
-i  :忽略大小写;
-n :顺便输出行号;
-v :反向选择,即显示出没有"字符串"内容的那一行;
--color=auto :可以将找到的关键词部分加上颜色显示;

示例1:将last中,有出现root的行取出来;
[~]$ last |grep 'root'

示例2:与示例1相反,只要没有root的就取出;
[~]$ last |grep -v 'root'

示例3:在last中,只要有root就取出且仅取出第一行;
[~]$ last |grep 'root' |cut -d ' ' -f 1

示例4:取出/etc/man_db.conf内包涵MANPATH的那几行;
[~]$ grep --color=auto 'MANPATH' /etc/man.conf

1.2 排序指令:sort、wc、uniq

sort

如果想对数据排序怎么做呢?

功能简介:

[~]$ sort [-fbMnrtuk] [file or stdin]

选项与参数:
-f :忽略大小写;
-b :忽略最前面的空格符部分;
-M :以月份的名字来排序,例如JAN、DEC等;
-n :使用纯数字进行排序,默认是以文字形态来排序的;
-r :反向排序;
-u :就是uniq,相同的数据,仅出现一行代表;
-t  :分隔符,默认是用[tab]键来分隔的;
-k :以那个区间来进行排序;

示例1:将/etc/passwd中个人账号排序
[~]$ cat /etc/passwd | sort

示例2:/etc/passwd内容是以:来分隔的,想以第三栏来排序
[~]$ cat /etc/passwd | sort -t ':' -k 3 nobody [-n 让它使用数字排序]

示例3:last中,输出的数据仅取账号,并加以排序
[~]$ last | cut -d ' ' -f 1 |sort

uniq

如果想去重怎么做?

功能简介:

[~]$ uniq [-ic]

选项参数:
-i :忽略大小写字符的不同;
-c :进行计数;

示例1:使用last将账号列出,仅取出账号列,进行排序后去重;
[~]$ last | cut -d ' ' -f 1 |sort |uniq

示例2:接上例,如果还想知道每个人的登入次数呢?
[~]$  last | cut -d ' ' -f 1 |sort |uniq -c 

wc

如果我想知道/etc/passwd/man_db.conf文件有多少字,多少行怎么做?

功能简介:

[~]$  wc [-lwm] 

选项与参数:
-l   :仅列出行;
-w :仅列出多少字(英文单字);
-m :多少字符;

示例1:/etc/man_db.conf里面有多少相关字、行、字符数?
[~]$  cat /etc/man_db.conf | wc   
     140     720    4574      ##输出的分别代表:行、字数、字符数

示例2:last可以输出登入者,但是last最后两行并非账号内容,该如何以一行指令串取出登入系统的总人数?
[~]$  last | grep [a-zA-Z] | grep -v 'wtmp' | grep -v 'reboot' |grep -v 'unkown' |grep -v 'shutdown'|wc -l

1.3 双向重导向:tee

">" 标记会将数据流整个传送给文件或装置,因此我们必须去读取这个文件或装置。如果想要从这个数据流处理过程中获取某段数据该怎么做?

tee会同时将数据流分送到文件和屏幕,输出到屏幕的我们叫它"stdout"。

功能简介:

[~]$  tee [-a] file

选项与参数:
-a :以累加的方式,将数据加入file中。

示例1:将last的输出存到last.list中
[~]$  last | tee last.list 

示例2:将ls的数据保存一份到ls.txt中,同时屏幕也有输出信息。
[~]$  ls -l | tee ls.txt |more

1.4 字符转换命令:tr、col、join、paste、expand

tr

tr可以删除一段数据中的文字,或者进行文字的替换

功能简介:

[~]$ tr [-ds] SET1 ...

选项与参数:
-d :删除数据中SET1的这个字符串;
-s :去重;

示例1:将last输出的数据,所有的小写编程大写;
[~]$ last |tr '[a-z]' '[A-Z]'

示例2:将/etc/passwd输出的数据,将冒号去掉;
[~]$ cat /etc/passwd | tr -d ':'

col

功能简介:

[~]$ col [-xb]

选项与参数:
-x :将tab键转换成对等的空格键

示例1:利用cat -A显示所有的特殊按键,以col将tab键转成空格键
[~]$ cat /etc/man.conf |col -x |cat -A

join

它表示处理两个文件之间的数据,主要在处理"两个文件中,有相同数据的那一行,才将它加在一起"。

功能简介:

[~]$ join [-til2] file1 file2

选项与参数:
-t :join默认以空格符分隔数据,并且比对第一个字段的数据,如果两个文件相同,则将两笔数据连成一行,且第一个字段放在第一个;
-i :忽略大小写;
-1:后面加数字,代表第一个文件要用第几个字段来分析;
-2:后面加数字,代表第二个文件要用第几个字段来分析;

示例1:将/etc/passwd与/etc/shadow相关数据整合成一栏
[~]$ head -n 3 /etc/passwd /etc/shadow  ##可以看到这两个文件的最左边字段是相同的账号,并且以 :分割
[~]$ join -t ':' /etc/passwd /etc/shadow | head -n 3 ##相同的部分被移动到最前面了

示例2:/etc/passwd第四个字段是GID,/etc/group第三个字段是GID,怎么样整合?
[~]$ head -n 3 /etc/passwd /etc/group  ## 他们中的第四个和第三个"0"则表示GID
[~]$ join - t ':' -1 4 /etc/passwd -2 3 /etc/group | head -n 3 ##相同的字段部分被移动到最前面了

注意:在使用join之前,你需要处理的文件应该要事先经过排序(sort)处理。否则,有些比对的会被略过。

paste

paste:"将两行贴在一起,中间以tab键隔开"。

功能简介:

[~]$ paste [-d] file1 file2

选项与参数:
-d :后面接分割字符,预设是以tab键来分割;
-   :如果file部分写成 - ,表示来自stdin的意思;

示例1:将/etc/passwd与/etc/shadow同一行贴在一起
[~]$ paste /etc/passwd /etc/shadow

示例2:先将/etc/group读出,然后与示例1贴在一起,仅取出前三行
[~]$ cat /etc/group | paste /etc/passwd /etc/shadow - | head -n 3 ##这个例子重点在 - 的使用,表示stdin

expand

expand:将tab键转成空格键。

功能简介:

[~]$ expand [-t] file

选项与参数:
-t :后面加数字。定义一个tab键代表多少个空格键。

示例1:将/etc/man_db.conf行首是MANPATH的行就取出,仅取前三行;
[~]$ grep '^MANPATH' /etc/man_db.conf |head -n 3 ##行首的标志为^

示例2:接示例1,如果想要将所有的符号都取出来?
[~]$ grep 'MANPATH' /etc/man.conf |head -n 3 |cat -A ##cat -A 可以把所有的tab键显示为^I

示例3:接示例2,怎样将tab键设定代表为6个空格字符?
[~]$ grep 'MANPATH' /etc/man.conf |head -n 3 |expand -t 6 |cat -A ##expand将tab转成空格,所以cat -A查看不到了

1.5 分区命令:split

split:可以将一个大文件依据文件大小或行数来分区,就可以将大文件分区为小文件了。

功能简介:

[~]$ split [-bl] file PREFIX

选项与参数:
-b :后面加想分区成的文件大小,可以加单位,例如b,k,m等;
-l  :以行数来进行分区
PREFIX :代表前导符,可作文分区文件的前导文字

示例1: /etc/services 有600kb,怎么分成300kb一个文件?
[~]$ split -b 300k /etc/services services
[~]$ ll -k services* ##可以看到被分成了servicesaa,servicesab,servicesac,services就是前导向名字了。

示例2:如何将上面3个小文件合成一个文件,档名为servicesback?
[~]$ cat services* >> servicesback

示例3:将ls -al / 输出的信息,每十行记录成一个文件;
[~]$ ls -al / | split -l 10 - lsroot ## 重点是 - ,它表示stdout或stdin。

1.6 参数替换: xargs

xargs : x是加减乘除的乘号,就是在产生某个指令的参数的意思。

功能简介:

[~]$ xargs [0epn] command

选项与参数:
-0 :如果输入的stdin含有特殊字符,例如`,\,空格键等,-0可以将它还原成一般字符。
-e :这个是EOF(end of file)的意思。后面加一个字符串,和字符串中间不没有空格键的,当xargs分析到这个字符串时会停止继续工作。
-p :在执行每个指令的argument时,都会询问使用者。
-n :后面加次数,每次command指令执行时,指定要使用几个参数。

示例1:将/etc/passwd内的第一列取出,仅取三行,使用id将每个账号内容显示出来
[~]$ id root ## 这个id可以查询用户的UID/GID等
[~]$ id $(cut -d ':' -f 1 /etc/passwd | head -n 3) ## $(cmd)可以预先取得参数,但id只能接受一个参数,上述指令会执行错误
[~]$ cut -d ':' -f 1 /etc/passwd | head -n 3 | id ## id并不是管道命令,此命令执行后,只会执行id
[~]$ cut -d ':' -f 1 /etc/passwd | head -n 3 | xargs id ##依旧是错误,因为xargs一口气将全部的数据都给id处理,但是id只能接受1个参数。
[~]$ cut -d ':' -f 1 /etc/passwd | head -n 3 | xargs -n 1 id

1.7 减号的用途

在管道命令中,尝尝会使用到前一个指令的stdout作为这次的stdin,例如下面的例子:

[~]$ tar -cvf - /home | tar -xvf - -C /tmp/homeback ## 将/home里面的文件打包,但打包的数据不记录到文件而是传送到stdout,经过管道后,传送给后面的 - 。

2.正规表示法

2.1什么是正规表示法?

简单来说,正规表示法就是处理字符串的方法,他是以行为单位进行字符串处理的行为,正规表示法通过一些特殊符号的辅助,可以让使用者对某些特定字符串进行搜索、删除、取代的处理。

它有基础正规表示法和延伸表示法。延伸表示法就是除了一些简单的操作,还可以以群组的字符串处理。例如:对Wechat和QQ字符串的搜索,注意是OR的关系而不是AND的关系。

2.2 基础正规表示法

正规表示法是处理字符串的一种表示方式,那么对字符排序有影响的语系就会对正规表示法的结果产生影响了。

语系对正规表示法的影响

为什么语系会影响正规表示法的输出结果?因为不同语系的编码数据是不同的,例如下面的例子:

LANG=C :0 1 2 ... A B C ... a b c ...
LANG=zh_TW :0 1 2 ... a A b ... z Z

所以使用正规表示法时,需要特别留意当时环境的语系,否则可能会发现与别人不同的搜索结果。

下面的练习使用"LANG=C"这个语系。 为了避免这个编码造成的英文与数字的获取问题,有些特殊符号我们也应该了解一下:

[:alnum:]  :表示英文大小写字符及数字,即0-9,A-Z,a-z;
[:alpha:]   :表示任何英文大小写字符,即A-Z,a-z;
[:blank:]   :表示空格键和[tab]按键;
[:cntrl:]     :表示键盘上的控制按键,即CR、LF、Tab、Del等等;
[:digit:]     :表示数字0-9;
[:graph:]   :表示除了空格键与[Tab]外的其他所有按键;
[:lower:]    :表示小写字符,即a-z;
[:upper:]    :表示大写字符,即A-Z;
[:print:]      :表示任何可以被打印出来的字符;
[:punct:]    :表示标点符号,即:"  '  ?  !  #  $ 等等;
[:space:]   :表示任何会产生空白的字符,包括空格、[Tab]、CR等;
[:xdigit:]    :表示16进制的数字类型,因此包括0-9,A-F,a-f;

2.3 grep的一些进阶选项

[~]$ grep [-A] [-B] [--color=auto] '搜索字符串' filename
选项与参数:
-A  :后面加数字,为after的意思,除了列出该行外,后续的n行也列出来;
-B  :后面加数字,为before的意思,除了列出改行外,前面的n行也列出来;
--color=auto :将要搜索的字符串附加颜色;

2.4 基础正规表示法练习

假设有以下文件:

[~]$  vi regular_express.txt
"Open Source" is a good mechanism to develop programs.
apple is my favorite food.
Football game is not use feet only.
this dress doesn't fit me.
However, this dress is about $ 3183 dollars.
GNU is free air not free beer.
Her hair is very beauty.
I can't finish the test.
Oh! The soup taste good.
motorcycle is cheap than car.
This window is clear.
the symbol '*' is represented as start.
Oh! My god!
The gd software is a library for drafting programs.
You are the best is mean you are the no. 1.
The world  is the same with "glad".
I like dog.
google is the best tools for search keyword.
goooooogle yes!
go! go! Let's go.
# I am VBird

示例1:搜索指定字符串

[~]$  grep -n 'the' regular_express.txt --color=auto

示例2:利用中括号来搜索集合字符

如果想要搜索"test"和"taste"两个关键字,我们可以这样来搜索:

[~]$ grep -n '[tae]st' regular_express.txt --color=auto

如果我们想搜索"oo",但不想要前面有"g"的数据怎么做?可以在集合字符中使用反向选择"[^]":

[~]$ grep -n '[^g]oo' regular_express.txt --color=auto

如果"oo"前不想要小写字符,可以这样写:

[~]$ grep -n '[^a-z]oo' regular_express.txt --color=auto

如果字符组是连续的,例如大写/小写/数字等等,就可以使用"[a-zA-Z0-9]"来表示。

由于语系对编码顺序是有影响的,因此也可以使用下面的表示法来测试前面的结果:

[~]$ grep -n '[^[:lower:]]oo' regular_express.txt --color=auto 

[~]$ grep -n '[[:digit:]]' regular_express.txt --color=auto 

示例3:行首与行尾字符 ^ $

如果只想让"the"在行首的行列出怎么做:

[~]$ grep -n '^the' regular_express.txt

如果想要开头是小写字符的那一行就列出怎么做:

[~]$ grep -n '^[a-z]' regular_express.txt
[~]$ grep -n '^[[:lower:]]' regular_express.txt

如果不想开头是英文字母怎么做:

[~]$ grep -n '^[^a-zA-z]' regular_express.txt
[~]$ grep -n '^[^[:alpha:]]' regular_express.txt

如果想要找出行尾有小数点"."的那一行怎么做:

[~]$ grep -n '\.$' regular_express.txt ## 注意:这里的小数点需要转义

如果想要找出"空白行"怎么做?

[~]$ grep -n '^$' regular_express.txt ## 因为只有行首和行尾,这样就找出空白行了。

假设有一个shell script,空白行和#的那一行是批注,因此想要省略掉这些行,怎么做?

[~]$ grep -v '^$' regular_express.txt | grep -v '^#' regular_express.txt

*示例4:任意一个字符 . 与重复字符 **

在正规表示法"*"并不是通配符:

  • . :表示一定有一个任意字符;

    • :表示重复前一个字符,0到无穷次;

如果我们想要找出"g??d"的字符怎么做:

[~]$ grep -n 'g..d' regular_express.txt ## 表示g和d之间必须存在两个字符

""表示重复0个或多个前面的字符,因此"o"表示:拥有空字符或一个o以上的字符。

[~]$ grep -n 'o*' regular_express.txt ## 因为允许空字符,所以将会把所有的数据都打印出来

如果是"oo"呢?第1个"o"必须存在,第2个"o"是可有可无的多个"o",所以,凡是有"o,oo,oooo"等等,都被列出来;同理,当需要至少2个o以上的字符串时,就需要"ooo"。

[~]$ grep -n 'ooo*' regular_express.txt

如果想找出g开头与g结尾的字符串,当中的字符可有可无怎么做?是"gg"吗?"g"表示空字符或一个以上的g,在加上后面的g,所以搜索的内容就是g,gg,ggg,gggg。只要该行中拥有一个以上的g就符合了。

那如何找出g.....g的行?可以使用任意一个字符"."。

[~]$ grep -n 'g.*g' regular_express.txt ## ". *"表示0个或多个任意字符

如果想要找出任意数字的行怎么做:

[~]$ grep -n '[0-9][0-9]*' regular_express.txt  ## 虽然[0-9]就可以达到效果,但是希望可以理解这个表达式的意义。

示例5:限定连续正规表示法的字符范围:{}

如果想找到2个o的字符串怎么做:

[~]$ grep -n 'o\{2\}' regular_express.txt  ## 因为{ }在shell是有特殊意义的,所以需要转义。

如果想找到g后面接2到5个o的字符串,再接一个g的字符串怎么做:

[~]$ grep -n 'go\{2,5\}g' regular_express.txt 

如果想要2个o以上的字符串"gooo...g"呢?除了gooo*g也可以是:

[~]$ grep -n 'go\{2,\}g' regular_express.txt 

2.5 基础正规表达式字符汇整

^word  :搜索的字符串(word)在行首;
word$ : 搜索的字符串(word)在行尾;
.          :表示"一定有一个任意字符"的字符;
\          :转义;
*          :重复0个到无穷个前一个RE字符;
[list]     :表示字符集合的RE字符,里面列出想搜索的;
[n1-n2]:表示字符集合的RE字符,里面列出想要获取的范围;
[^list]   :表示字符集合的RE字符,里面列出不想要的字符串或范围;
\{n,m\} :表示n到m个的"前一个RE字符";

2.6 sed工具

sed本身是一个管道命令,可以分析stdin了。

功能简介:

[~]$  sed [-nefr] [动作]

选项与参数:
-n  :使用安静(silent)模式,一般sed中,所有stdin的数据都会被显示。如果使用-n后,只有经过sed特殊处理的那一行或动作才会被显示出来;
-e  :直接在指令列模式上进行sed动作编辑;
-f   :直接将sed的动作写在一个文件内, -f filename 执行filename的sed动作;
-i   :直接修改读取的文件内容,而不是由屏幕输出;

动作说明:[n1[,n2]]fuction
n1,n2 :可以不存在,一般表示"选择进行动作的行数"。例如:需要在10到20行之间进行的动作表示为 10,20[fuction];

fuction 列表:
a  :新增,后面接字符串,这些字符串会在新的一行出现(当前的上一行);
c  :替换,后面接字符串,这些字符串可以替换n1到n2之间的行;
d  :删除;
i   :插入,后面接字符串,这些字符串会在新的一行出现(当前上一行);
p  :打印,将某个选择的数据打印出来,通常与 -n 一起使用;
s  :替换,可以直接进行替换。通常这个s的动作搭配正规表示法。

以行为单位的新增/删除

示例1 :将/etc/passwd的内容列出并打印行号,同时将2-5行删除
[~]$ nl /etc/passwd | sed '2,5d'  ## 删除第2行'2d';删除2到最后一行'3,$d'

示例2 :接上示例,在第二行后加上"drink tea?"
[~]$ nl /etc/passwd |sed '2a drink tea?'

以行为单位的替换与显示

示例3 :将2-5行的内容替换为"No 2-5 number"
[~]$ nl /etc/passwd |sed '2,5c No 2-5 number'

示例4 :将/etc/passwd文件内的第5-8行列出来
[~]$ nl /etc/passwd | sed -n '5,8p'

数据的搜索并取代功能

[~]$ sed 's/要被取代的字符串/新的字符串/g'

示例1:查询IP
[~]$ ifconfig en4 

示例2:接上一示例,根据'inet '获取结果
[~]$ ifconfig en4  | grep 'inet '

示例3:接上一示例,将IP前面的部分删除
[~]$ ifconfig en4  | grep 'inet ' | sed 's/^.*inet //g'

示例4:接上一示例,将IP后面的部分删除
[~]$ ifconfig en4  | grep 'inet ' | sed 's/^.*inet //g' | sed 's/ *netmask.*$//g'

示例5: /etc/man_db.conf中带有"MAN"的获取出来,删除批注行和空白行;
[~]$ cat /etc/man.conf |grep 'MAN' | sed 's/#.*//g' |sed '/^$/d' ## /^$/ 表示空白行

直接修改文件内容(慎用)

示例6:利用sed将regular_express.txt 内的每一行结尾为"."换成"!"
[~]$ sed -i 's/\.$/\!/g' regular_express.txt

示例7:利用sed直接在regular_express.txt最后一行加入"#This is a test"
[~]$ sed -i '$a # This is a test' regular_express.txt

正规表示法的扩展

例如上面有一个例子是在regular_express.txt中去除空白行与行首为#的行,使用的是

"grep -v '^$' regular_express.txt | grep -v '^#' "

可以简化为:

"egrep -v '$|#' regular_express.txt"

正规表示法扩展有哪些特殊符号?

+  :表示重复1个或1个以上的前一个RE字符; ## egrep -n 'go+d' regular_express.txt
?  :表示0个或1个的前一个RE字符; ## egrep -n 'go?d' regular_express.txt
()  :找出群组的字符串; ## egrep -n 'g(la|oo)d' regular_express.txt
()+:找出群组的字符串; ## echo AxyzxyzC | egrep 'A(xyz)+C' 意思是找出开头是A,结尾是C,包含1个以上xyz的字符串;

3.文件的格式化与相关处理

3.1 格式化打印:printf

功能简介:

[~]$ printf '打印格式' 实际内容

选项与参数:
\a   :警告声音输出;
\b   :删除键;
\f    :清除屏幕;
\n   :输出新的一行;
\r    :即enter键;
\t    :水平的[tab]键;
\v   :垂直的[tab]键;
\xNN  :NN为2位数的数字,可以转换数字成为字符;

C语言中,常见的变数格式:
%ns  :n是数字,s代表string,即n个字符串;
%ni   :n是数字,i代表integer,即n个整数数字;
%N.nf:n和N都为数字,f代表floating。表示加上小数点一个N个字符,小数点后面保留n位;

3.2 awk:数据处理工具

awk比较倾向于一行当中分成数字字段来处理,默认的字段分隔符为"空格键"或"tab键"。

功能简介:

[~]$ awk '条件类型1{动作1}条件类型2{动作2}...' filename

示例1:使用last取出前5行,只取出账号与IP。
[~]$ last -n 5 | awk '{print $1 "\t" $3}'  ## $1,$2,$3...表示每一行的每个字段的变量名称。$0则代表一整行的意思。

接下来了解以下awk有哪些变量:

NF  :每一行($0)拥有的字段总数;
NR  :目前awk处理的是第几行的数据;
FS   :分割字符,默认是空格键;

举例来说:/etc/passwd中以冒号作为分隔符,该文件第1个字段是账号,第3个字段是UID。那想要查阅第3栏小于10的数据怎么做:

[~]$ cat /etc/passwd | awk 'BEGIN {FS=":"} $3 < 10 {print $1 "\t" $3}'
## 这个BEGIN又是什么?它可以预先设定awk的变量!如果我们不加这个关键词,那么当我们读入第一行数据时候,它默认还是以空格键为分隔的!

假设有一下文本:

[~]$  cat text.txt
Name    1st     2nd     3th
tony    20      20      30
tom     10      30      35
jerry   5       45      45

如果想要计算每个人的总额怎么算?还需要格式化输出。

[~]$  cat test.txt | awk 'NR==1{printf "%10s %5s %5s %5s %5s",$1,$2,$3,$4,"Total\n"} NR>=2{printf "%10s %5d %5d %5d %5.2f\n",$1,$2,$3,$4,$1+$2+$3+$4}'

另外,awk的动作{}内也支持if条件,上面的指令可以修改为以下这样:

[~]$  cat test.txt | awk '{if (NR==1) printf "%10s %5s %5s %5s %5s",$1,$2,$3,$4,"Total\n"} {printf "%10s %5d %5d %5d %5.2f\n",$1,$2,$3,$4,$1+$2+$3+$4}'

3.3 文件比对工具

diff

diff用来比对两个文件之间的差异,以行为单位来比对的。

示例:将/etc/passwd备份为passwd.old后,把第4行删除,第6行替换为no line,再另存为passwd.new,怎么做呢?

[~]$  cat passwd.old | sed -e '4d' -e '6c no line' > passwd.new

接下来了解一下diff的使用:

[~]$ diff [-bBi] from-file to-file

选项与参数:
from-file :原始对比文件档名;
to-file :目标对比文件档名;
提示:from-file/to-file可以使用"-"替换,表示"stdin";

-b  :忽略一行中仅有多个空白的差异(例如"a  b"和"a    b"忽略差异);
-B  :忽略空白行的差异;
-i    :忽略大小写的不同; 

cmp

cmp在比对文件的时候,主要是利用字节单位去比对的。

[~]$ cmp [-l] file1 file2

选项与参数:
-l  :将所有的不同点的字节出都列出来。预设仅会输出第一个发现的不同点。

patch

将旧的文件升级成新的文件,经常与diff搭配使用。

示例1:制作passwd.old与passwd.new补丁文件
[~]$ diff -Naur passwd.old passwd.new > passwd.patch
[~]$ cat passwd.patch  ##可以看到passwd.old到passwd.new做了哪些修改,一般使用diff制作的补丁文件通常使用扩展名.patch。

功能简介:

[~]$ patch -pN < patch_file  ##更新;
[~]$ patch -R -pN < patch_file ##还原;

选项与参数:
-p  :加"取消几层目录",N为数字;
-R  :表示将新的文件还原成原来旧的文件;

示例2:将刚刚制作出来的path file用来更新旧版数据
[~]$ patch -p0 < passed.patch
[~]$ ls -l passwd*   

示例3:恢复旧的文件内容
[~]$ patch -R -p0 < passwd.patch
[~]$ ls -l passwd*   

因为新旧版的数据是在同一个目录下的,所以是"-p0"。

你可能感兴趣的:(第十一章 正规表示法与文件格式化处理(一))