一、sed(以行为单位处理文件)

  sed意为流编辑器(Stream Editor),在Shell脚本和Makefile中作为过滤器使用非常普遍,也就是把前一个程序的输出引入sed的输入,经过一系列编辑命令转换为另一种格式输出。sed和vi都源于早期UNIX的ed工具,所以很多sed命令和vi的末行命令是相同的。

0、sed命令格式

sed命令行的基本格式为:

  1. sed option 'script' file1 file2 ...
  2. sed option -f scriptfile file1 file2 ...

选项含义:

  1. --version   显示sed版本。
  2. --help   显示帮助文档。
  3. -n,--quiet,--silent   静默输出,默认情况下,sed程序在所有的脚本指令执行完毕后,将自动打印模式空间中的内容,这些选项可以屏蔽自动打印。
  4. -e script   允许多个脚本指令被执行。
  5. -f script-file,
  6. --file=script-file   从文件中读取脚本指令,对编写自动脚本程序来说很棒!
  7. -i,--in-place   直接修改源文件,经过脚本指令处理后的内容将被输出至源文件(源文件被修改)慎用!
  8. -l N, --line-length=N   该选项指定l指令可以输出的行长度,l指令用于输出非打印字符。
  9. --posix    禁用GNU sed扩展功能。
  10. -r, --regexp-extended  在脚本指令中使用扩展正则表达式
  11. -s, --separate    默认情况下,sed将把命令行指定的多个文件名作为一个长的连续的输入流。而GNU sed则允许把他们当作单独的文件,这样如正则表达式则不进行跨文件匹配。
  12. -u, --unbuffered    最低限度的缓存输入与输出。

以上仅是sed程序本身的选项功能说明,至于具体的脚本指令(即对文件内容做的操作)后面我们会详细描述,这里就简单介绍几个脚本指令操作作为sed程序的例子。

  1. a,append 追加
  2. i,insert 插入
  3. d,delete 删除
  4. s,substitution 替换

如:在输出testfile内容的第二行后添加"mmzs":

  1. [root@VM_0_5_centos test]# cat testfile
  2. mmzs
  3. mmzsblog
  4. mmzsit
  5. [root@VM_0_5_centos test]# sed "2a mmzs" ./testfile
  6. mmzs
  7. mmzsblog
  8. mmzs
  9. mmzsit
  10. //删除2-5行后,输出删除后的结果
  11. [root@VM_0_5_centos test]# sed "2,5d" testfile
  12. mmzs

sed处理的文件既可以由标准输入重定向得到,也可以当命令行参数传入,命令行参数可以一次传入多个文件,sed会依次处理。

sed的编辑命令可以直接当命令行参数传入,也可以写成一个脚本文件然后用-f参数指定,编辑命令的格式为:

  1. /pattern/action
  2. 注:其中pattern是正则表达式,action是编辑操作

sed程序一行一行读出待处理文件,如果某一行与pattern匹配,则执行相应的action,如果一条命令没有pattern而只有action,这个action将作用于待处理文件的每一行。

1、常用的sed命令

  1. /pattern/p 打印匹配pattern的行
    /pattern/d 删除匹配pattern的行
    /pattern/s/pattern1/pattern2/ 查找符合pattern的行,将该行第一个匹配pattern1的字符串替换为pattern2
    /pattern/s/pattern1/pattern2/g 查找符合pattern的行,将该行所有匹配pattern1的字符串替换为pattern2

使用p命令需要注意,sed是把待处理文件的内容连同处理结果一起输出到标准输出的,因此p命令表示除了把文件内容打印出来之外还额外打印一遍匹配pattern的行。例如:

  1. 一个文件testfile的内容是:
  2. [root@VM_0_5_centos test]# cat testfile
  3. mmzs
  4. mmzsblog
  5. mmzsit
  6. abc
  7. 123
  8. 打印其中包含abc的行
  9. [root@VM_0_5_centos test]# sed '/abc/p' testfile
  10. mmzs
  11. mmzsblog
  12. mmzsit
  13. abc
  14. abc
  15. 123
  16. 要想只输出处理结果,应加上-n选项,这种用法相当于grep命令
  17. [root@VM_0_5_centos test]# sed -n '/abc/p' testfile
  18. abc
  19. 使用d命令就不需要-n参数了,比如删除含有abc的行
  20. [root@VM_0_5_centos test]# sed '/abc/d' testfile
  21. mmzs
  22. mmzsblog
  23. mmzsit
  24. 123

