【问题标题】:sed: Delete match and newline (with CRLF)sed:删除匹配项和换行符(使用 CRLF)
【发布时间】:2022-01-26 08:47:27
【问题描述】:

我想在目录中的所有文件中查询console.log,然后删除与这些行之后的换行符匹配的行。也欢迎 AWK、Perl、Powershell 和 Windows 解决方案(除了 sed)。

但是,因为我在 Windows 上,所以我的代码以 CRLF 结尾,所以普通的 sed /d 不起作用。它只是将行替换为空白行。

之前:

hello.world();
console.log("Debug info");
foo.bar();

之后:

hello.world();
foo.bar();

我使用的当前命令,find pages -type f -exec sed -i -e '/console.log/d' {} \; 只用空行替换一行:

hello.world();

foo.bar();

这里有一些截图可以验证我的意思。

【问题讨论】:

  • 我想我知道为什么:这是因为 CR LF。如果你知道如何解决这个问题,我会非常高兴。如果不是,请重新打开问题。
  • 是的,我该如何解决我的问题。我不想立即将多团队应用转换为 LF。
  • 好的,谢谢。也感谢您帮助我诊断解决方案。我很生气,对此我很抱歉。祝你新年快乐
  • 以编程方式从代码中删除所有日志语句似乎是一种可疑的做法。使用选项使日志记录可控不是更好吗?

标签: awk text sed find


【解决方案1】:

理论上sed 中的d 命令应该删除整行,但是带有 DOS 行尾的行是一个讨厌的极端情况;显然,并非所有sed 版本在它们存在的情况下都能正常运行。

如果您愿意改用 Perl,这应该很简单:

perl -ni -e 'print unless /console\.log/' pages/**

演示:https://ideone.com/NNYocH

(通配符pages/** 不可移植,但如果您有支持此功能的外壳,则可以方便地代替find。)

如果您有 GNU Awk,您可以类似地使用它与 -i inplace 选项来覆盖输入文件。

awk -i inplace 'BEGIN{RS=ORS="\r\n"} !/console\.log/' pages/**

某些 Awk 版本的 DOS CR 行结尾可能存在类似问题,但我相信 GNU Awk 应该可以解决。

最后,这是一个使用临时文件的变体,应该适用于任何 Awk。

find pages -type f -exec sh -c '
    for file; do
        awk "BEGIN{RS=ORS=\"\\r\\n\"} !/console\.log/" "$file" >"$file.$$"
        mv "$file.$$" "$file"
    done' _ {} +

find 的现代版本应该允许您在-exec 之后使用+ 而不是\;,这应该比为每个找到的文件生成一个新的子进程性能要高得多。

注意正则表达式中的文字点应如何正确地进行反斜杠转义或放入字符类中(不带引号的点是匹配除换行符之外的任何字符的正则表达式特殊字符)。

【讨论】:

  • perl 命令不起作用(它还用空行替换换行符,而不是删除它们)。 awk 也做同样的事情,但它也很慢。
  • Perl 适合我,但幸运的是我没有可以检查它的 Windows 系统。如果你没有使用 Unix 兼容的 shell,你可能需要使用不同的引用。
  • 我在 WSL 上通过 Windows 终端使用 bash
  • 我更新了另一个 Awk 变体,但我不知道它是否会比 GNU Awk -i inplace 快。以我的经验,Awk 通常很快。我怀疑通常的 Windows 脑死亡(您是否同时在编辑器中打开了这些文件,或者其他什么?)
  • 新的 awk 变体在某种程度上更快(7.069s 与 8.449s 相比),但它不能正确替换 CRLF
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-13
  • 1970-01-01
  • 1970-01-01
  • 2012-01-09
  • 1970-01-01
相关资源
最近更新 更多