如何使用 sed、awk、grep 等基于模式在源代码中的方法周围添加“包装器”

如何使用 sed、awk、grep 等基于模式在源代码中的方法周围添加“包装器”

如何根据模式将包装器添加到文件中?

例如我有以下内容:

  ...
  find(css_policy_form_stage3).click
  with_ajax_wait
    expect(css_coverage_type_everquote).to be_visible
  end
  with_ajax_wait
    expect(css_coverage_type_everquote).to be_visible
  end
end
it "Stage 3" do
  select(coverage_type, from: css_coverage_type_everquote)
  find(css_has_auto_insurance).click
  ...

我想将这些"with_ajax_wait"块“包裹”在it "waits" do ... end它们周围。

即我想得到:

  ...
  find(css_policy_form_stage3).click
  it "waits" do
    with_ajax_wait
      expect(css_coverage_type_everquote).to be_visible
    end
  end
  it "waits" do
    with_ajax_wait
      expect(css_coverage_type_everquote).to be_visible
    end
  do
end
it "Stage 3" do
  select(coverage_type, from: css_coverage_type_everquote)
  find(css_has_auto_insurance).click
  ...

注释和假设:

  • 缩进代码块始终为 3 行长(带有...期望...和结束)。允许多于我的内部代码行会很好,但对于最简单的情况不需要。
  • 块本身应该有额外的 2 个空格缩进。
  • 还有其他不相关的端(示例显示在“阶段 3”之前)
  • 如果能够指定一个内部模式就好了,例如,只有那些开始expect缩进的代码行的块。我认为 awk 可能是一个工具,因为它能够读取连续行,但我很难知道如何编写它。

我想这是一个普遍有用的问答,因为在文件中添加包装器并不罕见。

有点类似于我之前的问题: 如何使用 awk 根据简单规则缩进源文件?
但是在本例中,我添加了包装器和缩进。

答案1

这是一种方法sed

sed -E '/with_ajax_wait/,/end/{       # if line is in this range
H                                     # append to hold space
/end/!d                               # if it doesn't match end, delete it
//{                                   # if it matches
s/.*//                                # empty the pattern space
x                                     # exchange pattern space w. hold space
s/^(\n)( *)/\2it "waits" do\1\2/      # add first line + initial spacing
s/\n/&  /g                            # re-indent all other lines
G                                     # append hold space to pattern space
s/^(( *).*)/\1\2do/                   # add the closing 'do' + initial spacing
}
}
' infile

所以输入如下:

with_ajax_wait
  expect(css_coverage_type_everquote).to be_visible
end
  find(css_policy_form_stage3).click
  with_ajax_wait
    expect(css_coverage_type_everquote).to be_visible
  end
  something here
    with_ajax_wait
      expect(css_coverage_type_everquote).to be_visible
        got some more stuff here to do
          process it
        done
    end
  end

输出是:

it "waits" do
  with_ajax_wait
    expect(css_coverage_type_everquote).to be_visible
  end
do
  find(css_policy_form_stage3).click
  it "waits" do
    with_ajax_wait
      expect(css_coverage_type_everquote).to be_visible
    end
  do
  something here
    it "waits" do
      with_ajax_wait
        expect(css_coverage_type_everquote).to be_visible
          got some more stuff here to do
            process it
          done
      end
    do
  end

它应该适用于超过三行的块,前提是您的with_ajax_wait块始终以 结尾end。如果需要,
请替换结尾doend因为您的示例令人困惑...(您用于end第一个块和do第二个块),例如这次使用BREand[[:blank:]]代替(空格):

sed '/with_ajax_wait/,/end/{
/with_ajax_wait/{
G
s/\([[:blank:]]*\)\(with_ajax_wait\)\(\n\)/\1it "waits" do\3  \1\2/
p
d
}
//!{
/end/!{
s/^/  /
}
/end/{
G
s/\([[:blank:]]*\)\(end\)\(\n\)/  \1\2\3\1end/
}
}
}
' infile

这个单独处理该范围内的每一行,该范围中的第一行和最后一行被重新缩进并添加包装器,其余行只是重新缩进。

答案2

这对我有用awk

awk '/with_ajax_wait/,/end/{          # match the lines between the blocks
  i=substr($0,0,match($0, "[^ ]")-1); # i contains the indented spaces
  if($0~/with_ajax_wait/){            # if it is the starting block
    $0=i"it \"waits\" do\n  "$0       # ... add the starting block before the line
  }else if($0~/end/){                 # if it is the ending block
    $0="  "$0"\n"i"end"               # ... add the end block after the line
  }else{                              # else
    $0="  "$0                         # just indent the line with 2 spaces
  }
}1' file

解释在评论里。整个语句末尾的1是一个 true 条件,因此awk会打印所有行。

答案3

尝试以下 SED:

sed '/with_ajax_wait/{/end/!N;N;s/^/  it \"waits\" do\n/;s/$/\nend/;s/\n/\n  /g}'

这适用于您给出的示例。

Mac操作系统版本

(在 OS X 10.8.5 上测试)Mac OS 不喜欢某些换行符或将命令与分号链接在一起。请改用以下内容:

sed -E -e '/with_ajax_wait/{' -e '/end/!N' -e 'N' -e 's/^/  it \"waits\" do\
/' -e 's/$/\
end/' -e 's/\n/\
  /g' -e '}'

这些是文字换行符,您可以在终端输入或复制它们。

怎么运行的

关键是N命令。我们想要填充 SED 的内存(模式空间)与一组形式

  with_ajax_wait
    // commands
  end

程序一次一行地遍历文件,直到到达匹配的行with_ajax_wait;然后它运行该N命令,该命令将更多行附加到模式空间,直到到达匹配的行end。程序的其余部分是执行换行的一系列替换:我们将it "waits" do行附加到块的开头,将do行附加到末尾,然后缩进所有内容。

局限性

  • end如果该词出现在任何地方,这将不起作用里面with_ajax_wait ... end。要实现这一点,需要对代码本身进行更认真的解析。如果我们可以保证结束end总是缩进两个空格,那么我们可以通过替换{/end/!N{/\n end/!N或其他东西来使这个 SED 更好一点。
  • it "waits" doand命令do始终缩进两个空格,即使内部文本或多或少缩进也是如此。这可能更容易修复,但代价是命令更复杂。

相关内容