Linux文本处理三剑客

目录

相关命令

正则表达式

基本正则表达式元字符:

字符匹配:

次数匹配:

位置锚定:

扩展的正则表达式元字符:

字符匹配:

次数匹配:

位置锚定:

一、grep

1.作用

2.用法及常用选项

练习1

3.egrep

练习2

4. fgrep

二、sed

1.常用选项

2.地址定界

3.编辑命令

练习

4.高级编辑命令

三、awk

1.print

2.变量

3.printf

4.操作符

5.PATTERN

6.常用的action

7.控制语句

8.array

9.函数

回顾

参考资料

相关命令

      grep:文本过滤(模式:pattern)工具:文本查找,寻找含有特定文本的行

                  grep, egrep, fgrep

      sed:stream editor,文本编辑工具(行)

      awk:Linux上的实现gawk,文本报告生成器,使文本更好看

正则表达式

      模式:由正则表达式字符及文本字符所编写的过滤条件

正则表达式REGEXP:由一类特殊字符及文本字符所编写的模式,其中有些字符不表示字符字面意义,而表示控制或通配的功能

            分两类:

                       基本正则表达式:BRE         grep

                       扩展正则表达式:ERE         grep -E, egrep

正则表达式引擎:用来检查表达式是否能够匹配到那行文本信息

基本正则表达式元字符:

字符匹配:

            .  匹配任意单个字符

            [ ] 匹配指定范围内的任意单个字符

            [^]匹配指定范围外的任意单个字符  注意^必须得在至少一个[ ]内

            [:digit:]、[:lower:]、[:upper:]、[:alpha:]、[:alnum:]、[:punct:](所有标点符号)、[:space:]  

次数匹配:

用在要指定次数的字符后面,用于指定前面的字符要出现的次数

            *匹配前面的字符任意次;>=0

                       例如:grep "x*y"

                             abxy

                             xay             *:y前面的x出现0次,也符合匹配条件

                             xxxxxxy       默认工作在贪婪模式

                  与glob中的*有区别

            .*任意长度的任意字符,此时与glob中单个*意义一致

            \?匹配其前面的字符0或1次,即前面的可有可无

            \+匹配其前面的字符至少1次;>0

\{m\}匹配前面的字符m次,有转义字符\才不会因为{ }而展开命令行

                  \{m,n\}匹配前面的字符至少m次,至多n次                                           \{0,n\}匹配前面的字符至多n次

                  \{m,\}匹配前面的字符至少m次

位置锚定:

            ^:行首锚定;用于模式的最左侧;e.g. ^root

            $:行尾锚定;用于模式的最右侧

                  ^PATTERN$:用于模式匹配整行

                  ^$:空行         ^[[:space:]]*$  假空行

            \<\b:词首锚定:用于单词模式的左侧

            \>\b:词尾锚定:用于单词模式的右侧

            \<PATTERN\>:匹配整个单词

分组:

                  \( \):将一个或多个字符捆绑在一起,当作一个整体进行处理

                             \(xy\)*ab

                       如果不加()

Note分组括号中的模式匹配到的内容会被正则表达式引擎记录于内部的变量中,这些变量的命名方式为:\1, \2, \3, ...(\n为在grep的命名方式,其他可能是$n)

\1:从左侧起,第一个左括号以及与之匹配右括号之间的模式所匹配到的字符

                                   \(ab\+\(xy\)*\):

                                         \1:ab\+\(xy\)*

                                         \2:xy

后向引用:引用前面的分组括号中的模式所匹配的字符,(而非模式本身)

e.g.1 匹配以t结尾,且t前面有1-3个字母

e.g.2 匹配符合条件(t结尾,在t之前有1-3个字母开头)的单词

e.g.3 首尾t前{1,3}个字母不同

e.g.4 运用后向匹配,首尾t前{1,3}个字母相同

扩展的正则表达式元字符:

字符匹配:

            .  匹配任意单个字符

            [ ] 匹配指定范围内的任意单个字符

[^]:匹配指定范围外的任意单个字符

