注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

Koala++'s blog

计算广告学 RTB

 
 
 

日志

 
 

Sed 介绍和教程[3]  

2011-01-15 15:11:03|  分类: shell |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

添加多行

上面三种命令都允许你一次添加多行,只需要在每行后面加上一个”\”

#!/bin/sh

sed '

/WORD/ a\

Add this line\

This line\

And this line

'

添加行和模式空间

我前面已经提到过模工空间,大多数命令在模式空上操作,其后的命令在上一次改动的结果上操作。前面三个命令,比如说读文件命令,添加新行到输出流去,这个过程跳过了模式空间。

位置范围和上面的命令

你也许还记得我在前面警告过你一些命令可以处理多行,而有一些命令则不可以。更准确地说:命令:”a””i””r””q”不可以接受一个范围,比如”1,100”或是”/begin/,/end/”。文档上说read命令可以接受一个范围,但我在尝试的时候却出错了,”c”命令,即修改命令可以接受一个范围,并且允许你将多行改为一行。

#!/bin/sh

sed '

/begin/,/end/ c\

***DELETED***

'

    你也可以如下例一般使用大括号,下例是对每行进行操作。

#!/bin/sh

# add a blank line after every line

sed '1,$ {

    a\

 

}'

多行模式

多数Unix工具都是面向行的,正则表达式也是向面行的。搜索跨多行的模式不是一件容易的事(提示,它会非常短)

    Sed读取文本中的一行,执行的命令可能会修改这一行,还可能会输出修改的内容,sed脚本的主循环可能看起来是样:

1.    从输入文件读取一行,将它放入模式空间。如果当前文件到达文件结束处,还有其它文件要读,将当前文件关闭,将下一个文件打开,将新的文件的第一行读入模式空间。

2.    文件行加1。打开一个新文件不会重置文件行数。

3.    检查每一个sed命令,如果在命令前有一个限制,并且在模式空间的当前行符合这一限制,命令就会被执行,一些命令,如”n””d”会导致sed返回第1步,”q”命令会导致sed中止,否则下一条命令继续执行。

4.    在所有命令被检查执行后,除非使用了”-n”参数,sed就将模式空间输出。

在命令前的限制会决定命令是否会被执行,如果限制是一个模式,并且命令是删除命令,下面的例子就是删除所有包含模式的行:

/PATTERN/ d

如果限制是一对行号,那么删除操作会对这个开区间内所有行进行删除。

10,20 d

    如果限制是一对模式,其实有一个变量来标记这对模式,如果第一个模式找到了,如果这个变量为false,第一个模式找到时,将它置为true,如果变量为true,命令就会执行,如果变量为true,当找到后面的一个模式,那么这个变量就会被置为false

/begin/,/end/ d

    你要仔细地看看我前面说的话,我的措辞是有用意的,它会包含一些不常见的情况,如:

# what happens if the second number

# is less than the first number?

sed -n '20,1 p' file

# generate a 10 line file with line numbers

# and see what happens when two patterns overlap

yes | head -10 | cat -n | \

sed -n -e '/1/,/7/ p' -e '/5/,/9/ p'

    天啊,这是什么逻辑。下面是一个新的检查,这次以一个表格的方式呈现,假设输入文件包含以下几行:

AB

CD

EF

GH

IJ

    sed开始工作后,第一行被放入模式空间,下一行是”CD””n””d””p”命令的总结如下:

+----------------+---------+------------------------------------------+

|Pattern   Next   | Command | Output      New Pattern   New Next       |

|Space    Input   |          |             Space        Input         |

+----------------+---------+------------------------------------------+

|AB    CD        | n        | <default>   CD             EF          |

|AB    CD        | d        | -           CD             EF          |

|AB    CD        | p        | AB           CD             EF          |

+----------------+---------+------------------------------------------+

    “n”命令可能也可能不会产生输出这取决于是否使用”-n”选项。

=打印行号

“=”命令将当前行号输出到标准输出,其中一个作用就是找到包含某模式的行号:

# add line numbers first,

# then use grep,

# then just print the number

cat -n file | grep 'PATTERN' | awk '{print $1}'

    sed的做法是:

sed -n '/PATTERN/ =' file

    我可以如下找到所有文件的行号:

#!/bin/sh

lines=`wc -l file | awk '{print $1}' `

    使用sed可以更简单:

#!/bin/sh

