linux中非常重要的三个命令 grep sed awk 结合正则表达式,可以发挥强大的功能。

           正则表达式

正则表达式由以下内容组合而成:


普通字符,例如空格、下划线、A-Z、a-z、0-9。

可以扩展为普通字符的元字符,它们包括:

(.) 它匹配除了换行符外的任何单个字符。

(*) 它匹配零个或多个在其之前紧挨着的字符。

[ character(s) ] 它匹配任何由其中的字符/字符集指定的字符,

你可以使用连字符(-)代表字符区间,例如 [a-f]、[1-5]等。

^ 它匹配文件中一行的开头。

$ 它匹配文件中一行的结尾。

\ 这是一个转义字符。



             sed流编辑器

sed 是一种在线编辑器,它一次处理一行内容。处理时,把当前处理的行存储在临时缓冲区中,

称为“模式空间”(pattern space),接着用sed命令处理缓冲区中的内容,处理完成后,

把缓冲区的内容送往屏幕。接着处理下一行,这样不断重复,直到文件末尾。文件内容并没有 改变,

除非你使用重定向存储输出。Sed主要用来自动编辑一个或多个文件;简化对文件的反复操作;

编写转换程序等。

sed使用参数

  选项与参数:

-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'

第二行后新增

nl /etc/passwd | sed '2a drink tea'

第二行前新增

nl /etc/passwd | sed '2i drink tea' 

  以行为单位的替换与显示

将第2-5行的内容取代成为『No 2-5 number』呢?

  nl /etc/passwd | sed '2,5c No 2-5 number'

   数据的搜寻并显示

搜索 /etc/passwd有root关键字的行:nl /etc/passwd | sed '/root/p' 

数据的搜寻并删除:nl /etc/passwd | sed '/root/d‘

        数据的搜寻并执行命令

   搜索/etc/passwd,找到root对应的行,执行后面花括号中的一组命令,

每个命令之间用分号分隔,这里把bash替换为blueshell,再输出这行:

  nl /etc/passwd | sed -n '/root/{s/bash/blueshell/;p}'

 如果只替换/etc/passwd的第一个bash关键字为blueshell,就退出

   nl /etc/passwd | sed -n '/bash/{s/bash/blueshell/;p;q}'

   数据的搜寻并替换

sed 's/要被取代的字串/新的字串/g'  g表示全局替换,不加g表示只替换每行的第一次匹配

    多点编辑

条sed命令,删除/etc/passwd第三行到末尾的数据,并把bash替换为blueshell

nl /etc/passwd | sed -e '3,$d' -e 's/bash/blueshell/'

      直接修改文件内容(危险动作,实际生产环境中要慎用)

sed 可以直接修改文件的内容,不必使用管道命令或数据流重导向! 

不过,由於这个动作会直接修改到原始的文件,所以请你千万不要随便拿系统配置来测试! 

我们还是使用下载的 regular_express.txt 文件来测试看看吧!

利用 sed 将 regular_express.txt 内每一行结尾若为 . 则换成 !

sed -i 's/\.$/\!/g' regular_express.txt

用 sed 直接在 regular_express.txt 最后一行加入『# This is a test』  

  sed -i '$a # This is a test' regular_express.txt 





                 grep

grep (global search regular expression(RE) and print out the line,

全面搜索正则表达式并把行打印出来)是一种强大的文本搜索工具,

它能使用正则表达式搜索文本,并把匹配的行打印出来。

grep常用用法

-a :将 binary 文件以 text 文件的方式搜寻数据

-c :计算找到 '搜寻字符串' 的次数

-i :忽略大小写的不同,所以大小写视为相同

-n :顺便输出行号

-v :反向选择,亦即显示出没有 '搜寻字符串' 内容的那一行!

--color=auto :可以将找到的关键词部分加上颜色的显示喔!

你可以在 ~/.bashrc 内加上这行:『alias grep='grep --color=auto'』再以『 source ~/.bashrc 』

来立即生效

grep与正规表达式

字符类

grep -n 't[ae]st' xxx.txt 查找文件中有tast或test单词,

其实 [] 里面不论有几个字节,他都谨代表某『一个』字节。

字符类的反向选择 [^] :如果想要搜索到有 oo 的行,但不想要 oo 前面有 g

