所以我想回答以下问题sed + 仅当不存在时才在字符串前添加单词和sed——当前面的字符不是某个字符时替换字符串中的字符并更进一步。
假设我有一个文件,我想将其全部替换_
为\_
,但我有两个限制:
- 如果
_
前面已经有 a\
那么我不希望发生任何事情。 (我们从来没有得到过\\
所以不必担心这种情况) - 我们应该仅有的
_
如果出现在两个分隔符之前,请进行此替换。例如,在start[
和之间]end
。
例如,以下内容:
Pretending_we have \_ some start[text that\_is really_cool]end.
Then \_nothing_ would start[happen_ to\_ that crew_]end
会被转换为
Pretending_we have \_ some start[text that\_is really\_cool]end.
Then \_nothing_ would start[happen\_ to\_ that crew\_]end
笔记:我知道在某些情况下,我们希望通过将每个实例替换\_
为未使用的内容,然后将所有_
实例替换为\_
,然后反转第一个更改来链接 sed。但我不想这样做,因为我不知道代码中可能存在哪些其他字符,所以如果可能的话我想直接这样做。
另外,我将在 vim 和终端中执行此操作(vim 作为测试运行以确保其正常工作,然后在终端中处理 11 个不同的文件。)我不太了解两者之间的差异,但是我想我会提到它,以防其中一个比另一个更容易。
编辑:回答一些提出的问题:
- perl/sed/vim 都是可以接受的方法来处理这个问题。只是不确定最好的方法是什么,我对 sed/vim 的正则表达式更满意,因此我提到了这些。 (通过将 sed 和 vim 混为一谈,我认为我造成了混乱,对此感到非常抱歉。我习惯使用 sed 和 vim 正则表达式来处理我的大部分正则表达式需求,并且从我注意到的情况来看,通常我在其中所做的工作完美地工作在 sed 和 vim 上。所以我假设他们使用相同的正则表达式处理,但这可能不是我应该做的安全假设,并且会对此进行查找。
- 我用的是ubuntu
- 一般来说,开始/结束分隔符将在同一行上,因此从理论上讲,这可以是一个安全的假设(尽管如果您知道如何做到这一点,那么行并不重要,这对于未来的人们看待这样的问题也是有好处的)
答案1
我会用perl
它:
perl -pe 's{start\[.*?\]end}{$& =~ s{\\?_}{\\_}gr}ge' < your-file
我们s
将所有 ( g
)start[...]end
序列替换为相同的序列($&
其中包含正则表达式匹配的内容),我们s
替换并r
返回所有 ( g
) _
s ,可选地 ( ?
) 前面带有\
with \_
。该e
标志表示替换 ( $& =~ s{\\?_}{\\_}gr
) 将被e
评估为代码。
假设没有嵌套start[...]end
.
如果start[...]end
s 可能跨越多行,请添加该-0777
选项(将记录分隔符设置为不可能的值),以便将输入作为一个整体进行处理,而不是一次处理一行。
s/pattern/replacement/flags
¹ 使用与 in相同的方法sed
,除了 inperl
我们也可以编写它s{pattern}{replacement}flags
,这有助于嵌套和易读
答案2
仅限 GNU sed:
sed -r ':1;s/(start\[.*[^\])(_.*\]end)/\1\\\2/;t1' file
如果您需要进行替换,则-i
最后设置该标志-ri
答案3
您可以使用 awk 命令来完成这项工作。可以方便地将方括号临时替换为其他字符,例如#
cat yourfile.txt| tr '[]' '#'
现在将上述结果通过管道传递给此命令:
awk -F# 'OFS=""; {for (i=1;i<=NF; i++) if(i%2==0){ gsub("\\\\","",$i);gsub("_","\\_",$i);$i="["$i"]"} print $0}'
答案4
使用 GNU awk 进行多字符RS
、RT
和第三个参数match()
:
$ awk -v RS=']end' '{ORS=RT} match($0,/(.*start\[)(.*)/,a) { gsub(/\\?_/,"\\_",a[2]); $0=a[1] a[2] } 1' file
Pretending_we have \_ some start[text that\_is really\_cool]end.
Then \_nothing_ would start[happen\_ to\_ that crew\_]end