正则表达式与文件格式化处理(2)-sed工具(主)
它的前一篇 正则表达式与文件格式化处理(1)-基础正则表达式练习(主)
基础正则表达式字符汇整
我们可以将基础的正则表达式特殊字符汇整如下:
RE 字符 | 意义与范例 |
---|---|
^word | 意义:待搜寻的字串( word )在行首! 范例:搜寻行首为 # 开始的那一行,并列出行号 grep -n '^#' regular_express.txt |
word\(|意义:待搜寻的字串( word )在行尾!<br>范例:将行尾为 ! 的那一行打印出来,并列出行号<br> `grep -n '!\)' regular_express.txt` | |
. | 意义:代表 “ 一定有一个任意字符 ” 的字符! 范例:搜寻的字串可以是 ( eve ) ( eae ) ( eee ) ( e e ), 但不能仅有 ( ee ) ! 亦即 e 与 e 中间 一定 仅有一个字符,而空白字符也是字符!grep -n 'e.e' regular_express.txt |
|意义:跳脱字符,将特殊符号的特殊意义去除! 范例:搜寻含有单引号 ' 的那一行! grep -n \' regular_express.txt |
|
* | 意义:重复零个到无穷多个的前一个 RE 字符 范例:找出含有 ( es ) ( ess ) ( esss ) 等等的字串, 注意,因为 * 可以是 0 个,所以 es 也是符合带搜寻字串。 另外,因为 * 为重复 “ 前一个 RE 字符 ” 的符号, 因此,在 * 之前必须要紧接着一个 RE 字符喔!例如任意字符则为 .* !grep -n 'ess*' regular_express.txt |
[list] | 意义:字符集合的 RE 字符,里面列出想要撷取的字符! 范例:搜寻含有 ( gl ) 或 ( gd ) 的那一行,需要特别留意的是,在 [] 当中 “ 谨代表一个待搜寻的字符 ” , 例如 “a[afl]y ” 代表搜寻的字串可以是 aay, afy, aly 即 [afl] 代表 a 或 f 或 l 的意思! grep -n 'g[ld]' regular_express.txt |
[n1-n2] | 意义:字符集合的 RE 字符,里面列出想要撷取的字符范围! 范例:搜寻含有任意数字的那一行!需特别留意,在字符集合 [] 中的减号 - 是有特殊意义的, 他代表两个字符之间的所有连续字符!但这个连续与否与 ASCII 编码有关, 因此,你的编码需要设置正确(在 bash 当中,需要确定LANG 与 LANGUAGE 的变量是否正确!) 例如所有大写字符则为 [A-Z] grep -n '[A-Z]' regular_express.txt |
[^list] | 意义:字符集合的 RE 字符,里面列出不要的字串或范围! 范例:搜寻的字串可以是 ( oog ) ( ood ) 但不能是 ( oot ) ,那个 ^ 在 [] 内时,代表的意义是 “ 反向选择 ” 的意思。 例如,我不要大写字符,则为 [^A-Z] 。但是,需要特别注意的是,如果以 grep -n [^A-Z] regular_express.txt 来搜寻, 却发现该文件内的所有行都被列出,为什么? 因为这个 [^A-Z] 是 “ 非大写字符 ” 的意思, 因为每一行均有非大写字符,例如第一行的 "Open Source" 就有 p,e,n,o.... 等等的小写字 grep -n 'oo[^t]' regular_express.txt |
\ | 意义:连续 n 到 m 个的 “ 前一个 RE 字符 ” 意义:若为 {n} 则是连续 n 个的前一个 RE 字符, 意义:若是 {n,} 则是连续 n 个以上的前一个 RE 字符! 范例:在 g 与 g 之间有 2 个到 3 个的 o 存在的字串亦即( goog )( gooog ) grep -n 'go\{2,3\}g' regular_express.txt |
再次强调: 正则表达式的特殊字符
与一般在指令列输入指令的 万用字符
并不相同,
例如,在万用字符当中的 *
代表的是 0 ~ 无限多个字符
的意思,但是在正则表达式当中,
*
则是 重复 0 到无穷多个的前一个 RE 字符
的意思~使用的意义并不相同,不要搞混了!
例题
我们要找到含有以 a 为开头的文件,则必须要这样:
ls | grep -n '^a.*'
以 ls -l
配合 grep
找出 /etc/
下面文件类型为链接文件属性的文件名:
由于 ls -l
列出链接文件时标头会是 lrwxrwxrwx
,因此使用如下的指令即可找出结果:
ls -l /etc | grep '^l'
sed 工具
我们先来谈一谈 sed 好了, sed 本身也是一个管线命令,可以分析 standard input 的啦!
而且 sed 还可以将数据进行取代、删除、新增、撷取特定行等等的功能呢!
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
就是啦!
以行为单位的新增 / 删除功能
范例一:将 /etc/passwd 的内容列出并且打印行号,同时,请将第 2~5 行删除!
nl /etc/passwd | sed '2,5d'
1 root:x:0:0:root:/root:/bin/bash
6 games:x:5:60:games:/usr/games:/usr/sbin/nologin
7 man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
...后面的省略...
看到了吧? sed 的动作为 '2,5d'
,那个 d 就是删除!因为 2-5 行给他删除了,所以显示的数据就没有 2-5 行啰~
另外,注意一下,原本应该是要下达 sed -e 才对,没有 -e 也行啦!同时也要注意的是, sed 后面接的动作,请务必以 ''两个单引号括住
喔!
范例二:承上题,在第二行后(亦即是加在第三行)加上 “drink tea?” 字样!
nl /etc/passwd | sed '2a drink tea'
1 root:x:0:0:root:/root:/bin/bash
2 daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
drink tea
3 bin:x:2:2:bin:/bin:/usr/sbin/nologin
...
嘿嘿!在 a 后面加上的字串就已将出现在第二行后面啰!那如果是要在第二行前呢?
nl /etc/passwd | sed '2i drink tea'
就对啦!就是将 a
变成 i
即可。
增加一行很简单,那如果是要增将两行以上呢?
范例三:在第二行后面加入两行字,例如 “Drink tea or .....” 与 “drink beer?”
$ nl /etc/passwd | sed '2a Drink tea or ......\
> drink bear?'
1 root:x:0:0:root:/root:/bin/bash
2 daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
Drink tea or ......
drink bear?
3 bin:x:2:2:bin:/bin:/usr/sbin/nologin
...
这个范例的重点是 “ 我们可以新增不只一行喔!可以新增好几行 ” 但是每一行之间都必须要以反斜线 \
来进行新行的增加喔!
所以,上面的例子中,我们可以发现在第一行的最后面就有 \
存在啦!在多行新增的情况下, \
是一定要的喔!
以行为单位的取代与显示功能
范例四:我想将第 2-5 行的内容取代成为 “No 2-5 number” 呢?
nl /etc/passwd | sed '2,5c No 2-5 number'
1 root:x:0:0:root:/root:/bin/bash
No 2-5 number
6 games:x:5:60:games:/usr/games:/usr/sbin/nologin
7 man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
...
范例五:仅列出 /etc/passwd 文件内的第 5-7 行
nl /etc/passwd | sed -n '5,7p'
5 sync:x:4:65534:sync:/bin:/bin/sync
6 games:x:5:60:games:/usr/games:/usr/sbin/nologin
7 man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
上述的指令中有个重要的选项 “ -n ” ,按照说明文档,这个 -n 代表的是 “ 安静模式 ” !
那么为什么要使用安静模式呢?你可以自行下达 sed'5,7p' 就知道了 ( 5-7 行会重复输出)!
有没有加上 -n 的参数时,输出的数据可是差很多的喔!你可以通过这个 sed 的以行为单位的显示功能,
就能够将某一个文件内的某些行号捉出来查阅!很棒的功能!不是吗?
部分数据的搜寻并取代的功能
除了整行的处理模式之外, sed 还可以用行为单位进行部分数据的搜寻并取代的功能喔!
基本上 sed 的搜寻与取代的与 vi 相当的类似!他有点像这样:
sed 's/ 要被取代的字串 / 新的字串 /g'
我们使用下面这个取得 IP 数据的范例,
一段一段的来处理给您瞧瞧,让你了解一下什么是咱们所谓的搜寻并取代吧!
步骤一:先观察原始讯息,利用 /sbin/ifconfig 查询 IP 为何?
/sbin/ifconfig eth0
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.1.7 netmask 255.255.255.0 broadcast 192.168.1.255
inet6 240e:a4:3647:e800:1512:c1c:f1a5:af54 prefixlen 64 scopeid 0x0<global>
inet6 240e:a4:3647:e800:2cc8:2a44:26f4:d06e prefixlen 128 scopeid 0x0<global>
inet6 fe80::1512:c1c:f1a5:af54 prefixlen 64 scopeid 0xfd<compat,link,site,host>
...
我们的重点在第二行,也就是 192.168.1.7
那一行而已!先利用关键字捉出那一行!
步骤二:利用关键字配合 grep 撷取出关键的一行数据
$ /sbin/ifconfig eth0 | grep 'inet '
inet 192.168.1.7 netmask 255.255.255.0 broadcast 192.168.1.255
步骤三:将 IP 前面的部分予以删除
$ /sbin/ifconfig eth0 | grep 'inet ' | sed 's/^.*inet //g'
192.168.1.7 netmask 255.255.255.0 broadcast 192.168.1.255
步骤四:将 IP 后面的部分予以删除
$ /sbin/ifconfig eth0 | grep 'inet ' | sed 's/^.*inet //g'\
> |sed 's/ *netmask.*$//g'
192.168.1.7
继续研究 sed 与正则表达式的配合练习!
步骤一:先使用 grep 将关键字 MAN 所在行取出来
[dmtsai@study ~]$ cat /etc/man_db.conf | grep 'MAN'
# MANDATORY_MANPATH manpath_element
# MANPATH_MAP path_element manpath_element
# MANDB_MAP global_manpath [relative_catpath]
# every automatically generated MANPATH includes these fields
....(后面省略)....
步骤二:删除掉注解之后的数据!
[dmtsai@study ~]$ cat /etc/man_db.conf | grep 'MAN'| sed 's/#.*$//g'
MANDATORY_MANPATH /usr/man
....(后面省略)....
从上面可以看出来,原本注解的数据都变成空白行啦!所以,接下来要删除掉空白行
[dmtsai@study ~]$ cat /etc/man_db.conf | grep 'MAN'| sed 's/#.*$//g' | sed '/^$/d'
MANDATORY_MANPATH /usr/man
MANDATORY_MANPATH /usr/share/man
MANDATORY_MANPATH /usr/local/share/man
....(后面省略)....
直接修改文件内容(危险动作)
你以为 sed 只有这样的能耐吗?那可不! sed 甚至可以直接修改文件的内容呢!
范例六:利用 sed 将 regular_express.txt 内每一行结尾若为 . 则换成 !
sed -i 's/\.$/\!/g' regular_express.txt
上头的 -i 选项可以让你的 sed 直接去修改后面接的文件内容而不是由屏幕输出喔!
这个范例是用在取代!请您自行 cat 该文件去查阅结果啰!
范例七:利用 sed 直接在 regular_express.txt 最后一行加入 “# This is a test”
sed -i '$a # This is a test' regular_express.txt
由于 $ 代表的是最后一行,而 a 的动作是新增,因此该文件最后新增啰!
sed 的 “ -i ” 选项可以直接修改文件内容,这功能非常有帮助!举例来说,如果你有一个 100 万行的文件,
你要在第 100 行加某些文字,此时使用 vim 可能会疯掉!因为文件太大了!那怎办?
就利用 sed 啊!通过 sed 直接修改 / 取代的功能,你甚至不需要使用 vim 去修订!很棒吧!
它的后一篇:正则表达式与文件格式化处理(3)-正则表达式延伸,awk(主)
参考: <<鸟哥的Linux私房菜-基础学习篇(第四版)>>