我想替换与正则表达式匹配的文件的一部分。关键是,它必须作为单个字符串(如grep -Pzo
)处理整个文件,但据我所知,sed
是基于行的。
我试图强制sed
通过操纵IFS
来强制执行此操作,但我仍然缺乏bash
经验,而且我不确定我在做什么。
我希望你能帮助我澄清一些我不理解的事情。
所以我做了这样的事情:
OIFS=$IFS
IFS=""
content=$(cat -v file | sed 's/(?<=<\/div>(?!.*\/div>)).*//')
#Remove everything begining from last </div> to the end of file.
IFS=$OIFS
但我没有像我预期的那样工作。我也在试验perl
进行替换,但问题似乎是一样的
我会很感激任何提示。
编辑:
根据下面的评论,我正在粘贴一些示例数据:
Source:
<html>
<body>
<div>
some site with many <div> divs </div>
<div> and more <div> even more </div> </div>
</div> <!-- last div closing -->
This is all to be deleted
</body>
</html>
然后:s/</div>(?<=<\/div>(?!.*\/div>)).*//s
<html>
<body>
<div>
some site with many <div> divs </div>
<div> and more <div> even more </div> </div>
编辑2:
我找到了比下面建议更简单的方法:
cat file | perl -0pe 's/(?<=<\/div>(?!.*\/div>)).*//'
-0导致记录分隔符为空,这使得perl在一次运行中处理整个字符串而不是循环遍历行。
答案 0 :(得分:3)
您可以通过撤消输入文件,删除第一个</div>
之前的所有内容然后再次撤消来执行此操作:
tac input.txt | sed '1,/<\/div>/d' | tac > output.txt
这将删除包含</div>
的最后一行及其后的所有内容。
替代sed
(虽然不是很漂亮,但我确信有更聪明的方法):
tr '\n' '~' < input.txt | sed -r 's~(.*)</div>.*~\1~g' | tr '~' '\n' > output.txt
使用占位符(在此示例中为~
)替换换行符,以便所有内容都在一行上,将该行匹配到最后一行</div>
,然后再次替换换行符。根据您的输入数据选择占位符,显然它应该是不会发生的事情。
答案 1 :(得分:3)
这是一个更通用的解决方案:
$ cat file | tr '\n' '\r' | sed 's,\(.*</div>\).*,\1,' | tr '\r' '\n'
<html>
<body>
<div>
some site with many <div> divs </div>
<div> and more <div> even more </div> </div>
</div>
说明:
tr '\n' '\r'
通过回车替换换行符,因此sed
会将文件内容视为一行。
sed 's,\(.*</div>\).*,\1,'
删除</div>
的最后一场比赛后的所有内容。
tr '\r' '\n'
用换行符替换剩余的回车符。
注意:如果您的原始文件包含windows样式的\ r \ n换行符,请先转换为unix样式的换行符:
$ cat file | dos2unix | tr '\n' '\r' | sed 's,\(.*</div>\).*,\1,' | tr '\r' '\n' | unix2dos
答案 2 :(得分:0)
有些人喜欢awk
awk '/<\/div>/ {exit} 1' file
找到模式后exit
。