次数匹配:

            扩展的正则表达式次数匹配不用反斜线 \ 转义

            *匹配前面的字符任意次;>=0

            ?0或1次

            +1次或多次

            {m}匹配m次

            {m,n}至少m,至多n次

位置锚定:

            ^:行首锚定

            $:行尾锚定

            \<, \b:词首锚定

            \>, \b:词尾锚定

分组:

                  ()

                  后向引用:\1, \2, ...

            或者:

                  a|b  a或者b

                       e.g. C|cat表示的是”C或cat”,而不是”Cat或cat”

                             (C|c)at表示是”Cat或cat”

一、grep

      grep:Global search REgular expression and Print out the line.

1.作用

文本搜索工具,根据用户指定的“模式”对目标文本逐行进行匹配检查,打印匹配到的行

2.用法及常用选项

grep [OPTIONS] PATTERN [FILE...]  模式两边要加引号

            选项:

                  --color=auto:对匹配到的文本着色显示

                  -v:显示不能够被pattern匹配到的行

                  -i:忽略字符大小写

                  -o:仅显示匹配到的字符串

                  -q:静默模式,不输出任何信息,只需要判断结果是否存在时有用

                  -A #:after, 后#行

                  -B #:before, 前#行

                  -C #:context, 前后各#行

                  -E:使用ERE;

                  -F:使用快速正则表达式

                  -P:使用prel正则表达式

练习1

显示/proc/meminfo文件中以大小写s开头的行;(要求:使用两种方式)

方法1:[root@Tux ~]# grep '\<[Ss].*' /proc/meminfo

      改进:grep ^[Ss]   /proc/meminfo

方法2:[root@Tux ~]# grep -i ^S /proc/meminfo

方法3:grep -e ^S -e ^s  /proc/meninfo

显示/etc/passwd文件中不以/bin/bash结尾的行

[root@Tux ~]# grep -v '/bin/bash$' /etc/passwd

[root@Tux ~]# grep -v '(/bin/bash)\>' /etc/passwd   (此做法错误:\>用于单词词尾锚定)

显示/etc/passwd文件中ID号最大的用户的用户名

分析:cut 取用户名-> sort -k3n排序->如何取出最大一行 tail -1

[root@Tux ~]# sort -t:-k3n /etc/passwd | cut -d:-f1 | tail -1

nfsnobody

[root@Tux ~]# sort -t:-k3nr /etc/passwd | cut -d:-f1 | head -1

nfsnobody

如果用户root存在,显示其默认的shell程序

            # id root &> /dev/null && grep "^root\>" /etc/passwd | cut -d:-f7

            P.S. 也可以将root后的\>换成:

找出/etc/passwd中的两位或三位数

错误做法:grep '[0-9]\{2,3\}' /etc/passwd 这样提取出来的可能不是纯数字

            # grep " \< [0-9]\{2,3\} \> " /etc/passwd

显示/etc/rc.d/rc.sysinit文件中,至少以一个空白字符开头的且后面存非空白字符的行

      错误做法:grep '^[[:space:]]\+.*[^[:space:]].*' /etc/rc.d/rc.sysinit

                       非空白字符没有仅跟在空白字符后面,题目理解有偏差

            # grep "^[[:space:]]\+[^[:space:]]" /rc.d/rc.sysinit

找出"netstat -tan"命令的结果中以'LISTEN'后跟0个、1个或多个空白字符结尾的行

            # netstat -tan | grep "LISTEN[[:space:]]*$"

添加用户bash、testbash、basher以及nologin(其shell为/sbin/nologin);而后找出/etc/passwd文件中用户名同shell名的行

错误做法1:grep '\<\([[:alpha:]].*\):.*\1\>' /etc/passwd 模式成了一个单词

错误做法2:grep '^\([[:alpha:]]\+\).*\1$' /etc/passwd

      P.S. ↑[:alpha:]应改成 [:alnum:]

      useradd -s /sbin/nologin nologin

            # grep " ^\([[:alnum:]]\+ \> \) .* \1$ " /etc/passwd

3.egrep

      支持扩展的正则表达式,相当于grep -E,其他选项和grep一样

      egrep = grep -E

      egrep [OPTIONS] PATTERN [FILE...]

