上一章里面说了bash里面有一些万用字符,这张介绍的正则表达式要跟上一章的万用字符区分开来哦~
基础正则表达式
语系也会对正则表达式产生影响,本章的语系均为LANG=C
我们首先需要了解一些特殊的符号
1.grep
grep [-A] [-B] [–color=auto] ‘搜寻字串’ filename
选项与参数:
-A :后面可加数字,为 after 的意思,除了列出该行外,后续的 n 行也列出来;
-B :后面可加数字,为 befer 的意思,除了列出该行外,前面的 n 行也列出来;
–color=auto 可将正确的那个撷取数据列出颜色
#范例1:用dmesg列出核心讯息,再以grep找出含qxl的行
dmesg | grep 'qxl'
#范例2:承上,要将捉到的关键字显色,且加上加号来表示
dmesg | grep -n --color=auto 'qxl'
#范例3:承上,在关键字所在行的前两行和后三行一起捉出来显示
dmesg | grep -n -A3 -B2 --color=suto 'qxl'
2.基础正则表达式练习
要有一些设置:
1.语系已经使用export LANG=C;export LC_ALL=C的设置值
2.grep已经使用alias设置成’grep --color=auto’
#例题1:搜寻特定字串
#搜寻特定字串
grep -n 'the' regular_express.txt
#反向选择
grep -vn 'the' regular_express.txt
#不论大小写
grep -in 'the' regular_express.txt
#例题2:利用中括号来搜寻集合字符
#找test和taste
grep -n 't[ae]st' regular_express.txt
#找'oo'
grep -n 'oo' regular_express.txt
#不想'oo'前面有'g'
grep -n '[^g]oo' regular_express.txt
#不想'oo'前面有小写字母
grep -n '[^a-z]oo' regular_express.txt
#取得有数字的那些行
grep -n '[0-9]' regular_express.txt
#上面的两个也可以用下面这两条命令代替
grep -n '[^[:lower:]]oo' regular_express.txt
grep -n '[[:digit:]]' regular_express.txt
#例题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
#可能会存在断行字符的问题^M$结尾或$结尾,可以cat-A查看一下
cat -An regular_express.txt | head -n 10 | tail -n 6
#找出来空白行
grep -n '^$' regular_express.txt
#把一个文件中的空白行或注释行删掉
cat -n /etc/rsyslog.conf
grep -v '^$' /etc/rsyslog.conf | grep -v '^#'
#例题4:任意一个字符.,与重复字符*
#万用字符中*代表任意0或多个字符,但在正则表达式中并不是那个意思
#. (小数点):代表“一定有一个任意字符”的意思;
#(星星号):代表“重复前一个字符, 0 到无穷多次”的意思,为组合形态
#找出‘g??d’的字串所在的那些行
grep -n 'g..d' regular_express.txt
#如果运行下面的命令,会把所有的数据都打印出来放在屏幕上
grep -n 'o*' regular_express.txt#因为*表示的是重复0次或多次
#至少需要一个o
grep -n 'oo*' regular_express.txt
#至少需要两个o
grep -n 'ooo*' regular_express.txt
#字符开头结尾都是g,中间至少有一个o
grep -n 'goo*g' regular_express.txt
#字符开头结尾都是g,中间的字符可有可无
grep -n 'g.*g' regular_express.txt
#找出任意数字的行
grep -n '[0-9][0-9]*' regular_express.txt
#例题5:限定连续RE字符范围{}
#因为{}在shell中有特殊含义,因此需要加跳脱字符
#找两个o的字串
grep -n 'o\{2\}' regular_express.txt
#g后面接2-5个o,然后接一个g
grep -n 'go\{2,3\}g' regular_express.txt
#两个以上的o
grep -n 'go\{2,\}g' regular_express.txt
grep -n 'gooo*g' regular_express.txt
基础正则表达式字符汇整
以 ls -l 配合 grep 找出 /etc/ 下面文件类型为链接文件属性的文件名,由于 ls -l 列出 链接文件时标头会是“ lrwxrwxrwx ”,因此使用如下的指令即可找出结果:
ls -l /etc | grep ‘^l’
如果只想知道有几个文件,加上| wc -l即可
3.sed工具
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 就是啦!
sed后面跟的动作,一定要用两个单括号括住
#范例1:将/etc/passwd的内容列出并打印行号,同时将2-5行删除
nl /etc/passwd | sed '2,5d'
#只删除第二行
nl /etc/passwd | sed '2d'
#删除3到最后一行
nl /etc/passwd | sed '3,$d'#其中的$表示最后一行
#承上题,在第二行后加上‘drink tea’字样
nl /etc/passwd | sed '2a drink tea'
#在第2行前加上
nl /etc/passwd | sed '2i drink tea'
#在第二行后面加两行(用反斜线换行)
nl /etc/passwd | sed '2a Drink tea or ……\
drink beer ?'
#范例3:以行为单位的取代与显示功能
nl /etc/passwd | sed '2,5c No 2-5 number'
#取出文件中的5-7行(加上-n只有被处理了的那些会显示出来,p是打印的意思)
nl /etc/passwd | sed -n '5,7p'
sed还能进行部分数据的搜寻并取代功能
sed ‘s/要被取代的字串/新的字串/g’
#范例4:
#step1:观察原始讯息,利用/sbin/ifconfig查询ip为何?
/sbin/ifconfig eth0
#step2:利用关键字配合grep取出关键的一行数据
/sbin/ifconfig eth0 | grep 'inet '
#step3:将ip前面的部分删除
/sbin/ifconfig eth0 | grep 'inet ' | sed 's/^.*inet //g'
#step4:将ip后面的部分删除
/sbin/ifconfig eth0 | grep 'inet ' | sed 's/^.*inet //g' | sed 's/ *netmask.*$//g'
sed与正则表达式的配合练习
如果我只想要MAN存在的那几行数据,但是含有#在内的注解不要,空白行也不要
#step1:先用grep将关键MAN所在行取出来
cat /etc/man_df.conf | grep 'MAN'
#step2:删除掉注解之后的数据
cat /etc/man_df.conf | grep 'MAN' | sed 's/^#.*$//g'
#step3:上面一步所有的注解数据都成空白行了,接下来删除空白行
cat /etc/man_df.conf | grep 'MAN' | sed 's/^#.*$//g' | sed '/^$/d'
sed可以直接修改文件内容,但风险很大
#范例6:利用sed将regular_express.txt每一行结尾为.就换成!
sed -i 's/\.$/\!/g' regular_express.txt
#范例7:利用sed在文件最后一行添加文字
sed -i '$a #This is a test'#$表示最后一行,在最后一行后面新增
延伸正则表达式
之前我们取出空白行与行首为#的行列,使用的是
grep -v '^$' regular_express.txt | grep -v '^#'
如果用延伸正则表达式的话可以简化为:
egrep -v '^$|^#' regular_express.txt
grep默认只能使用基础正则表达式,如果想用延伸正则表达式的话可以用egrep(grep -E),其实延伸正则表达式与基础正则表达式相比就只是多了几个特殊符号罢了
文件的格式化与相关处理
格式化打印:printf
printf ‘打印格式’ 实际内容
选项与参数:
关于格式方面的几个特殊样式:
\a 警告声音输出
\b 倒退键(backspace)
\f 清除屏幕 (form feed)
\n 输出新的一行
\r 亦即 Enter 按键
\t 水平的 [tab] 按键
\v 垂直的 [tab] 按键
xNN NN 为两位数的数字,可以转换数字成为字符。
关于程序语言内,常见的变量格式
%ns 那个 n 是数字, s 代表 string ,亦即多少个字符;
%ni 那个 n 是数字, i 代表 integer ,亦即多少整数码数;
%N.nf 那个 n 与 N 都是数字, f 代表 floating (浮点),如果有小数码数, 假设我共要十个位数,但小数点有两位,即为 %10.2f 啰!
#范例1:列出printf.txt中的姓名与成绩(用tab键分隔)
printf '%s\t %s\t %s\t %s\t %s\t \n'$(cat printf.txt)
因为printf不是管线命令,因此需要跟上面那样加$()调用
上面的命令可能会存在无法对齐的情况,可以固定一下字段
#将上述数据关于第二行之后,分别以字串、整数、小数点来显示
printf '%10s %5i %5i %5i %8.2f \n' $(cat print.txt | grep -v '^Name')
printf除了可以格式化处理之外,他还可以依据ASCII的数字与图形对应来显示数据
#范例3:列出16进位数值45代表的字符是啥
printf '\x45\n'
awk:好用的数据处理工具
相较于 sed 常常作用于一整个行的处理, awk 则比较 倾向于一行当中分成数个“字段”来处理。因此,awk 相当的适合处理小型的数据处理。
awk ‘条件类型1{动作1} 条件类型2{动作2} …’ filename
awk主要是处理每一行的字段内的数据,而默认的字段的分隔符号是空白键或tab键
#awk使用的一个例子
last -n 5#这样可以取出last的前5行
#如果想要取出账号与登陆者的ip,且账号和ip之间以tab隔开,会变成下面的样子(其中$1和$3分别表示第一个和第三个字段)
last -n 5 | awk '{print $1 "\t" $3}'
此外,除了$1$2$3这种变量之外,还有一个特殊的变量$0,它表示那一行所有的数据
awk是是“以行为一次处理的单位”, 而“以字段为最小的处理单位”。那么 awk 怎么知道我到底这个数据有几行?有几栏呢?这就需要 awk 的内置变量的帮忙啦~
#列出每一行的账号,列出目前处理的行数,说明该行有多少字段
last -n 5 | awk '{print $1 "\t lines:" NR "\t columns: " NF}'
awk的逻辑运算字符(用在条件类型里)
#查阅/etc/passwd中第三栏小于10以下的数据,并且仅列出账号与第三栏,可以按照下面这么做
cat /etc/passwd | awk '{FS=":"} $3>10 {print $1 "\t " $3}'
#但是上面的语句有个问题就是第一行会显示错误,读入第一行的时候还是用空白键分割的,从第二行才开始生效,针对这个问题可以用BEGIN这个关键字预先设置awk的变量
cat /etc/passwd | awk 'BEGIN{FS=":"} $3>10 {print $1 "\t " $3}'
此外,awk还能进行“计算功能”,这儿假设了一个txt,向计算每个人的工资总额
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}'
与bash shell不同,在awk中,变量可以直接使用,不需要加上$符号;awk的动作内支持if条件,上面的指令可以修订为下面的样子
cat pay.txt | \
awk '{if (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}'
文件对比工具
diff
对比两个文件之间的差异(以行为单位),一般用在ASCII纯文本文件的比对上。通常用在同一文件或软件比较新旧版本差异上
diff [-bBi] from-file to-file
选项与参数:
from-file :一个文件名,作为原始比对文件的文件名;
to-file :一个文件名,作为目的比对文件的文件名;
-b :忽略一行当中,仅有多个空白的差异(例如 “about me” 与 “about me” 视为相同
-B :忽略空白行的差异。
-i :忽略大小写的不同。
#首先创建一下新旧文件
mkdir -p /tmp/testpw
cd /tmp/testpw
cp /etc/passwd passwd.old
cat /etc/passwd | sed -e '4d' -e '6c no six line' > passwd.new
diff passwd.old passwd.new
不用用diff去比对两个完全不相干的文件,因为根本比不出来啥。此外,diff可以比较两个目录的差异
diff /etc/rc0.d/ /etc/rc5.d/
cmp
主要也是比对两个文件,他主要用“字节”单位去比对
cmp [-l] file1 file2
选项与参数:
-l :将所有的不同点的字节处都列出来。因为 cmp 默认仅会输出第一个发现的不同点。
cmp passwd.old passwd.new
patch
前面diff是比较两个不同版本之间的差异,但是如果要升级呢?就是“先比较先旧版本的差异,并将差异档制作成为补丁文件,再由补丁 文件更新旧文件”即可。
#范例1:以/tmp/testpw内的passwd.old与passwd.new制作补丁文件
diff -Naur passwd.old passwd.new > passwd.patch
cat passwd.patch
那么如何将旧文件更新为新的内容呢,需要先安装一下patch这个软件
patch -pN > patch_file#更新
patch -R -pN > patch_file#还原
选项与参数:
-p :后面可以接“取消几层目录”的意思。
-R :代表还原,将新的文件还原成原来旧的版本。
#范例2:将刚刚制作出来的patch file用来更新旧版数据
patch -p0 > passwd.patch
ll passwd*
#范例3:恢复旧文件的内容
patch -R -p0 > passwd.patch
ll passwd*
-p后面跟着0是因为我们在对比新旧版的数据时是在同一个目录下,因此不需要减去目录。
文件打印准备:pr
打印/etc/man_db.conf
pr /etc/man_db.conf