注意:sed命令不会修改原文件,删除命令只表示某些行不打印输出,而不是从原文件中删去。

使用查找替换命令时,可以把匹配pattern1的字符串复制到pattern2中,例如:

  1. [root@VM_0_5_centos test]# sed 's/bc/-&-/' testfile
  2. mmzs
  3. mmzsblog
  4. mmzsit
  5. a-bc-
  6. 123
  7. pattern2中的&表示原文件的当前行中与pattern1相匹配的字符串
  8. 再比如:
  9. [root@VM_0_5_centos test]# sed 's/\([a-z]\)\([a-z]\)/-\1-~\2~/' testfile
  10. -m-~m~zs
  11. -m-~m~zsblog
  12. -m-~m~zsit
  13. -a-~b~c
  14. 123
    pattern2中的\1表示与pattern1的第一个()括号相匹配的内容,\2表示与pattern1的第二个()括号相匹配的内容。

注意:sed默认使用Basic正则表达式规范,如果指定了-r选项则使用Extended规范,那么()括号就不必转义了。

  1. [root@VM_0_5_centos test]# sed 's/yes/no/;s/mm/MM/' ./testfile
  2. 注:使用分号隔开指令。
  3.  
  4. [root@VM_0_5_centos test]# sed -e 's/yes/no/' -e 's/mm/MM/' testfile
  5. 注:使用-e选项。

2、练习:

如果testfile的内容是:

  1. <html><head><title>Hello World</title></head>
  2. <body>Welcome to the world of mmzs!</body></html>

现在要去掉所有的HTML标签,使输出结果为:

  1. Hello World
  2. Welcome to the world of mmzs!

怎么做呢?如果用下面的命令:

  1. [root@VM_0_5_centos test]# sed 's/<.*>//g' testfile

结果是两个空行,把所有字符都过滤掉了。这是因为,正则表达式中的数量限定符会匹配尽可能长的字符串,这称为贪心的(Greedy)。比如sed在处理第一行时,<.*>匹配的并不是或这样的标签,而是:

  1. <html><head><title>Hello World</title>

这样一整行,因为这一行开头是<,中间是若干个任意字符,末尾是>。那么这条命令怎么改才对呢?答案如下:

  1. 错误:得到两个空行,匹配过多
  2. [root@VM_0_5_centos test]# sed 's/<.*>//g' testfile
  3.  
  4. 限定了匹配的行
  5. [root@VM_0_5_centos test]# sed '/Hello World/s/<[/ a-z]*>//g' testfile
  6. Hello World
  7. <body>Welcome to the world of mmzs!</body></html>
  8. 不完美示例,因为{4,5}导致可扩展性差
  9. [root@VM_0_5_centos test]# sed -r 's/<(\/)?[a-z]{4,5}>//g' testfile
  10. Hello World
  11. Welcome to the world of mmzs!
  12. 正确示例0
  13. [root@VM_0_5_centos test]# sed 's/<[/ a-z]*>//g' testfile
  14. Hello World
  15. Welcome to the world of mmzs!
  16. 正确示例1
  17. [root@VM_0_5_centos test]# sed 's/<[^>]*>//g' testfile
  18. Hello World
  19. Welcome to the world of mmzs!

注:上面代码中的红色部分表示pattern1部分的匹配规则,此处的/也不表示转义,是语法中的(有点类似分隔符的意思)

二、awk(以列为单位处理文件)

  sed以行为单位处理文件,awk比sed强的地方在于不仅能以行为单位还能以列为单位处理文件。awk缺省的行分隔符是换行,缺省的列分隔符是连续的空格和Tab,但是行分隔符和列分隔符都可以自定义,比如/etc/passwd文件的每一行有若干个字段,字段之间以:分隔,就可以重新定义awk的列分隔符为:并以列为单位处理这个文件。awk实际上是一门很复杂的脚本语言,还有像C语言一样的分支和循环结构,但是基本用法和sed类似。