练习2

显示当前系统root、centos或user1用户的默认shell和UID

      egrep '^root|centos|user1\>' /etc/passwd |cut -d: -f1,7,3 --output-delimiter='  '

            # grep -E '^(root|centos|user1)\>' /etc/passwd | cut -d:-f1,3,7

找出/etc/rc.d/init.d/functions文件(CentOS6)中某单词后面跟一个小括号的行

            # grep -E -o "^[_[:alpha:]]+\(\)" /etc/rc.d/init.d/functions

使用echo输出一绝对路径,使用egrep取出其基名

      命令:basename    去掉前导的目录部分后打印"名称"

basename /usr/bin/sort       输出"sort"

命令:dirname       输出已经去除了尾部的"/"字符部分的名称;如果名称中不包含"/",则显示"."(表示当前目录)。

 dirname /usr/bin/sort  输出"/usr/bin"

            dirname stdio.h           输出"."

            # echo "/mnt/sdc" | grep -E -o "[^/]+/?$" | cut -d"/" -f1

进一步地:使用egrep取出路径的目录名,类似于dirname命令的结果

# echo "/etc/rc.d/init.d" | egrep -o '^/.*/' | egrep -o '^/.*([[:alpha:]]|[0-9])\>' || echo "."

找出ifconfig命令结果中1-255之间的数值

      # ifconfig | egrep '\<1?[[:digit:]]{,2}\>|\<25[0-5]\>|\<2[0-4][[:digit:]]\>'

找出ifconfig命令结果中的IP地址(满足x.x.x.x即可)

# ifconfig | egrep -o '([[0-9]]{1,2}|1[0-9]{1,2}|25[0-5]|2[0-4][[0-9])\.([0-9]{1,2}|1[0-9]{1,2}|25[0-5]|2[0-4][0-9])\.([0-9]{1,2}|1[0-9]{1,2}|25[0-5]|2[0-4][0-9])\.([0-9]{1,2}|1[[0-9]{1,2}|25[0-5]|2[0-4][[0-9])'

4. fgrep

不支持正则表达式搜索,全按字符本身搜索

二、sed

sed:Stream EDitor, 行编辑器

用法:

      sed [option]... 'script' inputfile...

            script:

                  '地址命令'

1.常用选项

行为模式:

      sed读取每个文件,一次读一行,将读取的行放到内存的模式空间;编辑命令修改模式空间中的内容;(未编辑结束的内容可以暂时放到保持空间,而保持空间当中的内容又可以重新被读取到模式空间,随后可继续编辑)当所有操作完成后,sed将模式空间的最后内容打印到标准输出

选项:

-n:不输出模式中的内容至屏幕;默认行为是将模式空间的内容输出到屏幕

-e:多点编辑   P.S. 多点编辑时,每个模式前都要加-e

-f /PATH/TO/SCRIPT_FILE:从指定文件中读取编辑脚本

-r:支持使用扩展正则表达式

-i:原处编辑

2.地址定界

①不给地址:对全文进行处理

②单地址

     #:指定的行

     /pattern/:被此处模式所能够匹配到的每一行

③地址范围

     #,#

     #,+#

     /pat1/,/pat2/

     #,/pat1/

④ ~:步进

     1~2

     2~2

3.编辑命令

d:删除

p:显示模式空间中的内容

a \text:在行后面追加文本;支持使用\n实现多行追加

i \text:在行前面插入文本;支持使用\n实现多行插入

c \text:替换行为单行或多行文本

w /path/to/somefile:保存模式空间匹配到的行至指定文件中 (另存为)

r /path/from/somefile:读取指定文件的文本流至模式空间中匹配到的行的行后

=:为模式空间中的行打印行号

!:取反条件;

s///:查找替换;支持使用其它分隔符,s@@@,s###

     替换标记:

           g:行内全局替换

           p:显示替换成功的行

           w /PATH/TO/SOMEFILE:将替换成功的结果保存至指定文件中

P.S. p命令和要地址定界一起使用,也就是打印被定界匹配到的行

练习

