【问题标题】:sed is adding unwanted whitespace to end of file, making it invalidsed 在文件末尾添加不需要的空格,使其无效
【发布时间】:2017-06-02 00:04:31
【问题描述】:

尝试使用 sed 替换文件内容,替换有效,但由于某种原因,我在生成的输出文件末尾获得了额外的空白,导致文件在打开的应用程序中不可读/不可见。

我的命令如下:

for file in *.example ; do LANG=C sed -i "" "s|https://foo.bar|http://foo.bar|g" "$file" ; done

我尝试过但没有成功的事情:

  • 未将 s/[...]/g 参数括在引号中(导致命令失败)
  • 使用 | 以外的分隔符例如 / 或 _ 或 %(没有区别)
  • 使用单引号而不是双引号(没有区别)
  • 同时转义句点和冒号(没有区别)

编辑:这个问题似乎与文件类型有关,因此我不再对解决方案感兴趣。感谢回复的人。

【问题讨论】:

  • 如果您需要备份,请将 sed -i "" 替换为 sed -i,使用 sed -i.tmp。
  • @V.Michel:sed (BSD Sed) 的 macOS (OS X) 实现需要 -i "",不像 GNU 实现 (-i.tmp 可以同时使用这两者,因为 option-argument是非空的)。有关详细信息,请参阅我的 this answer
  • 如果末尾的空格使文件无法打开,则可能不是纯文本文件;如果它不是纯文本文件,则对其进行纯文本样式替换可能会破坏其格式。文件格式是什么?
  • 我看到这种情况发生的唯一方法是当您在s 命令中使用变量并且该变量包含\n\r
  • @GordonDavisson 你是对的,它不是纯文本文件;这是一个种子文件。奇怪的是,我之前在 torrent 文件上使用过其他 sed 命令语句并取得了巨大成功,但这些语句来自不同的来源。我相信,无论出于何种原因,这些文件的来源都以与我的 sed 命令语句不匹配的方式对它们进行了编码。事实上,我什至运行了一个旧的 sed 命令语句,我知道它正在工作,但是在这些文件上,它也损坏了它们。

标签: bash macos unix sed


【解决方案1】:

我建议更换

\foo.bar

通过

foo.bar

【讨论】:

  • 此外,如果您使用不同的分隔符,拼写错误会更容易发现(或者更确切地说,完全避免):sed 's|https://foo.bar|http://foo.bar|'
  • 感谢您发现我的错字。我已经编辑了我的帖子以更正它,并就不同的分隔符听取了您的建议。然而,最初的问题仍然存在。关于空白问题有什么建议吗?
  • @Cyrus 尽管我不再对我的具体问题的解决方案感兴趣,但我仍将其标记为已回答,以感谢您回复并发现我的错字:) 干杯。
【解决方案2】:

事后诸葛亮:

BSD/macOS sed 从根本上说不适合在 二进制 文件中进行替换,因为它 每个输出命令都会输出一个尾随 \n(换行符)。

相比之下,GNU sed 没有这个问题,因为它 - 值得称赞的是 - 如果输入“行”有一个 \n也是。

请注意,换行符分隔行的概念并不真正适用于二进制输入:换行符可能存在也可能不存在,并且可能存在大量数据。在最坏的情况下,将一次读取整个输入[1]

您可以使用以下命令测试此行为:

sed -n 'p' <(printf 'x') | cat -et  # input printf 'x' has no trailing \n

输出x$ 表示添加了一个换行符(cat -et 表示为$)(BSD Sed),而仅x 表示它不是(GNU Sed)。

因此,鉴于您使用的是 macOS,您可以使用Homebrew 来安装带有brew install gnu-sed 的 GNU Sed,然后使用以下命令:

LANG=C gsed -i 's|https://foo.bar|http://foo.bar|g' *.example
  • Homebrew 将 GNU Sed 安装为 gsed,因此它可以 macOS 的股票 (BSD) sed 一起存在。

  • LANG=C(稍微稳健一点:LC_ALL=C)需要按原样传递二进制输入的所有字节,而不会导致二进制字节未被识别为有效字符)。
    请注意,这种方法将您限制为仅使用 ASCII 字符进行替换(除非您明确添加字节值作为转义序列)。

  • 注意不同的、不兼容的-i 就地更新语法无需备份 - no(单独的)选项参数;背景见我的this answer

  • 请注意如何在 Sed 脚本周围使用 '...'(单引号),这通常是可取的,因为它避免了前面发生的 shell 扩展与 Sed 最终看到的内容之间的混淆。


[1] 除了内存使用,这里可以使用 Sed 的默认行解析行为,因为您的替换命令不匹配换行符。但是,如果您想通过 NUL 将输入分解为“行”(并在输出上使用 NUL),则可以使用 GNU Sed 的 -z 选项。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-10-14
    • 1970-01-01
    • 2012-08-06
    • 1970-01-01
    • 2012-04-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多