标签:grep、sed、awk
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
本文出自 “学不思则惘 思不学则殆” 博客,请务必保留此出处http://tuwei.blog.51cto.com/11040555/1916536
标签:grep、sed、awk
原文地址:http://tuwei.blog.51cto.com/11040555/1916536