①删除/boot/grub/grub.conf文件中所有以空白开头的行行首的空白字符;

sed 's@^[[:space:]]\+@@' /boot/grub/grub.conf

②删除/etc/fstab文件中所有以#开头,后面至少跟一个空白字符的行的行首的#和空白字符

sed 's@^#[[:space:]]\+@@' /etc/fstab

③echo一个绝对路径给sed命令,取出其基名;取出其目录名

      取出其基名

echo /etc/rc.d/init.d/testsrv | sed "s@/.*/@@"

      取出其目录名

echo "/etc/sysconfig/" | sed 's@[^/]\+/\?$@@'

4.高级编辑命令

h:把模式空间中的内容覆盖至保持空间中

H:把模式空间中的内容追加至保持空间中

g:从保持空间取出数据覆盖至模式空间     get

G:从保持空间取出内容追加至模式空间    Get

x:把模式空间中的内容与保持空间中的内容进行互换

n:读取匹配到的行的下一行至模式空间

N:追加匹配到的行的下一行至模式空间

d:删除模式空间中的行

D:删除多行模式空间中的所有行

示例

sed -n 'n;p' FILE:显示偶数行

     

sed '1!G;h;$!d' FILE:逆向显示文件内容

解析:

①第一个命令1!G

若取出的行不是文本中的第一行就将保持空间中的内容追加至模式空间,是第一行则不做任何操作

②第二个命令h

将模式空间的内容覆盖至保持空间

③第三个命令$!d

若取出的行不是文本中的最后一行就将删除模式空间中的最后一行,是文本中的最后一行则不做任何操作

P.S. 事实上使用tac命令即可实现同样的功能

sed '$!N;$!D' FILE:取出文件后两行

sed '$!d' FILE:取出文件最后一行

sed 'G' FILE:

sed '/^$/d;G' FILE:

sed 'n;d' FILE:显示奇数行

sed -n '1!G;h;$p' FILE:逆向显示文件中的每一行

三、awk

      awk:报告生成器,格式化文本输出

AWK:Aho, Weinberger, Kernighan --> New AWK, NAWK

GNU awk, gawk

gawk - pattern scanning and processing language

基本用法:gawk  [options]  'program'  FILE ...

                  program:PATTERN{ACTION STATEMENTS}

                       语句之间用分号分隔

选项:

-F:指明输入时用到的字段分隔符

-v var=value:自定义变量        P.S 每声明一个变量时都要加-v选项

      程序模型:

      awk将输入流看做一连串记录的集合,每条记录可细分为多个字段

1.print

print item1, item2, ...

要点:

            ① 逗号分隔符

② 输出的各item可以是字符串,也可以是数值;当前记录的字段、变量或awk的表达式

③ 如省略item,相当于print $0;

2.变量

①内建变量

FS:input field seperator,输入字段分割字符,默认为空白字符

OFS:output field seperator,输出字段分割字符,默认为空白字符

RS:input record seperator,输入记录分割字符,即输入时的换行符

ORS:output record seperator,输出时的换行符

 

NF:number of field,字段数量

{print NF}, {print $NF}    在awk中引用变量时不需要加符号$(除了字段变量)

NR:number of record, 行数

            FNR各文件分别计数;行数

FILENAME:当前文件名

ARGC:命令行参数的个数

ARGV:数组,保存的是命令行所给定的各参数

②自定义变量

a.  -v var=value

P.S. 变量名区分字符大小写,引用变量时不需要加符号$(除了字段)

b.  在program中直接定义

3.printf

格式化输出:printf FORMAT, item1, item2, ...

① FORMAT格式符必须给出

② 不会自动换行,需要显式给出换行控制符,\n

            ③ FORMAT中需要分别为后面的每个item指定一个格式化符号

      格式符:

            %c:显示字符的ASCII码

            %d, %i:显示十进制整数

            %e, %E:科学计数法数值显示

            %f:显示为浮点数

            %g, %G:以科学计数法或浮点形式显示数值

            %s:显示字符串

            %u:无符号整数

            %%:显示%自身

修饰符:

#[.#]:第一个数字控制显示的宽度;第二个#表示小数点后的精度

                                   %3.1f

            -:左对齐

            +:显示数值的符号

4.操作符

      算术操作符:

                        x+y, x-y, x*y, x/y, x^y, x%y

                        -x:转换为数值

                        +x:转换为数值

字符串操作符:没有符号的操作符,字符串连接

赋值操作符:

                       =, +=, -=, *=, /=, %=, ^=

                       ++, --

比较操作符:

                       >, >=, <, <=, !=, ==

模式匹配符:

                       ~:是否匹配

                       !~:是否不匹配

逻辑操作符:

                       &&

                       ||

                       !

函数调用:

                       function_name(argu1, argu2, ...)

条件表达式:

                       selector?if-true-expression:if-false-expression

# awk -F: '{$3>=1000?usertype="Common User":usertype="Sysadmin or SysUser"; printf "%15s:%-s\n",$1,usertype}' /etc/passwd

5.PATTERN

      ① empty:空模式,匹配每一行

      ② /regular expression/:仅处理能够被此处的模式匹配到的行

      ③ relational expression:关系表达式;结果有“真”有“假”;结果为“真”才会被处理

            真:结果为非0值,非空字符串

      ④ line ranges:行范围

            startline,endline:/pat1/,/pat2/

            注意: 不支持直接给出数字的格式

      ~]# awk -F:'(NR>=2&&NR<=10){print $1}' /etc/passwd

      ⑤ BEGIN/END模式

            BEGIN{}:仅在开始处理文件中的文本之前执行一次

            常见用法:

                  变量初始化、打印输出表头

            END{}:仅在文本处理完成之后执行一次

            常见用法:

                  打印所有行的分析结果

# awk -F: 'BEGIN{printf "%10s  %10s\n--------------------------\n","username","UID"}{printf "%10s %10s\n",$1,$3}' /etc/passwd

6.常用的action

      ① Expressions

      ② Control statements:if, while等

      ③ Compound statements:组合语句

      ④ input statements

      ⑤ output statements

7.控制语句

条件式执行

      if(condition) {statments}

      if(condition) {statments} else {statements}

重复执行

      while(conditon) {statments}

      do {statements} while(condition)

      for(expr1;expr2;expr3) {statements}

      break

      continue

 

      delete array[index]

      delete array

 

      exit

      { statements }

①if-else

语法:if(condition) statement [else statement]

~]# awk -F:'{if($3>=1000) {printf "Common user:%s\n",$1} else {printf "root or Sysuser:%s\n",$1}}' /etc/passwd

~]# awk -F:'{if($NF=="/bin/bash") print $1}' /etc/passwd

~]# awk '{if(NF>5) print $0}' /etc/fstab

~]# df -h | awk -F[%] '/^\/dev/{print $1}' | awk '{if($NF>=20) print $1}'

使用场景:对awk取得的整行或某个字段做条件判断

②while循环

语法:while(condition) statement

条件“真”,进入循环;条件“假”,退出循环

使用场景:对一行内的多个字段逐一类似处理时使用;对数组中的各元素逐一处理时使用

~]# awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {print $i,length($i); i++}}' /etc/grub2.cfg

      匹配/etc/grub2.cfg以若干空格开头后接linux16的行,打印其中每个字段及其字符个数

~]# awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {if(length($i)>=7) {print $i,length($i)}; i++}}' /etc/grub2.cfg

③do-while循环

语法:do statement while(condition)

意义:至少执行一次循环体

④for循环

语法:for(expr1;expr2;expr3) statement

for(variable assignment;condition;iteration process) {for-body}

~]# awk '/^[[:space:]]*linux16/{for(i=1;i<=NF;i++) {print $i,length($i)}}' /etc/grub2.cfg

特殊用法:

能够遍历数组中的元素

                  语法:for(var in array) {for-body}

⑤switch语句

语法:switch(expression) {case VALUE1 or /REGEXP/:statement; case VALUE2 or /REGEXP2/:statement; ...; default:statement}

⑥break和continue

break [n]

continue    提前结束本来循环,进入下一字段

