sed单行脚本学习笔记

回家真好

前段时间忙着找工作、项目结题、写报告……反正是总有做不完的事情,哈哈。好在暂时告一段落了,应老妈强烈要求回家休息几天。这次回家除了这身衣服,只带了一本《sed与awk
》,我觉得这种小册子最适合茶余饭后休闲之用。如果你也有兴趣学 sed ,推荐你一起看《sed与awk
》(可以在谷歌图书
在线阅读英文版:D)。

花了两天时间,看完了前面 sed 的部分。要掌握一个工具就要熟悉它的规则,man 等参考手册向我们介绍这些规则,教程则演示如何使用这些规则,但要将这些规则运用自如,还需要去理解别人的代码并尝试自己解决问题。在 SourceForge
上有份经典的文档:《SED单行脚本快速参考
》(单行脚本要求命令行长度小于65个字符),由 Eric Pement
整理,Joe Hong
翻译,通篇阅读后获益良多,故撰此文和大家分享。

精彩脚本摘录

# 在每一行后面增加一空行
sed G

在参考手册中,命令G的作用是“将换行符后的保持空间内容追加到模式空间”。就像前文提到的,看过教程后只是熟悉了规则,还不能将规则运用自如,我自己写的代码是:sed 's/$//n/',就是因为我还不熟悉每个命令会对模式空间产生什么影响。所以看到这段参考代码时感觉眼前一亮:“原来还可以这样写!”

# 显示文件中的最后10行 (模拟“tail”)
sed -e :a -e '$q;N;11,$D;ba'

假设文件有 N 行(N 大于10),显示最后10行也就意味着删除前的 N-10 行。在多行模式中,命令“D”可以删除模式空间中第一行;命令“N”可以将下一行追加到模式空间中,建立多行模式。因此问题转化为:“1)将整个文件的内容放入一个模式空间中;2)删除前 N-10 行。”其中问题1)通过控制语句“b”来解决:sed ':a; N; ba';至于问题二,模式“1,$”代表文本中的所有行,因此紧跟着的命令被执行N次,同理,模式“11,$”匹配后面的 N-10 行,因此“11,$D”一个执行了 N-10 次。

其实,在 GNU sed 中,命令“$q”是可以删掉的,因为在最后一行执行命令“N”就会因出错而自动退出。

另外,在 info 手册中也有一个解决方法:sed '1h;2,10{H;g};$q;1,9d;N;D'。他的思路差不多,只不过是将中间文本保持在“保持空间”而不是“模式空间”,因此无需通过控制语句来制造循环。但它繁琐一些,需要在两处指定地址范围。

# 显示文件中的最后2行(模拟“tail -2”命令)
sed '$!N;$!D'

这条脚本也很精彩,命令“$!N”只能执行到倒数第二行,除了倒数第二行,命令“$!D”都能被执行,因此仅剩下最后两行未被删除。我的解决方法要麻烦一些:sed -n 'N;$p;D',命令“$p”只能执行在倒数第二行执行,并且输出最后两行。当文件只有一行时,两段脚本都没有输出。

我的解决方法

# 显示文件中的倒数第二行
sed -e '$!{h;d;}' -e x # 当文件中只有一行时,输入空行
sed -e '1{$q;}' -e '$!{h;d;}' -e x # 当文件中只有一行时,显示该行
sed -e '1{$d;}' -e '$!{h;d;}' -e x # 当文件中只有一行时,不输出
# 我的解决方法
sed 'x;$!d' # 当文件中只有一行时,输入空行
sed '1h;1!x;$!d' # 当文件中只有一行时,显示该行
sed -n 'N;$P;D' # 当文件中只有一行时,不输出

在解决这个问题上,参看代码显得有些繁琐。只有将每行都交换“模式空间”和“保持空间”的内容(命令“x”),并将除最后一行外所有内容删除(命令“$!d”),就能获得倒数第二行,因为“保持空间”初始化时为空,因此当文件中只有一行时输入空行;为了在文件中只有一行时能显示该行,要对第一行特殊照顾:覆盖保持空间;第三条命令你很熟悉,咋一看以为是上面“tail -2”的解决方法,它们很像,差别仅仅是“tail -2”中“p”是小写,此处是大写。

