如何反转grep -P命令并移除输出文件中的脚本内容?
问题描述
我有一批由oops.sh生成的输出文件,这些文件中同时包含了生成它们的脚本完整内容。示例文件内容如下:
Hello world! This script is called #!bash scriptName=$(echo $0) echo """Hello world! This script is called $scriptName.""" # Wait, WTF just happened? echo "Done.". Done.
我希望使用grep或sed命令移除原脚本内容,期望输出如下:
Hello world! This script is called . Done.
我已成功匹配到需要移除的内容——grep -Pazo "(?s)\#\!bash.*?Done\.\"" outputOops.txt,但无法反转匹配结果。(我不懂Perl,目前也没时间学习,该匹配命令是参考StackOverflow答案写出的,但未能理解相关反转匹配的答案)。我尝试了以下命令,除最后两个返回-bash: !: event not found外,其余均无输出:
grep -Pazov "(?s)\#\!bash.*?Done\.\"" outputOops.txt grep -Pazo -v "(?s)\#\!bash.*?Done\.\"" outputOops.txt grep -Pazo --invert-match "(?s)\#\!bash.*?Done\.\"" outputOops.txt grep -Pazo "(?s)(?!)\!bash.*?Exiting\.\"" outputOops.txt grep -Pazo "(?s)(?!)(\!bash.*?Exiting\.")" outputOops.txt
请问我哪里操作错误?grep的-P标志不支持反转匹配吗?如果是,我该用什么替代方法?
问题分析与解决方法
错误原因解析
grep -o与-v的组合逻辑冲突:你用了-o(仅输出匹配的片段)搭配-v(反转匹配),再加上-z(将整个文件视为单行),这会导致逻辑矛盾——-o只提取匹配部分,反转后grep无法正确拆分出"不匹配的片段",所以没有输出。- bash历史扩展触发报错:最后两个命令报错是因为用了双引号包裹正则,bash会把
!解析成历史事件扩展字符,换成单引号就能避免。 grep -P支持反转匹配,但不适合你的需求:-P本身兼容-v,但grep的定位是"过滤/提取内容",而你要的是"删除文件中的一段内容",用grep做这件事会非常别扭。
替代解决方案
更适合的工具是sed,它擅长文本替换/删除操作,以下是可行命令:
方法1:GNU sed 删除目标片段
sed -z -E 's/#!bash.*?Done\."//g' outputOops.txt
-z:把整个文件当作单行处理,解决跨多行匹配的问题-E:启用扩展正则,支持.*?非贪婪匹配逻辑s/匹配内容//g:把匹配到的片段替换为空(等同于删除)
如果你的sed版本支持-P(Perl兼容正则),也可以用:
sed -z -P 's/#!bash.*?Done\."//g' outputOops.txt
方法2:修正grep命令(仅作演示,不推荐)
如果一定要用grep,得去掉-o,利用-z和-v配合正则匹配要删除的块,再输出剩余内容:
grep -Pzav "(?s)#!bash.*?Done\." outputOops.txt
但这种方式依赖grep对单行文本的处理,远不如sed直观可靠。
内容的提问来源于stack exchange,提问作者Photosynthetic
相关产品推荐
相关产品推荐

