从 stdin 捕获特殊字符到 shell 变量

Capturing special characters from stdin to a shell variable

我有一个程序可以打印包含空字节 [=19=] 和特殊字符(如 \x1f 和换行符)的内容。例如:

someprogram

#!/bin/bash
printf "ALICE[=11=]BOB\x1fCHARLIE\n"

给定这样一个程序,我想以这样一种方式读取它的输出,即所有这些特殊字符都被捕获在 shell 变量 output 中。所以,如果我 运行:

echo $output

因为我没有给出 -e,所以我希望输出为:

ALICE[=13=]BOB\x1fCHARLIE\n

如何实现?

我的第一次尝试是:

output=$(someprogram)

但是我得到了没有特殊字符的回显输出:

./myscript.sh: line 2: warning: command substitution: ignored null byte in input
ALICEBOBCHARLIE

我也试过使用read如下:

output=""
while read -r
do
    output="$output$REPLY"
done < <(someprogram)

然后我摆脱了警告,但输出仍然缺少所有特殊字符:

ALICEBOBCHARLIE

那么我如何捕获 someprogram 的输出,使我的结果字符串中包含所有特殊字符?

编辑:请注意,在 bash:

中可以有这样的字符串
$ x="ALICE[=18=]BOB\x1fCHARLIE\n"
$ echo $x
ALICE[=18=]BOB\x1fCHARLIE\n

所以这不应该是问题所在。

EDIT2:既然我得到了一个可接受的答案并且我对事情的理解更好了一点,我将稍微重新表述这个问题。所以,我只需要能够将 someprogram 的输出存储在某些 shell 变量中,这样我就可以将它打印到标准输出而无需任何特殊字符的任何更改,就好像 someprogram 直接通过管道传输到标准输出。

您不能在 bash 变量中存储零字节。不可能。

通常的解决方案是将字节流转换为十六进制。然后每次你想用它做点什么的时候把它转换回来。

$ x=$(printf "ALICE[=10=]BOB\x1fCHARLIE\n" | xxd -p)
$ echo "$x"
414c49434500424f421f434841524c49450a
$ <<<"$x" xxd -p -r | hexdump -C
00000000  41 4c 49 43 45 00 42 4f  42 1f 43 48 41 52 4c 49  |ALICE.BOB.CHARLI|
00000010  45 0a                                             |E.|
00000012

您也可以为此目的编写自己的序列化和反序列化函数。

我的另一个想法是,例如通过使用零字节作为分隔符(因为任何其他字节都是有效的)将数据读入数组。然而,这会在区分尾随零字节时出现问题:

 $ readarray -d '' arr < <(printf "ALICE[=11=]BOB\x1fCHARLIE\n")
 $ printf "%s[=11=]" "${arr[@]}" | hexdump -C
 00000000  41 4c 49 43 45 00 42 4f  42 1f 43 48 41 52 4c 49   |ALICE.BOB.CHARLI|
 00000010  45 0a 00                                          |E..|
 #               ^^ additional zero byte if input doesn't contain a trailing zero byte
 00000013