# 删除文件中的重复行,不管有无相邻。注意hold space所能支持的缓存
# 大小,或者使用GNU sed。
sed -n 'G; s//n/&&/; /^/([ -~]*/n/).*/n/1/d; s//n//; h; P'
# 上面的代码在 GNU sed v4.1.5 中不能正常工作,但在 v4.0.7 中却可以执行。
# 修改后
sed -n 'G; s//n/&&/; /^/([^/n]*/n/).*/n/1/d; s//n//; h; P'

参考代码中运用了一个小技巧:用模式“[ -~]”来匹配所有可打印字符。可打印字符的ASCII范围是0x20-0x7F,而0x20和0x7F分别是空格和波浪线。但这个技巧不能在 GNU sed v4.1.5 中使用(但在 v4.0.7 中却可以使用)。为了使代码通用,需要改为“[^/n]”。

# 只保留多个相邻空行的第一行。并且删除文件顶部和尾部的空行。
# (模拟“cat -s”)
sed '/./,/^$/!d' #方法1,删除文件顶部的空行,允许尾部保留一空行
sed '/^$/N;//n$/D' #方法2,允许顶部保留一空行,尾部不留空行

在我的环境里测试,方法2尾部同样保留一个空行。

我的单行脚本

我看的兴起,也设计了一个单行脚本。问题来源于设计宏替换器,比如C语言中有如下定义:

#define PRINT printf
PRINT("printf with PRINT");

此时使用 s/PRINT/printf/g 就会把字符串中的“PRINT”也替换掉。因此需要使用一下脚本:

# 只替换不在字符串内的模式
sed -r 's/^|"[^"]*"/&/n/g; :a; s/(/n[^"]*)foo//1bar/; ta; s//n//g'
# 只替换字符串中的模式
sed -r 's/^|"[^"]*"//n&/g; :a; s/(/n"[^"]*)1//1x/; ta; s//n//g'