0、awk命令格式

awk命令行的基本形式为:

  1. awk option 'script' file1 file2 ...
  2. awk option -f scriptfile file1 file2 ...

和sed一样,awk处理的文件既可以由标准输入重定向得到,也可以当命令行参数传入,编辑命令可以直接当命令行参数传入,也可以用-f参数指定一个脚本文件,编辑命令的格式为:

  1. /pattern/{actions}
  2. condition{actions}
  3. sed类似,pattern是正则表达式,actions是一系列操作

解释:awk程序一行一行读出待处理文件,如果某一行与pattern匹配,或者满足condition条件,则执行相应的actions,如果一条awk命令只有actions部分,则actions作用于待处理文件的每一行。

1、常用命令

比如文件testfile的内容表示某商店(产品-价格-销量):

  1. [root@VM_0_5_centos test]# cat testfile
  2. ProductA 30 13
  3. ProductB 76 46
  4. ProductC 55 32

打印每一行的第二列:

  1. [root@VM_0_5_centos test]# awk '{print $2;}' testfile
  2. 30
  3. 76
  4. 55

自动变量$1、$2分别表示第一列、第二列等,类似于Shell脚本的位置参数,而$0表示整个当前行。再比如,如果某种产品的库存量低于75则在行末标注需要订货:

  1. [root@VM_0_5_centos test]# awk '$2<75 {printf "%s\t%s\n", $0, "REORDER";} $2>=75 {print $0;}' testfile
  2. ProductA 30 13 REORDER
  3. ProductB 76 46
  4. ProductC 55 32 REORDER

可见awk也有和C语言非常相似的printf函数。awk命令的condition部分还可以是两个特殊的condition-BEGIN和END,对于每个待处理文件,BEGIN后面的actions在处理整个文件之前执行一次,END后面的actions在整个文件处理完之后执行一次。

awk命令可以像C语言一样使用变量(但不需要定义变量),比如统计一个文件中的空行数:

  1. [root@VM_0_5_centos test]# cat testfile
  2. ProductA 30 13
  3. ProductB 76 46
  4.  
  5. ProductC 55 32
  6. [root@VM_0_5_centos test]# awk '/^ *$/ {x=x+1;} END {print x;}' testfile
  7. 2

就像Shell的环境变量一样,有些awk变量是预定义的有特殊含义的:

awk常用的内建变量:

  1. FILENAME 当前输入文件的文件名,该变量是只读的
  2. NR     当前行的行号,该变量是只读的,R代表record
  3. NF     当前行所拥有的列数,该变量是只读的,F代表field
  4. OFS     输出格式的列分隔符,缺省是空格
  5. FS     输入文件的列分融符,缺省是连续的空格和Tab
  6. ORS     输出格式的行分隔符,缺省是换行符
  7. RS     输入文件的行分隔符,缺省是换行符

例如打印系统中的用户帐号列表:

  1. [root@VM_0_5_centos test]# awk 'BEGIN {FS=":"} {print $1;}' /etc/passwd
  2. root
  3. bin
  4. daemon

