Bash新手;用这个成语生成一个字符串的重复:
echo $(head -c $numrepeats /dev/zero | tr '\0' 'S')
我决定用多个字符替换每个空字节(例如' MyString'而不仅仅是' S'),所以我尝试了以下sed
echo $(head -c $numrepeats /dev/zero | sed 's/\0/MyString/g' )
但我得到一个空输出。我意识到我必须做
echo $(head -c $numrepeats /dev/zero | sed 's/\x0/MyString/g' )
或
echo $(head -c $numrepeats /dev/zero | sed 's/\x00/MyString/g' )
相反,但我不明白为什么。 tr
和sed
匹配的字符之间有什么区别?是因为sed
与正则表达式匹配吗?
修改
有趣的发现\0
replacement
命令的's/regexp/replacement'
部分sed
实际上与&
的行为相同。仍然没有解释为什么\0
中的regexp
与nullbyte不匹配(正如在tr
和大多数其他正则表达式实现中那样)
答案 0 :(得分:3)
从tr(1)的手册页:
SET被指定为字符串...解释的序列是:
\ NNN字符,八进制值NNN(1到3个八进制数字)
对于sed(1),手册页不是那么清楚,所以一些尝试可以显示:
echo -n hi |sed 's/h/t/g' |hexdump -c (0000000 t i)
易。然后:
echo -n hi |sed 's/h//g' |hexdump -c (0000000 i)
空模式删除匹配项。再简单。然后:
echo -n hi |sed 's/h/\0/g' |hexdump -c (0000000 h i)
这个\ 0似乎什么都不做。所以试试
echo -n hi |sed 's/h/\00/g' |hexdump -c (0000000 h 0 i)
哦!是否可以将\ 0作为匹配部分的参考?这也可以解释前面的例子。 sed man page谈到\ 1到\ 9,而不是\ 0(但是\ 0无论如何都有意义,即使在模式规范中也是如此。)
所以,简而言之:对于sed,\ 0有一个特殊含义,不是一个NUL字符。但它理解八进制:
echo -n hi |sed 's/h/\o0/g' |hexdump -c (0000000 \0 i)
和十六进制:
echo -n hi |sed 's/h/\x0/g' |hexdump -c (0000000 \0 i)
正如评论中指出的那样,tr和sed是不同的工具,设计不同。是的,sed使用regexp而tr没有,但这不是关于\ 0的一般解释不同的解释。在unix凌乱的世界中,通常有一些惯例。在unix的凌乱世界中, more 经常是这些约定的例外。
答案 1 :(得分:1)
问题中的后两个命令确实有效:
$ sed --version
sed (GNU sed) 4.4
Packaged by Cygwin (4.4-1)
$ echo -e "Hello\0World" | hexdump.exe -c
0000000 H e l l o \0 W o r l d \n
000000c
$ echo -e "Hello\0World" | sed 's/\x0/MyString/g'
HelloMyStringWorld
$ echo -e "Hello\0World" | sed 's/\x00/MyString/g'
HelloMyStringWorld
八进制序列必须以\o
为前缀(谢谢, Benjamin W。,对于此提示):
$ echo -e "Hello\0World" | sed 's/\o0/MyString/g'
HelloMyStringWorld
因此,OP中必定存在另一个问题。
答案 2 :(得分:1)
特殊问题:本身没有tr
和sed
。相反,这些程序的版本跨时间和操作系统平台。一般来说,UNIX的历史是一个快速变化的花期;更具体地说,tr
在1973年发布用于版本4 Unix,而sed
在1979年首次出现在版本7 Unix中。从一开始,这些是由不同的作者在不同的{{1}上编写的。对于不同的shell,具有不同的目的(注意:Bash在1989年写得很多,而不是"所有者和#34;这些实用程序中的任何一个)。并且,就这些程序如何独立演化,维护(由不同的作者),如何/修复了哪些错误等而言,事情变得更加多样化和复杂。尽管最近已经做出很多努力来标准化核心实用程序,但是os
和sed
以完全相同的方式处理字符是无法理解历史,麻烦的缺乏标准以及奇怪的有益的多个UNIX本身。