替换不在字符串内模式的原理是:

  1. 先在起始位置和字符串的第二个引号后面添加换行符(s/^|"[^"]*"/&/n/g);
  2. 替换所有将换行符和第一个引号之间的模式,这些字符都不在字符串里面(s/(/n[^"]*)foo//1bar/);
  3. 迭代执行第二部,直到替换所有模式(ta);
  4. 删除所有换行符(s//n//g)。

其中换行符是作分隔符用,你也可以使用其他的、不在该行中的字符。替换字符串内模式的原理基本相同,只是分隔符放到字符串第一个引号的前面,并替换以引号开头的模式。下面是测试结果(将字符‘1’替换为‘x’):

$ cat string

123"123"123
111"44a"jjl
dad"111"ddd
"111"44"5555"
"111""""333"
1122
"1111"2211"1111"
4455
"9988"
"1155"
$ sed -r 's/^|"[^"]*"/&/n/g;:a;s/(/n[^"]*)1//1x/;ta;s//n//g' string

x23"123"x23
xxx"44a"jjl
dad"111"ddd
"111"44"5555"
"111""""333"
xx22
"1111"22xx"1111"
4455
"9988"
"1155"
$ sed -r 's/^|"[^"]*"//n&/g;:a;s/(/n"[^"]*)1//1x/;ta;s//n//g' string

123"x23"123
111"44a"jjl
dad"xxx"ddd
"xxx"44"5555"
"xxx""""333"
1122
"xxxx"2211"xxxx"
4455
"9988"
"xx55"

我的环境是 Debian Lenny + GNU sed 4.1.5。Windows版本可以到 GNUWin32 下载最新的 Sed for Windows,也可以发邮件向我索取 GNU sed.exe v4.0.7。GNU sed 自 v3.02.80 起可以使用转义字符'/t'来代替制表符,其他大部分他版本还不能识别'/t'的简写方式。下面摘录《sed与awk》中很好玩的一段话:

像许多程序一样,sed脚本通常以开始都很小,并且写和读都很简单。在测试脚本时,可能会发现不适用于一般规则的特殊情况。为了解决这些问题,可以给脚本增加行,生成更长、更复杂并且更完整的脚本。虽然花费在细化脚本上的时间抵消了不用手动编辑而节省下来的时间,但至少在这段时间内,你的头脑被自己的这个似乎熟悉的想法占据:“看!计算机完成的。”

 

——《sed与awk》 P119


版权声明

请尊重原创作品。转载请保持文章完整性,并以超链接形式注明原始作者“redraiment
”和主站点
地址,方便其他朋友提问和指正。

联系方式

我的邮箱,欢迎来信(redraiment@gmail.com

我的Blogger(子清行
):http://redraiment.blogspot.com/

我的Google Sites(子清行
):https://sites.google.com/site/redraiment

我的CSDN博客(梦婷轩
):http://blog.csdn.net/redraiment

我的百度空间(梦婷轩
):http://hi.baidu.com/redraiment

时间: 2024-08-15 09:24:34

sed单行脚本学习笔记的相关文章

sed 单行脚本快速参考

sed (stream editor) 功能说明:利用script来处理文本文件. 语法:sed [-hnV][-e<script>][-f<script文件>][文本文件] 补充说明:sed可依照script的指令,来处理.编辑文本文件. 参数: -e<script>或--expression=<script> 以选项中指定的script来处理输入的文本文件. -f<script文件>或--file=<script文件> 以选项中指

SED单行脚本快速参考(流编辑器)第1/2页_linux shell

sed (stream editor) 功能说明:利用script来处理文本文件.语法:sed [-hnV][-e<script>][-f<script文件>][文本文件]补充说明:sed可依照script的指令,来处理.编辑文本文件.参数:-e<script>或--expression=<script> 以选项中指定的script来处理输入的文本文件.-f<script文件>或--file=<script文件> 以选项中指定的scr

SED单行脚本快速参考中文版(Unix 流编辑器)_linux shell

英文标题:USEFUL ONE-LINE SCRIPTS FOR SED (Unix stream editor) 原标题:HANDY ONE-LINERS FOR SED (Unix stream editor) 整理:Eric Pement - 电邮:pemente[at]northpark[dot]edu 版本5.5 译者:Joe Hong - 电邮:hq00e[at]126[dot]com 在以下地址可找到本文档的最新(英文)版本: http://sed.sourceforge.net/

Bash脚本学习笔记快速入门篇

脚本安全 我的所有bash脚本都以下面几句为开场白:  代码如下 复制代码 #!/bin/bash set -o nounset set -o errexit 这样做会避免两种常见的问题:     引用未定义的变量(缺省值为"")     执行失败的命令被忽略 需要注意的是,有些Linux命令的某些参数可以强制忽略发生的错误,例如"mkdir -p" 和 "rm -f". 还要注意的是,在"errexit"模式下,虽然能有效的

PERL脚本 学习笔记_基础教程

1. chomp无参数时,使用默认参数,将对$_操作. 2. 数组@array..可用$array[number]引用.$#array..表示数组中索引数. 3. $!包含出错信息: 4. 默认打开文件句柄的方式是"<"即输入,">>"和">"区别就在于一个添加方式操作文件的. if(@ARGV < 2){ die "Not enough arguments\n"; } 5. select LOG

Awk学习笔记

Awk学习笔记 整理:Jims of 肥肥世家 <jims.yang@gmail.com > Copyright 2004 本文遵从GPL协议,欢迎转载.修改.散布. 第一次发布时间:2004年8月6日 博主笔:本人尊重作者的版权 1. awk简介 awk 是一种编程语言,用于在linux/unix下对文本和数据进行处理.数据可以来自标准输入.一个或多个文件,或其它命令的输出.它支持用户自定义函数和 动态正则表达式等先进功能,是linux/unix下的一个强大编程工具.它在命令行中使用,但更多

[收藏]AWK学习笔记

Table of Contents 1. awk简介 2. awk命令格式和选项 2.1. awk的语法有两种形式 2.2. 命令选项 3. 模式和操作 3.1. 模式 3.2. 操作 4. awk的环境变量 5. awk运算符 6. 记录和域 6.1. 记录 6.2. 域 6.3. 域分隔符 7. gawk专用正则表达式元字符 8. POSIX字符集 9. 匹配操作符(~) 10. 比较表达式 11. 范围模板 12. 一个验证passwd文件有效性的例子 13. 几个实例 14. awk编程

作为一个新手的Oracle(DBA)学习笔记

Oracle数据库笔记 Jack Chaing 作者QQ595696297 交流群 127591054 祝大家学习进步. 如果大家想看Word版本的可以去下载:Word排版比较清晰一些. http://download.csdn.net/detail/jack__chiang/9810532 此笔记是作者本人去年开始从一个DBA新人的学习笔记,积累至今,希望拿出来给那些对DBA有兴趣的童孩学习,大家一起努力嘛. 此笔记记录了作者工作学习中从零基础的学习的记录,和从中遇见的问题与问题的解决!很高兴

Bash学习笔记

                                                                          第1 页        共28页 Bash shell学习笔记 .........................................................................................................................2 1. 引言................