Answers:
sed命令:sed '$!N;s/"[^"]*"\n<[^>]*>/other characters /;P;D'
sed -e :n -e '$!N;s/"[^"]*"\n<[^>]*>/other characters /;tn'
sed -e :n -e '$!N;/"$/{$!bn' -e '};s/"[^"]*"\n<[^>]*>/other characters /g'
它们全部以基本的s///ubstitution命令为基础:
s/"[^"]*"\n<[^>]*>/other characters /
他们也都尽力处理最后一行,因为seds在边缘情况下的输出往往会有所不同。这就是其含义,$!它是匹配!不是$最后一行的每一行的地址。
它们也都使用Next命令将下一条输入\n字符后面的输入行追加到图案空间。任何已经唱歌sed了一段时间的人都会学会依靠\n腰线字符-因为唯一获得该字符的方法是将其明确放置在此处。
这三者都采取了一些尝试,以便在采取行动之前尽可能少地读取输入内容- sed尽快采取行动,不需要在读取整个输入文件之前就这样做。
尽管它们全部完成N,但它们三个递归方法都不同。
第一条命令采用了非常简单的N;P;D循环。这三个命令内置于任何兼容POSIX的命令中,sed并且它们可以很好地相互补充。
N-如前所述,在N插入的\n行分隔符之后,将ext输入行追加到模式空间。P像p; 它会P漂洗图案空间-但只保留到第一个出现的\newline字符。因此,给出以下输入/命令:
printf %s\\n one two | sed '$!N;P;d'sed P只漂一只。但是,随着...
D像d; 它D删除模式空间并开始另一个行循环。不同于 d,D最多仅删除\n模式空间中第一个出现的ewline。如果在\n后跟字符之后的模式空间中有更多内容,请sed从下一个行循环开始,再继续剩余行。d例如,如果将先前示例中的替换为a D,sed则将同时P撕裂一和二。此命令仅对与ubstitution语句不匹配的行递归s///。因为s///ubstitution会删除\n添加了的ewline N,所以在sed D删除模式空间时,将永远不会剩下任何东西。
可以进行测试以应用P和/或D选择性地应用,但是还有其他更适合该策略的命令。因为实现了递归来处理仅匹配替换规则一部分的连续行,所以匹配ubstitution 两端的连续行序列s///不能很好地工作:
鉴于此输入:
first "line"
<second>"line"
<second>"line"
<second>line and so on
...打印...
first other characters "line"
<second>other characters line and so on
它确实可以处理
first "line"
second "line"
<second>line
...正好。
此命令与第三条命令非常相似。都采用一个:b牧场/ tEST标签(如也证明Joeseph R.的答案在这里)和递归回到它在一定条件下。
-e :n -e-可移植sed脚本将:使用\newline或新的内联-execution语句来分隔标签定义。
:n-定义名为的标签n。您可以随时使用bn或将其返回tn。tn- 如果自定义标签以来或自上次成功调用ests以来发生任何故障,则t est命令返回指定的标签(如果未提供,则退出当前行周期的脚本)。s///t在此命令中,对匹配的行进行递归。如果sed成功用其他字符替换了模式,则sed返回:n标签,然后重试。如果s///未执行ubstitution,则会自动打印sed图案空间并开始下一个线周期。
这倾向于更好地处理连续序列。如果最后一个失败,则输出:
first other characters other characters other characters line and so on
如前所述,这里的逻辑与上一个逻辑非常相似,但是测试更加明确。
/"$/bn-这是sed测试。由于branch命令是此地址的函数,sed因此仅在附加了ewline并且模式空间仍以双引号结束之后才可以b牧场返回。:n\n"有作为之间几乎没有做过N和b地-这样sed可以准确地非常迅速收集尽可能多的输入作为必须保证以下线路不能满足您的规则。s///此处的ubstitution不同之处在于,它使用了global标志-因此它将立即进行所有必要的替换。给定相同的输入,此命令的输出与最后一个相同。
DATA您怎么收到文本输入?
<<\DATA\ntext input\nDATA\n中,该文件已生成,但这仅sed是shell在here文档中传递的文本。它会像sed 'script' filename或一样工作process that writes to stdout | sed 'script'。有帮助吗?
D所有修改的行都是双行?(您在必要时使用了它;也许我不太了解sed)
D因为D否则D将从输出中删除您现在看到的翻倍。我刚刚进行了编辑-我可能很快也会对此进行扩展。
D件事。
好吧,我可以想到几种简单的方法,但是都不涉及grep(无论如何也不会进行替代)或sed。
佩尔
要更换每个发生"line"\n<second>用other characters,使用:
$ perl -00pe 's/"line"\n<second>/other characters /g' file
first other characters line and so on
或者,要将多个连续出现的"line"\n<second>视为一个,并用替换所有它们other characters,请使用:
perl -00pe 's/(?:"line"\n<second>)+/other characters /g' file
例:
$ cat file
first "line"
<second>"line"
<second>"line"
<second>line and so on
$ perl -00pe 's/(?:"line"\n<second>)+/other characters /g' file
first other characters line and so on
将-00导致Perl来读取,这意味着“线”被定义为“段落模式”的文件\n\n,而不是\n本质上,每个段落被视为一条线。因此,替换在换行符之间匹配。
awk
$ awk -v RS="\n\n" -v ORS="" '{
sub(/"line"\n<second>/,"other characters ", $0)
print;
}' file
first other characters line and so on
相同的基本思想是,将记录分隔符(RS)设置\n\n为对整个文件进行处理,然后将输出记录分隔符设置为空(否则将打印额外的换行符),然后使用该sub()函数进行替换。
awk应该是print;}' file。我需要避免使用Perl并最好使用sed,无论如何,您都建议使用其他好的选择。
读取整个文件并进行全局替换:
sed -n 'H; ${x; s/"line"\n<second>/other characters /g; p}' <<END
first "line"
<second> line followed by "line"
<second> and last
END
first other characters line followed by other characters and last
${cmds}是GNU特定的-其他大多数seds都需要\n加粗线或-e在p和之间断开}。您可以完全避开括号,而且可以\n方便地携带,甚至可以避免在第一行插入多余的斜线字符,例如:sed 'H;1h;$!d;x;s/"line"\n<second>/other characters /g'
sed -n '1{h;n};H; ${x; s/"line"\n<second>/other characters /g; p}'-但是,这变得难以维护。
这是glenn答案的一种变体,如果您连续多次出现(sed仅适用于GNU ),该变体将起作用:
sed ':x /"line"/N;s/"line"\n<second>/other characters/;/"line"/bx' your_file
该:x只是分支的标签。基本上,这样做是在替换后检查该行,如果仍然匹配"line",则分支回到:x标签(这是正确的bx),然后向缓冲区添加另一行并开始处理它。
sed它使非POSIX标签处理足够远,可以接受一个空格作为标签声明的分隔符。不过,您应该注意,其他任何地方sed都将失败-并且将针对失败N。GNU 在最后一行sed上的a退出之前违反了POSIX准则来打印模式空间N,但是POSIX清楚地表明,如果N在最后一行上读取命令,则不应打印任何内容。
v命令,该命令会相互中断,sed但在GNU 4和更高版本中是空手。
sed -e :x -e '/"line"/{$!N' -e '};s/"line"\n<second>/other characters/;/"line"/bx'。
\n您发表的野蛮言论是我问的原因。人们很少问他们s//\n/是否可以像使用GNU 那样做sed,尽管大多数其他人sed都会拒绝右侧的逃逸。尽管如此,\n转义仍然sed可以在任何POSIX的左侧使用,并且您可以像对其一样轻巧地进行翻译,y/c/\n/尽管它具有与POSIX 相同的效果s/c/\n/g,因此并不总是那么有用。