为啥 sed 不替换 NULL 字符 \x0?

Posted

技术标签:

【中文标题】为啥 sed 不替换 NULL 字符 \\x0?【英文标题】:Why sed doesn't replace NULL-characters \x0?为什么 sed 不替换 NULL 字符 \x0? 【发布时间】:2022-01-21 02:51:08 【问题描述】:

如果我想替换几行,例如在一个文件或 STDIN 中,我不知道文件或 STDIN 中出现的行数,我可以将整个流程变成一行,例如tr,像这样:

$ printf "%s\n" aaa bbb ccc ddd | tr '\n' '\0' | sed -e 's#bbb\x0ccc\x0ddd#string2\x0string3\x0string4#g' | tr '\0' '\n'

aaa
bbb
ccc
ddd

我想在这种情况下得到这个结论:

aaa
string2
string3
string4

请注意,这是一个测试示例,在实际情况下,我不知道要进行替换的行数。我只知道需要替换的行和需要替换的行。

据我所知,sed 可以替换 NULL 字符,例如:

printf "%s\n" aaa bbb ccc ddd | tr '\n' '\0' | sed -e 's#\x0#\n#g'
aaa
bbb
ccc
ddd

为什么第一种情况没有发生?

您可以尝试用正则表达式替换它-(.*)而不是\x0,但是输入数据不同,会导致替换错误,如下例所示:

$printf "%s\n" aaa bbb ccc ddd bbb ddd | tr '\n' '\0' | sed -e 's#bbb\(.*\)ccc\(.*\)ddd#string2\1string3\2string4#g' | tr '\0' '\n'

aaa
string2
string3
ddd
bbb
string4

您能告诉我如何正确替换多行吗?感谢您的帮助!

【问题讨论】:

sed 是用 C 编写的。NUL 不能出现在 C 字符串中。因此,期望sed 的常见实现能够容忍模式缓冲区内的 NUL,除非 sed 的特定实现被设计和记录为不遗余力地这样做本身就是一个延伸。 (尽管正如 PSkocik 所说,\x0 根本不是 NUL 的完全逃脱,所以这里有一个明显的脱节) 将所有\ns 转换为\0s,就像您对tr '\n' '\0' 所做的那样,将有效的POSIX 文本文件变成无效的文件(通过删除所需的最终\n)等等YMMV 以及任何后续文本处理工具(例如 sed)将其作为输入。不过,您永远不需要这样做,因此,如果您认为您需要针对某些特定应用程序,请发布一个新问题,我们会为您提供帮助。 【参考方案1】:

问题似乎是 \x 转义消耗的不仅仅是 1 零。 考虑在\x0c 中,0c 都是有效的十六进制数字。

十六进制转义的工作方式因语言而异。 例如,在 C 语言中,它们非常贪婪(将消耗所有有效的十六进制数字)。 对于非宽字符串,更明智的 \x 转义将消耗两位数(以填充 8 位字节)。 Sed 的版本似乎是这样工作的。

在实验上,用\x00 替换\x0 有效:

printf "%s\n" aaa bbb ccc ddd | tr '\n' '\0' | sed -e 's#bbb\x00ccc\x00ddd#string2\x00string3\x00string4#g' | tr '\0' '\n'

【讨论】:

以上是关于为啥 sed 不替换 NULL 字符 \x0?的主要内容,如果未能解决你的问题,请参考以下文章

sed 替换特定字符,字符串的行

os x下使用sed进行字符串替换

如何用sed命令替换一行中的某个字符串

[坑]sed命令替换指定字符后不固定字符串,文本信息的替换删除

[坑]sed命令替换指定字符后不固定字符串,文本信息的替换删除

linux 给文件替换字符串/替换内容/替换某行 (shell,sed)