如何根据模式将包装器添加到文件中?
例如我有以下内容:
...
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
。如果需要,
请替换结尾do
,end
因为您的示例令人困惑...(您用于end
第一个块和do
第二个块),例如这次使用BRE
and[[: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" do
and命令do
始终缩进两个空格,即使内部文本或多或少缩进也是如此。这可能更容易修复,但代价是命令更复杂。