⑦next

      awk实际上进行了两次循环

next可以提前结束对本行的处理而直接进入下一行

~]# awk -F: '{if($3%2!=0) next; print $1,$3}' /etc/passwd

8.array

关联数组:array[“index-expression”]

index-expression:

①可使用任意字符串;字符串要使用双引号

②如果某数组元素事先不存在,在引用时,awk会自动创建此元素,并将其值初始化为“空串”

P.S. 若要判断数组中是否存在某元素,要使用"index in array"格式进行

若要遍历数组中的每个元素,要使用for循环

                             for(var in array) {for-body}

~]# awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";for(i in weekdays) {print weekdays[i]}}'  和bash不一样,索引记得不要加$

            P.S. var会遍历array的每个索引

常见用法:统计某一类值出现的次数

~]# netstat -tan | awk '/^tcp\>/{state[$NF]++}END{for(i in state) { print i,state[i]}}'

                       state["LISTEN"]++

                       state["ESTABLISHED"]++

~]# awk '{ip[$1]++}END{for(i in ip) {print i,ip[i]}}' /var/log/httpd/access_log

练习1:统计/etc/fstab文件中每个文件系统类型出现的次数

~]# awk '/^UUID/{fs[$3]++}END{for(i in fs) {print i,fs[i]}}' /etc/fstab

练习2:统计指定文件中每个单词出现的次数

要做行内字段遍历

~]# awk '{for(i=1;i<=NF;i++){count[$i]++}}END{for(i in count) {print i,count[i]}}' /etc/fstab

9.函数

①内置函数

数值处理:

rand():返回0和1之间一个随机数

字符串处理:

length([s]):返回指定字符串的长度

sub(r,s,[t]):以r表示的模式来查找t所表示的字符中的匹配的内容,并将其第一次出现替换为s所表示的内容

gsub(r,s,[t]):以r表示的模式来查找t所表示的字符中的匹配的内容,并将其所有出现均替换为s所表示的内容

split(s,a[,r]):以r为分隔符切割字符s,并将切割后的结果保存至a所表示的数组(从1开始编号)

~]# netstat -tan | awk '/^tcp\>/{split($5,ip,":");count[ip[1]]++}END{for (i in count) {print i,count[i]}}'

②自定义函数

function name(arg1, arg2, arg3..)

{

      statement

}

回顾

grep

      grep:文本过滤器

            PATTERN

            REGEXP:

                  BRE、ERE

            BRE:

                  字符匹配:., [], [^]

                  次数匹配:*, \?, \+, \{m\}, \{m,n\}

                  位置锚定:^, $, \<, \b, \>, \b

                  分组:\(\)

                       后向引用:\1, \2, ...

            vim, sed, awk, nginx,

egrep及扩展的正则表达式

      egrep = grep -E

      egrep [OPTIONS] PATTERN [FILE...]

      扩展正则表达式的元字符:

            字符匹配:

                  .

                  []

                  [^]

            次数匹配:

                  *

                  ?:0或1次;

                  +:1次或多次;

                  {m}:匹配m次;

                  {m,n}:至少m,至多n次;

            锚定:

                  ^

                  $

                  \<, \b

                  \>, \b

            分组:

                  ()

                  后向引用:\1, \2, ...

            或者:

                  a|b

                       C|cat:C或cat

sed

      sed [options] 'SCRIPT' FILE...

      编辑命令:d, p, w, r, a, i, c, s, =,

                       n, N, h, H, g, G, p, P, x, D

awk

      -F, -v

      print, printf

      $i, FS, RS, NF, NR, ARGC, ARGV

      +, -, *, /, ^, %

      >, <, ==, !=

      ~, !~

      &&, ||, !

      BEGIN, END

      for( var in array )

      split(s,a[,r])

参考资料:

①马哥随堂笔记

②《Linux Shell 脚本攻略》

③《Shell 脚本学习指南》

注:诚恳欢迎读者对本文提出批评意见,若发现存在错误,我定第一时间修改。如果读者觉得文章对您有帮助,欢迎点赞鼓励一下哟٩(๑❛ᴗ❛๑)۶。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值