grep -n '[^g]oo' xxx.txt

 字符类的连续:再来,假设我 oo 前面不想要有小写字节

 grep -n '[^a-z]oo' xxx.txt

 也就是说,当我们在一组集合字节中,如果该字节组是连续的,

例如大写英文/小写英文/数字等等, 就可以使用[a-z],[A-Z],[0-9]等方式来书写,

那么如果我们的要求字串是数字与英文呢? 

呵呵!就将他全部写在一起,变成:[a-zA-Z0-9]


行首与行尾字节 ^ $

行首字符:如果我想要让 the 只在行首列出呢? 这个时候就得要使用定位字节了

grep -n '^the' xxx.txt

开头是小写字节的那一行就列出

grep -n '^[a-z]' xxx.txt


如果我不想要开头是英文字母

grep -n '^[^a-zA-Z]' xxx.txt

那如果我想要找出来,行尾结束为小数点 (.) 的那一行

grep -n '\.$' xxx.txt 特别注意到,因为小数点具有其他意义(底下会介绍),

所以必须要使用转义字符(\)来加以解除其特殊意义

找出空白行grep -n '^$' xxx.txt

. (小数点):代表『一定有一个任意字节』的意思

* (星号):代表『重复前一个字符, 0 到无穷多次』的意思,为组合形态


限定连续 RE 字符范围 {}

我们可以利用 . 与 RE 字符及 * 来配置 0 个到无限多个重复字节, 那如果我想要限制一个范围

区间内的重复字节数呢?

举例来说,我想要找出两个到五个 o 的连续字串,该如何作?这时候就得要使用到限定范围的字符 {} 了。 但因为 { 与 } 的符号在 shell 是有特殊意义的,因此, 我们必须要使用字符   \ 来让他失去特殊意义才行。 

至於 {} 的语法是这样的,假设我要找到两个 o 的字串,可以是:

 grep -n 'o\{2\}' xxx.txt


假设我们要找出 g 后面接2到5个o ,然后再接一个 g 的字串

grep -n 'go\{2,5\}g' xxx.txt





                AWK

awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大。简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理。

awk有3个不同版本: awk、nawk和gawk,未作特别说明,一般指gawk,gawk 是 AWK 的 GNU 版本。

awk是一个卓越的模式扫描和处理语言,它可被用于在 Linux 下构造有用的过滤器。当我们在Unix/Linux 下使用特定的命令从字符串或文件中读取或编辑文本时,我们经常需要过滤输出以得到感兴趣的部分,这时正则表达式就派上用场了。正则表达式可以定义为代表若干个字符序列的字符串。

它最重要的功能之一就是它允许你过滤一条命令或一个文件的输出、编辑文本或配置文件的一部分等等。

有三种方式调用awk

   1.命令行方式

awk [-F  field-separator]  'commands'  input-file(s)

其中,commands 是真正awk命令,[-F域分隔符]是可选的。 input-file(s) 是待处理的文件。

在awk中,文件的每一行中,由域分隔符分开的每一项称为一个域。通常,

在不指名-F域分隔符的情况下,默认的域分隔符是空格。

2.shell脚本方式

将所有的awk命令插入一个文件,并使awk程序可执行,然后awk命令解释器作为脚本的首行,一般通过键入脚本名称来调用。

相当于shell脚本首行的:#!/bin/sh

可以换成:#!/bin/awk

3.将所有的awk命令插入一个单独文件,然后调用:

awk -f awk-script-file input-file(s)

其中,-f选项加载awk-script-file中的awk脚本,input-file(s)跟上面的是一样的。

假设last -n 5的输出如下

   [root@www ~]# last -n 5 <==仅取出前五行

root     pts/1   192.168.1.100  Tue Feb 10 11:21   still logged in

root     pts/1   192.168.1.100  Tue Feb 10 00:46 - 02:28  (01:41)

root     pts/1   192.168.1.100  Mon Feb  9 11:41 - 18:30  (06:48)

dmtsai   pts/1   192.168.1.100  Mon Feb  9 11:41 - 11:41  (00:00)

root     tty1                   Fri Sep  5 14:09 - 14:10  (00:01)


如果只是显示最近登录的5个帐号

   #last -n 5 | awk  '{print $1}'

