2

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

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

4 回答 4

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
  } 
}

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

您也可以<filename>像 sed 一样省略和流式传输输入,例如:

cat myfile.txt | perl -ne 'BEGIN...'
于 2012-05-07T03:57:37.917 回答
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 执行多次编辑。但要小心逃避$。

于 2012-05-07T05:28:17.097 回答
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
于 2012-05-07T08:53:35.623 回答
0

发射器:

@(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
于 2012-05-07T04:57:34.780 回答