我需要在包含模式的任何行之前添加一个新行,我们可以假设该模式始终是当前行的第一个字符串。例如
This is a
pattern
This is a
pattern
sed
我可以使用命令添加新行
sed -i 's/pattern\+/\n&/g' file
得到输出
This is a
pattern
This is a
pattern
为了防止添加多个新行(在多次执行的情况下),我想检查模式之前的行是否为空。我知道我可以做到这一点
if [ "$line" == "" ]; then
但是,我首先如何确定匹配模式的前一行呢?
编辑:模式可以出现多次。
答案1
您可以将前一行存储在保留空间中:
sed '
/^pattern/{
x
/./ {
x
s/^/\
/
x
}
x
}
h'
不过,这样会更清晰awk
:
awk '!previous_empty && /pattern/ {print ""}
{previous_empty = $0 == ""; print}'
就像 GNU 实现sed
有一个-i
就地编辑选项一样,GNU 实现也awk
有-i /usr/share/awk/inplace.awk
¹ 功能。
^不使用-i inplace
as尝试首先从当前工作目录gawk
加载inplace
扩展(asinplace
或),有人可能已经在其中植入了恶意软件。随系统提供的扩展inplace.awk
的路径可能会有所不同,请参阅输出inplace
gawk
gawk 'BEGIN{print ENVIRON["AWKPATH"]}'
答案2
我知道你的问题最初是关于 sed 的,但 vim 中有一个非常简单的答案:
:g/.\npattern/norm o
或者,如果您希望完全从命令行运行:
vim file -c "g/.\npattern/norm o" -c "wq"
它的工作方式是查找与以下正则表达式匹配的任何行:
.\npattern
这是您的模式后面的任何非空行。然后,对于每个匹配,它应用以下命令norm o
,该命令在当前光标位置下方打开一个换行符。
答案3
但是,我首先如何确定匹配模式的前一行呢?
嗯...也许这会起作用。
使用grep
及-B
开关:
-B num, --before-context=num
Print num lines of leading context before each match. See
also the -A and -C options.
考虑这个 infile:
cat infile
foo
bar
baz
现在,如果我grep
for bar
,前一行应该为空:
if [[ $(grep -B 1 'bar' infile | head -1) == "" ]]; then echo "line is empty"; fi
line is empty
与使用grep
on相反baz
,前一行是不是空的:
if [[ $(grep -B 1 'baz' infile | head -1) == "" ]]; then echo "line is empty"; fi
<no output>
答案4
如果我们有 gnused (Linux 和许多其他系统中的默认设置,并且可供所有人使用)
sed -zri 's/([^\n]\n)(pattern)/\1\n\2/g' file
在哪里
([^\n]\n)(pattern)
非空行之后的模式-z
用空字符分隔“行”(slurp 文件)-r
具有扩展的正则表达式