lines=`sed -n '$=' file `

    “=”只接收一个位置,所以如果你想打印一个范围的行号,你必须用大括号:

#!/bin/sh

# Just print the line numbers

sed -n '/begin/,/end/ {

=

d

}' file

    因为”=”命令只打印到标准输出,如果你不能在同行的模式上输出它,你需要编辑多行模式来完成这个功能。

y变换

    如果你想将一个单词从小写变到大小,你可以写26个字符的替换,将”a”转换到”A”,等等。Sed有可以如tr程序的命令,它是”y”命令。比如,要将”a””f”变为大写,可以用:

sed 'y/abcdef/ABCDEF/' file

    当然我可以举一个将26个字母转为大写的例子,但那样比较占空间。

    如果你想将包含有16进制数字(比如,0x1aff)转为大写(0x1AFF),你可以用:

sed '/0x[0-9a-zA-Z]*/ y/abcdef/ABCDEF' file

    这种方法只有在文件中只有一个数字的时候才有效,如果你想改变行中第二个单词为大写,你就没辙了,除非你用多行编辑。

”l”打印控制字符

“l”命令可以打印当前模式空间,所以用它来调试sed是很有效的。而且它可将一个不可见字符转为可打印字符,转换规则是”\”加上字符八进制值。在探求sed的微妙的问题时,我感觉打印当前模式空间很有用。

在多行上工作

    在多行模式下有三个新命令:”N””D””P”。我将介绍它们与”n””d””p”单行命令的关系。

    “n”命令会打印当前模式空间(除非使用了-n选项),清空当前模式空间,从输入中读取下一行。”N”命令不打印不当模式空间,也不清空模式当间,它读取下一行,并将新行的字符追加到模式空间。

    “d”命令会删除当前模式空间,并读取下一行,再将新行放入模式空间,并放弃当前操作,然后开始sed的第一个命令,即开始一次新的循环。”D”命令删除模式空间中的第一部分,直到新行的字符,而保留模式空间其余的部分。它像”d”一样,放弃当前操作并开始一个新的循环,但是它不会打印当前模式空间,你在前一步打印它,如果”D”命令在一个大括号里与其它命令一起执行,在”D”之后的命令会被忽略,然后另一组sed命令会被执行,除非模式空间已经空了。如果真是这样,那么循环会重新开始。

    “p”命令会打印整个模式空间,”P”命令只打印模式空间的第一部分,直接新行的字符。

    一些例子也许会说明只用”N”命令不是很有用,下例:

sed -e 'N'

    它不会改变输入流,它会将第一行和第二行结合,并打印它们,将第三行和第四行结合,打印它们,等等。它允许你使用一个新的字符,它匹配在模式空间中在多行中的字符,如果你想搜索一个以”#”结尾的行,并将它追加到另一行,你可以用:

#!/bin/sh

sed '

# look for a "#" at the end of the line

/#$/ {

# Found one - now read in the next line

    N

# delete the "#" and the new line character,

    s/#\n//

}' file

    你可以用下面命令查找前一行包含”ONE”下一行包含”TWO”的两行,并将它打印出来:

#!/bin/sh

sed -n '

/ONE/ {

# found "ONE" - read in next line

    N

# look for "TWO" on the second line

# and print if there.

    /\n.*TWO/ p

}' file

    下一个例子会删除所有在”ONE””TWO”之间的字符:

#!/bin/sh

sed '

/ONE/ {

# append a line

    N

# search for TWO on the second line   

    /\n.*TWO/ {

# found it - now edit making one line

       s/ONE.*\n.*TWO/ONE TWO/

    }

}' file

    你可以在连续两行找一个特定的模式,或是你可以在连续两行中找一个被行边界分开的两个词,下面的例子是查找两个词或是在同一行,或是一个在上一行的行尾另一个在下一行的行首,如果找到,删除第一个词。

#!/bin/sh

sed '

/ONE/ {

# append a line

    N

# "ONE TWO" on same line

    s/ONE TWO/TWO/

# "ONE

# TWO" on two consecutive lines

    s/ONE\nTWO/TWO/

}' file

    如果我们找到一行包含”ONE”并且下一行含有”TWO”,我们用”D”命令删除第一行。

#!/bin/sh

sed '

/ONE/ {

# append a line

    N

# if TWO found, delete the first line

    /\n.*TWO/ D

}' file

    如果我们想打印第一行,而不是删除它,也不打印第二行,可以用将上例的”D”命令换成”P”命令,并用”-n”参数。

