为啥 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 的完全逃脱,所以这里有一个明显的脱节)
将所有\n
s 转换为\0
s,就像您对tr '\n' '\0'
所做的那样,将有效的POSIX 文本文件变成无效的文件(通过删除所需的最终\n
)等等YMMV 以及任何后续文本处理工具(例如 sed
)将其作为输入。不过,您永远不需要这样做,因此,如果您认为您需要针对某些特定应用程序,请发布一个新问题,我们会为您提供帮助。
【参考方案1】:
问题似乎是 \x
转义消耗的不仅仅是 1 零。
考虑在\x0c
中,0
和c
都是有效的十六进制数字。
十六进制转义的工作方式因语言而异。
例如,在 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命令替换指定字符后不固定字符串,文本信息的替换删除