用 0xFF 填充文件在 OSX 中给出 C3BF

Syn*_*sso 5 dd macos

此命令将0xff在 Linux 中填充文件。

dd if=/dev/zero ibs=1k count=100 | tr "\000" "\377" >paddedFile.bin
Run Code Online (Sandbox Code Playgroud)

当我在 OSX 中运行它时,结果是不同的。

$ dd if=/dev/zero ibs=1k count=100 | tr "\000" "\377" >paddedFile.bin
100+0 records in
200+0 records out
102400 bytes transferred in 0.000781 secs (131104008 bytes/sec)
$ hexdump -C paddedFile.bin
00000000  c3 bf c3 bf c3 bf c3 bf  c3 bf c3 bf c3 bf c3 bf  
|................|
*
00032000
Run Code Online (Sandbox Code Playgroud)

这里发生了什么?

Gia*_*968 10

开门见山。

这一切都取决于运行时在终端会话中设置的LANGorLC_ALLtr。Linux 将它们设置为,C而 macOS 将其设置为类似en_US.UTF-8. 当然,这en_US可能是其他一些本地语言,例如en_UK(英国英语),但关键是[something].UTF-8设置而不是纯 ASCII viaC是导致这种情况的原因。

更多细节。

似乎tr在 macOS 中将 转换0xff为 UTF8 等价物,c3bf而不是纯 ASCII 0xff。在此 Apple 社区支持线程中对此进行了解释:

Linux 不像 Mac 那样在终端中处理 Unicode。如果将“LANG”环境变量设置为“C”(在 Linux 上可能是这样),它将起作用。否则,所有这些高位都将被解释为 Unicode 字符。

使用该LANG提示有效!只需执行以下操作;我刚刚在 macOS 10.13.6 (High Sierra) 上亲自测试过。

首先,记下现有的LANG值是这样的:

echo $LANG
Run Code Online (Sandbox Code Playgroud)

我看到的输出是:

en_US.UTF-8
Run Code Online (Sandbox Code Playgroud)

现在将LANG值设置为C这样:

LANG=C
Run Code Online (Sandbox Code Playgroud)

并再次运行该命令:

dd if=/dev/zero ibs=1k count=100 | tr "\000" "\377" >paddedFile.bin
Run Code Online (Sandbox Code Playgroud)

现在这些hexdump值应该是这样的:

hexdump -C paddedFile.bin
00000000  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
*
00019000
Run Code Online (Sandbox Code Playgroud)

要重置该LANG值,只需关闭该终端会话或运行以下命令:

LANG=en_US.UTF-8
Run Code Online (Sandbox Code Playgroud)

或者——正如评论中所指出的——你可以LANGtr像这样调用之前直接在命令行选项中设置值:

dd if=/dev/zero ibs=1k count=100 | LANG=C tr "\000" "\377" >paddedFile.bin
Run Code Online (Sandbox Code Playgroud)

你甚至可以使用LC_ALL而不是LANG因为LANG它只是从LC_ALL这样派生出来的:

dd if=/dev/zero ibs=1k count=100 | LC_ALL=C tr "\000" "\377" >paddedFile.bin
Run Code Online (Sandbox Code Playgroud)

  • “Linux 将其设置为 `C`,而 macOS 将其设置为类似 `en_US.UTF-8`”——我不确定这就是全部。在我的 Kubuntu 或 Debian `env | grep -E 'LANG|LC'` 只返回 `LANG=pl_PL.UTF-8`,所以它是 Unicode。OP 的原始命令仍然是开箱即用的“0xff”。可能是因为 Linux 和 Mac 的 `tr` 实现本身不同吗? (4认同)
  • 是的,它必须由`tr`来完成。在写入文件时发生这种转换是有负面意义的。 (3认同)

ilk*_*chu 6

问题是trLinux 上的GNU并没有真正的多字节字符的概念,而是一次一个字节地工作。

tr手册页的字符和在线文档的说话,但是这是一个有点简单化的。TODO源代码包中的文件提到了这一项(摘自coreutils 8.30):

使 wc、tr、fmt 等工具(大多数 textutils)适应多字节感知。问题是我想避免复制重要的逻辑块,但我也想在单字节模式下运行时只产生最小(最好是“无”)成本。

在 Linux 系统上——即使使用 UTF-8 语言环境 ( en_US.UTF-8)——GNUtr将 an 替换ä为两个“字符”( 的 UTF-8 表示ä有两个字节):

linux$ echo 'ä' | tr 'ä' 'x'
xx
Run Code Online (Sandbox Code Playgroud)

同样,混合 anä和 anö会产生有趣的结果,因为它们的 UTF-8 表示共享一个公共字节:

linux$ echo 'ö' | tr ä x
x?
Run Code Online (Sandbox Code Playgroud)

或者反过来(x这里不适用):

linux$ echo ab | tr ab äx
ä
Run Code Online (Sandbox Code Playgroud)

在您的情况下,GNUtr将 the\377作为原始字节值。

trMac上是不同的,它知道的多字节字符的概念,并采取相应的行动:

mac$ echo 'ä' | tr ä x
x

mac$ echo ab | tr ab äx
äx
Run Code Online (Sandbox Code Playgroud)

数值为 0377 (U+00ff) 的字符的 UTF-8 表示是两个字节c3 bf,所以这就是你得到的。

tr逐字节工作的简单方法是使用 C 语言环境,而不是 UTF-8 语言环境。这再次给出了有趣的行为:

$ echo 'ä' | LC_ALL=C tr 'ä' 'x'
xx
Run Code Online (Sandbox Code Playgroud)

在您的情况下,您可以使用:

... | LC_ALL=C tr "\000" "\377"
Run Code Online (Sandbox Code Playgroud)

或者你可以使用类似 Perl 的东西来生成这些\xff字节:

perl -e 'printf "\377" x 1000 for 1..100'
Run Code Online (Sandbox Code Playgroud)