#!/bin/sh

sed -n '

# by default - do not print anything

/ONE/ {

# append a line

    N

# if TWO found, print the first line

    /\n.*TWO/ P

}' file

    将三个多行命令结合使用是很常见的,通常的顺序是”N””P”,最后”D”。下面的例子会删除在”ONE””TWO”之间的字符,如果它们没有相邻的两行。

#!/bin/sh

sed '

/ONE/ {

# append the next line

    N

# look for "ONE" followed by "TWO"

    /ONE.*TWO/ {

#   delete everything between

       s/ONE.*TWO/ONE TWO/

#   print

       P

#   then delete the first line

       D

    }

}' file

    在前面我介绍过”=”命令,并用它向一个文件添加行号,你可以用sed的两次调用来实现(尽管可以用一次调用来实现,但这种是在下节介绍)。第一次调用是用sed输出文件行号,然后在下一行打印行内容,第二次调用会将两行合起来:

#!/bin/sh

sed '=' file | \

sed '{

    N

    s/\n/ /

}'

    你可以把一行分成两行,再将它们合并,在下面的例子可,如果文件中有一个16进制数字后面跟了一个单词,你想将第一个单词变为大写,你可以用”y”命令,但你必须将行分为两行,改变其中之一,再将它们合起来,即,一行包含:

0x1fff table2

    会被分成两行:

0x1fff

table2

    并且第一行将被转换为大写,我用tr命令将空格将空间转为新行:

#!/bin/sh

tr ' ' '\012' file|

sed ' {

    y/abcdef/ABCDEF/

    N

    s/\n/ /

}'

    尽管用sed来写不太清晰,但它是能代替tr的,你可以在替换命令中嵌入一个新行,但你必须用一个反斜杠来转义。你必须在替换命令的左部用”\n”,而要在右部内嵌一个新行,这简直太不幸了,深叹一口气,下面是这个例子:

#!/bin/sh

sed '

s/ /\

/' | \

sed ' {

    y/abcdef/ABCDEF/

    N

    s/\n/ /

}'

    有时我添加一个特殊字符做为标记,,并在输入找这个特殊字符,当找到后,它用一个空格来标记,反斜杠是一个不错的选择,但它必须要用反斜杠来转义,这使得sed脚本不清晰,免得有人问白痴问题,下面的脚本是将一个空格转换成”\”和一个新行:

#!/bin/sh

sed 's/ /\\\

/' file

    哈,这才对呢。或是用C Shell来真正把他搞晕!

#!/bin/csh -f

sed '\

s/ /\\\\

/' file

    再来几个这样的例子,我想他再也不会问你问题了!我想我有点过火了。我在下图总结了我们讨论过的所有特性:

+----------------+---------+------------------------------------------+

|Pattern      Next   | Command | Output   New Pattern   New Next       |

|Space    Input |          |             Space        Input         |

+----------------+---------+------------------------------------------+

|AB        CD     | n        | <default>   CD             EF          |

|AB        CD     | N        | -           AB\nCD         EF          |

|AB        CD     | d        | -           CD             EF          |

|AB        CD     | D        | -           CD             EF          |

|AB        CD     | p        | AB           CD             EF          |

|AB        CD     | P        | AB           CD             EF          |

+----------------+---------+------------------------------------------+

|AB\nCD       EF     | n        | <default>   EF             GH          |

|AB\nCD       EF     | N        | -           AB\nCD\nEF    GH          |

|AB\nCD       EF     | d        | -           EF             GH          |

|AB\nCD       EF     | D        | -           CD             EF          |

|AB\nCD       EF     | p        | AB\nCD      AB\nCD         EF          |

|AB\nCD       EF     | P        | AB          AB\nCD         EF          |

+----------------+---------+------------------------------------------+

sed脚本中使用换行

    有时想在sed脚本中用换行符,嗯,这有一些微妙的地方,如果想查找换行符,可以用”\n”,下面是一个查找一个短语,在找到这个短语后,删除换行符的例子。

(echo a;echo x;echo y) | sed '/x$/ {

N

s:x\n:x:

}'

    它会产生:

a

xy

    但是,如果你想插入一个新行,不要用”\n”,而是直接输入新行:

(echo a;echo x;echo y) | sed 's:x:X\

:'

    它会产生:

a

X

 

y

  评论这张
 
阅读(1935)| 评论(1)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017