sed在多行匹配后追加

时间:2012-05-06 23:28:41

标签: file sed patch

我得到了一些看起来像这样的代码:

lots of code... 
start(){
  some code...
  if mountpart "$1" /mnt -w ; then
  some code...
}
lots of code...

我现在想在if mountpart "$1" /mnt -w ; then之后使用sed插入一些新代码。 由于if mountpart "$1" /mnt -w ; then存在多次,因此我无法在每次匹配后简单地附加新代码。它应该只在start() { }

内首次出现后插入

为此使用sed是个好主意吗?或者执行此类更改的适当工具是什么?

4 个答案:

答案 0 :(得分:2)

一旦你需要开始跟踪状态(例如,我在文件中的哪个位置?到目前为止我看到了什么?),我通常会从sed切换到perl。这是一个简单的单行程序来完成你需要的工作(用你需要插入的新代码替换“NEW CODE”;用实际文件替换<filename>):

perl -ne 'BEGIN{$state=0} print; if (/^\s*start\(\){/) {$state++;} if (/if mountpart "\$1" \/mnt -w ; then/) { if ($state==1) {print "NEW CODE\n"; $state++;} }'  <filename>

简要地说明这一点:-n使perl的工作有点像sed;它将读取每一行并处理它,但是,除非你要求它,否则它不会打印该行;这让我们在输出新代码之前输出每一行。 -e使perl从命令行读取程序。接受程序并重新格式化并添加注释,我们得到了这个:

// -n runs the program for every line of input
// but a BEGIN {} block only runs once, before input
BEGIN {
  //where are we in the input?
  // 0=no start() yet
  // 1=start() was seen
  // 2=we have output the new code; never do it again
  $state=0
} 

print;  // print the line we just read in, unchanged

if (/^\s*start\(\){/) {  //regex.  Did we see start(){ ?
  $state++;              //if so, change to next state
}

if (/if mountpart "\$1" \/mnt -w ; then/) {   //regex. did we see mountpart cmd?
  if ($state==1) {                            //if so, are we in the right state
    print "NEW CODE\n";                       //if so, output the new code
    $state++;                                 //...and change to next state 
                                              //...so we don't output new code 2x
  } 
}

请注意,我们从不按名称引用该行...我们只是说“print”来打印该行,并且正则表达式看起来像sed paterns,我们假设我们匹配该行。那是因为-n将每一行读入perl的$_变量,这是print等函数的默认参数。这不是我写一个大型perl程序的方式,但对于像这样的单行或简单的一次性修复脚本来说是合适的(和惯用的)。

你也可以省略<filename>并像sed那样输入输入,例如:

cat myfile.txt | perl -ne 'BEGIN...'

答案 1 :(得分:1)

我的sed脚本,patch.sed:

# replace your "if then" block inside start() by another pattern 
# to make it unrecognizable to sed in the next command
/^start(){/,/^}/!{s/if mountpart "$1" \/mnt -w ; then/outside_start/g}

# inside start(), append "NEW CODE" after "if then" block
/if mountpart "$1" \/mnt -w ; then/a\
NEW CODE

# recover your "if then" block outside start()
/^start(){/,/^}/!{s/outside_start/if mountpart "$1" \/mnt -w ; then/g}

输入:

lots of code... 
if mountpart "$1" /mnt -w ; then
lots of code

start(){
  some code...
  if mountpart "$1" /mnt -w ; then
  some code...
}
lots of code...
if mountpart "$1" /mnt -w ; then

运行它:

sed -f patch.sed input

输出:

lots of code...
if mountpart "$1" /mnt -w ; then
lots of code

start(){
  some code...
if mountpart "$1" /mnt -w ; then
    NEW CODE
some code...
}
lots of code...
if mountpart "$1" /mnt -w ; then

你的“start(){”应该在一行的开头,“}”也与它匹配。这是在start()内匹配的方式;

如果没有脚本,您可以使用“-e”选项通过sed执行多重编辑。但要小心逃避$。

答案 2 :(得分:1)

这可能对您有用:

sed '/^start()/,/^}/!b;x;/./{x;b};x;/if mountpart "$1" \/mnt -w ; then/!b;h;a\  NEWCODE' file

如果有很多NEWCODE,请将其放在一个文件中并改为运行:

sed '/^start()/,/^}/!b;x;/./{x;b};x;/if mountpart "$1" \/mnt -w ; then/!b;h;r newcode.txt' file

说明:

保留空间是备用寄存器。它可用于操作文本或(如本例中)标记/开关以显示已发生的事件。

  • 如果文字不在start()}之间拯救/^start()/,/^}/!b
  • 检查保留空间以及是否有任何内容拯救x;/./{x;b}
  • 检查标记,如果没有拯救x;/if mountpart "$1" \/mnt -w ; then/!b
  • 将标记字符串作为状态开关h
  • 放置在保留空间中
  • 附加/阅读NEWCODE a\ NEWCODEr newcode.txt

答案 3 :(得分:0)

TXR:

@(collect)
@prolog
@(until)
start(){
@(end)
@(collect)
@inner
@(until)
  if mountpart "$1" /mnt -w ; then
@(end)
@(collect)
@epilog
@(end)
@(output)
@{prolog "\n"}
@{inner "\n"}
@{epilog[0]}
NEW TEXT
@{epilog[1..t] "\n"}
@(end)

数据:

lots of code... 
  if mountpart "$1" /mnt -w ; then
lots of code

start(){
  some code...
  if mountpart "$1" /mnt -w ; then
  some code...
}
lots of code...
  if mountpart "$1" /mnt -w ; then

执行命令

$ txr insert.txr code.sh
lots of code... 
  if mountpart "$1" /mnt -w ; then
lots of code

start(){
  some code...
  if mountpart "$1" /mnt -w ; then
NEW TEXT
  some code...
}
lots of code...
  if mountpart "$1" /mnt -w ; then