工学1号馆

home

Shell脚本编程2–查找与替换

Wu Yudong    November 18, 2016     Linux/Unix   617   

本文继续学习shell脚本编程,文本查找与文本替换

1、查找文本

以grep程序查找文本(匹配文本)很方便

有三种程序可以用来查找整个文本文件:

grep

最早的文本匹配程序,使用POSIX定义的基本正则表达式

egrep

扩展式grep,功能更加强大,但是代价是会耗费更多的运算资源

fgrep

快速grep,这个版本匹配固定的字符串而非正则表达式,使用优化的算法

这三种grep最后合并在2001POSIX标准的grep命令

grep最简单的用法就是使用固定字符串:

wu@ubuntu:~$ who
wu    :0            2016-11-16 06:03 (:0)
wu    pts/12    2016-11-16 06:04 (:0)
wu@ubuntu:~$ who | grep -F w
wu    :0            2016-11-16 06:03 (:0)
wu    pts/12    2016-11-16 06:04 (:0)

-F选项用以查找固定字符串w

本文地址:http://wuyudong.com/2016/11/18/3048.html,转载请注明出处。

2、正则表达式

正则表达式有两个基本部分组成:一般字符和特殊字符

字符 BRE/ERE 模式含义
\ 两者都可 用以关闭后续字符的特殊意义
. 两者都可 匹配单个字符,但NUL除外
* 两者都可 匹配在它之前的任意数量的单个字符
^ 两者都可 匹配紧接着的正则表达式,在行或字符串的起始处
$ 两者都可 匹配前面的正则表达式,在字符串或行结尾出处
[…] 两者都可 匹配方括号内任一字符,连字符(-)表示连接字符的范围

匹配单个字符

  • 一般字符就是它自身
  • 转义字符\
  • .字符即任意字符
  • 使用方括号[],里面的^放在字首表示取反

后向引用

首先,将子表达式包含在\ ( \ )中。最多包含9个子表达式
然后,使用\digit,其中digit可以是1-9,表示与先前第digit个子表达式匹配

例如:

模式 匹配成功
\ (ab\ )\ (cd\ )[def]*\2\1 abcdcdab、abcdeeecdab、abcdddeeffcdab、……
\ (why\ ).*\1  一行里重现两个why

后向引用在寻找重复字以及匹配引号时特别好用:
\ ([” ‘]\ ).*\1           匹配单引号或双引号括起来的字

单个表达式匹配多字符

使用.或者*进行匹配,但是*修饰符不能表明匹配次数,区间表达式可以解决这类问题,区间表达式接在单个字符正则表达式后面,控制该字符连续重复几次即为匹配成功。

区间表达式将一个或两个数字放在\{与\}之间,有3种变化,如下:

\ {n\ }        前置正则表达式所得结果重现n次

\ {n,\ }       前置正则表达式所得结果重现至少n次

\ {n,m\ }   前置正则表达式所得结果重现n至m次

例如:

a\ {5\ } 表示重现5个a

q\ {10,42\ }  表示重现10到42个q

至于n与m的值必须介于0~RE_DUP_MAX之间,可以通过$getconf命令查看:

wu@ubuntu:~$ getconf RE_DUP_MAX
32767

文本匹配锚点

两个meta字符(^与$)叫做锚点,针对要被匹配字符串的开始或结尾处进行匹配

^与$可以同时使用,将括起来的正则表达式匹配整个字符串

3、字段处理

一条记录指的是相关信息的单个集合,而字段指的是记录的组成部分

文本文件惯例

一行表示一条记录,使用空格或tab分隔字段,例如:

wu@ubuntu:~/bin$ cat record1.data
#name        age    address
zhangsan    20     guangzhou
lisi                21     beijing
wangwu      22     shenzhen

#起到注释的作用,也可以使用冒号来界定分隔字段,但无论使用哪种,定界符最好不要成为数据的内容

以定界符分隔字段最好的例子就是/etc/passwd

wu@ubuntu:~/bin$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
……

在这个文件里,一行表示系统里的一个用户,每个字段都以冒号隔开

使用cut选定字段

cut命令是用来剪下文本文件里的数据,文本文件可以是字段类型或是字符类型。

下面的命令显示系统上每个用户的登录名以及其全名:

wu@ubuntu:~/bin$ cut -d : -f 1,5 /etc/passwd
root:root
daemon:daemon
bin:bin
sys:sys
……

通过选择其他字段编号,还可以取出每个用户的根目录:

wu@ubuntu:~/bin$ cut -d : -f 6  /etc/passwd
/root
/usr/sbin
/bin
/dev
……

使用join连接字段

join命令可以将多个文本结合在一起,每个文件里面的记录都共用一个键值

wu@ubuntu:~/bin$ cat sales
#业务数据
#业务员        数量
张三              100
李四              200
王五              300
wu@ubuntu:~/bin$ cat quotas
#配额
#业务员        配额
张三               50
李四               30
王五               45

为了让join运作得到正确的结果,输入文件必须先完成排序,merge-sales.sh

#! /bin/sh
# merge-sales.sh
#
# 结合配额与业务员数据

# 删除注释并排序数据文件
sed '/^#/d' quotas | sort > quotas.sorted
sed '/^#/d' sales  | sort > sales.sorted

# 以第一个键值作结合,将结果产生至标准输出
join quotas.sorted sales.sorted

# 删除缓存文件
rm quotas.sorted sales.sorted

运行结果如下:

wu@ubuntu:~/bin$ merge-sales.sh
张三 50 100
李四 30 200
王五 45 300

如果文章对您有帮助,欢迎点击下方按钮打赏作者

Comments

No comments yet.
To verify that you are human, please fill in "七"(required)