You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何反转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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 06:54:50