root

root

root

dmtsai

root

awk工作流程是这样的:读入有'\n'换行符分割的一条记录,然后将记录按指定的域分隔符划分域,

填充域,$0则表示所有域,$1表示第一个域,$n表示第n个域。默认域分隔符是"空白键" 或 "[tab]键",

所以$1表示登录用户,$3表示登录用户ip,以此类推.

 如果只是显示/etc/passwd的账户

 #cat /etc/passwd |awk  -F ':'  '{print $1}'  

 -F指定域分隔符为':'

 

 如果只是显示/etc/passwd的账户和账户对应的shell,而账户与shell之间以tab键分割

 cat /etc/passwd |awk  -F ':'  '{print $1"\t"$7}'

 

 如果只是显示/etc/passwd的账户和账户对应的shell,而账户与shell之间以逗号分割,

 而且在所有行添加列名name,shell,在最后一行添加"blue,/bin/nosh"。

 cat /etc/passwd |awk  -F ':'  'BEGIN {print "name,shell"}  {print $1","$7} 

 END {print "blue,/bin/nosh"}'

 awk工作流程是这样的:先执行BEGING,然后读取文件,读入有/n换行符分割的一条记录,

 然后将记录按指定的域分隔符划分域,填充域,$0则表示所有域,$1表示第一个域,$n表示第n个域,随后开始执行模式所对应的

 动作action。

 接着开始读入第二条记录······直到所有的记录都读完,最后执行END操作。

 搜索/etc/passwd有root关键字的所有行,并显示对应的shell

 awk -F: '/root/{print $7}' /etc/passwd

 awk内置变量

   awk有许多内置变量用来设置环境信息,这些变量可以被改变,下面给出了最常用的一些变量。

  统计/etc/passwd:文件名,每行的行号,每行的列数,对应的完整行内容

 awk  -F ':'  '{print "filename:" FILENAME ",linenumber:" NR ",columns:" NF ",linecontent:"$0}' /etc/passwd

 使用printf替代print,可以让代码更加简洁,易读

 awk  -F ':'  '{printf("filename:%10s,linenumber:%s,columns:%s,linecontent:%s\n",FILENAME,NR,NF,$0)}' /etc/passwd

 printf函数,其用法和c语言中printf基本相似,可以格式化字符串,输出复杂时,printf更加好用,代码更易懂

   awk编程

   除了awk的内置变量,awk还可以自定义变量

 下面统计/etc/passwd的账户人数

 count是自定义变量。之前的action{}里都是只有一个print,其实print只是一个语句,而action{}可以有多个语句,以;号隔开。

 awk 'BEGIN {count=0;print "[start]user count is ", count} {count=count+1;print $0;} END{print "[end]user count is ", count}' 

 /etc/passwd

  

 统计某个文件夹下的文件占用的字节数 以M为单位显示: 

    ls -l |awk 'BEGIN {size=0;} {size=size+$5;} 

END{print "[end]size is ", size/1024/1024,"M"}' 注意,

统计不包括文件夹的子目录

统计某个文件夹下的文件占用的字节数,过滤4096大小的文件(一般都是文件夹):

  ls -l |awk 'BEGIN {size=0;print "[start]size is ", size} {if($5!=4096){size=size+$5;}} 

END{print "[end]size is ", size/1024/1024,"M"}'

循环语句 awk中的循环语句同样借鉴于C语言,支持while、do/while、for、break、continue,

这些关键字的语义和C语言中的语义完全相同

   数组

 因为awk中数组的下标可以是数字和字母,数组的下标通常被称为关键字(key)。值和关键字都存储在内部的一张

 针对key/value应用hash的表格里。由于hash不是顺序存储,因此在显示数组内容时会发现,

 它们并不是按照你预料的顺序显示出来的。数组和变量一样,都是在使用时自动创建的,

 awk也同样会自动判断其存储的是数字还是字符串。一般而言,awk中的数组用来从记录中收集信息,

 可以用于计算总和、统计单词以及跟踪模板被匹配的次数等等。

显示/etc/passwd的账户

awk -F ':' 'BEGIN {count=0;} {name[count] = $1;count++;}; 

END{for (i = 0; i < NR; i++) print i, name[i]}' /etc/passwd