shell编程基础(七): 处理文件命令sed与awk的更多相关文章

  1. Linux学习之二十一-shell编程基础

    Shell编程基础 Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁.Shell 既是一种命令语言,又是一种程序设计语言.Shell 是指一种应用程序,这个应用程序提供了一个 ...

  2. 【转】Shell编程基础篇-上

    [转]Shell编程基础篇-上 1.1 前言 1.1.1 为什么学Shell Shell脚本语言是实现Linux/UNIX系统管理及自动化运维所必备的重要工具, Linux/UNIX系统的底层及基础应 ...

  3. shell编程基础(转载)

    Shell编程基础 原作者 Leal:请参阅页面底部的编者列表. 授权许可: 创作共享署名协议 GNU 自由文档许可证 注意:本文仍然在持续的修订之中,且错漏之处可能较多.如果能够阅读英语的话,可以考 ...

  4. 【转】Shell编程基础篇-下

    [转]Shell编程基础篇-下 1.1 条件表达式 1.1.1 文件判断 常用文件测试操作符 常用文件测试操作符 说明 -d文件,d的全拼为directory 文件存在且为目录则为真,即测试表达式成立 ...

  5. 【Shell 编程基础第二部分】Shell里的流程控制、Shell里的函数及脚本调试方法!

    http://blog.csdn.net/xiaominghimi/article/details/7603003 本站文章均为李华明Himi原创,转载务必在明显处注明:转载自[黑米GameDev街区 ...

  6. 7-1 shell编程基础之二

    shell编程基础之二 算数运算 bash中的算术运算:help let +, -, *, /, %取模(取余), **(乘方),乘法符号有些场景中需要转义 实现算术运算: (1) let var=算 ...

  7. 6-2 shell编程基础

    shell编程基础 编程基础 Linus:Talk is cheap, show me the code 程序和编程风格 程序: 程序:算法+数据结构 数据:是程序的核心 算法:处理数据的方式 数据结 ...

  8. 41、shell编程基础

    bash的变量默认都是全局变量,脚本内都可以调用,无论在什么位置(函数体中也一样),即函数体外可以调用函数体内的变量: local一般用于局部变量声明,多在函数体内使用: 如果要变为局部变量,则要使用 ...

  9. Linux常用命令和Shell编程基础

    目录相关 cd - .与.. 分别表示当前目录和父目录 - ~与$HOME 都是指当前用户的主目录 - cd – 切换到上一次所在的目录(不一定是父目录) pwd - pwd 显示当前目录 - $PW ...

随机推荐

  1. LinkeList 特有方法

    LinkedList:特有方法:addFirst();addLast();添加元素到集合,添加到头尾,getFirst();getLast();获取元素,但不删除元素.如果集合中没有元素,会出现NoS ...

  2. C++ 虚函数的两个例子

    1. 第一个例子是朋友告诉我Qt中的某个实现 1 #include <iostream> 2 3 // Qt中的某个实现 4 class A{ 5 public: 6 A() = defa ...

  3. mybatis 中的缓冲

    package com.oaec.mybatis.test; import com.oaec.mybatis.dao.StudentDao;import com.oaec.mybatis.entity ...

  4. TCP/IP(一)之开启计算机网络之路

    阅读目录(Content) 一.局域网.广域网和Internet 1.1.局域网 1.2.广域网 1.3.Internet 二.计算机数据之间通信的过程 2.1.路由器的功能(转发收到的分组) 三.O ...

  5. kaldi运行thchs30例子

    首先,thchs30有两种数据库,kaldi运行的数据库最好是 thchs30-openslr. 修改run.sh里面的语音库路径  thchs30=... 修改nj线程数 等于CPU的核心数 修改c ...

  6. JavaScript之DOM对象获取(1)

    我们在操作html中的节点的时候,第一步就需要获取到对应节点(元素),才能有后续的操作.获取节点的方式有很多 1.document.getElementById(‘id值’) 通过id精确的选中某一个 ...

  7. 弹性盒子模型属性之flex-grow

    在学习弹性盒子模型的时候,有几个属性常常让同学们感觉头痛, 不知到最后得到的效果数值到底是怎样计算得来的,那么不要慌,稳住,我们能赢 !!!今天就让我们先来看看flex-grow这个属性 flex-g ...

  8. 简单读!spring-mvc源码之url的暴露之路

    spring中,注册controller的url有多种方式: 1. 你可以啥都不都干,直接使用 @RequestMapping 注解上体路径,然后加上 <component-scan>, ...

  9. while(true)应用之 实现自己的消息队列

    早些时候,一直有个疑问,就是比如你从前端发一个操作之后,后台为什么能够及时处理你的东西呢?当然了,我说的不是,服务器为什么能够立即接收到你的请求之类高大上的东西.而是,假设你用异步去做一个事情,而后台 ...

  10. eureka相关异常

    1. eureka相关异常 1.1. 异常信息 Error creating bean with name 'eurekaAutoServiceRegistration': Singleton bea ...