在shell脚本中以较低级别处理二进制数据通常是一个坏主意。
bash变量不能包含字节0。zsh是唯一可以在其变量中存储该字节的外壳。
无论如何,命令参数和环境变量不能包含那些字节,因为它们是传递给execve系统调用的NUL分隔字符串。
另请注意:
var=`cmd`
或其现代形式:
var=$(cmd)
从的输出中删除所有结尾的换行符cmd。因此,如果该二进制输出以0xa字节结尾,则存储在中时将被破坏$var。
在这里,您需要存储编码的数据,例如使用xxd -p。
hdr_988=$(head -c 988 < "$inputFile" | xxd -p)
printf '%s\n' "$hdr_988" | xxd -p -r > "$output_hdr"
您可以定义辅助函数,例如:
encode() {
eval "$1"='$(
shift
"$@" | xxd -p -c 0x7fffffff
exit "${PIPESTATUS[0]}")'
}
decode() {
printf %s "$1" | xxd -p -r
}
encode var cat /bin/ls &&
decode "$var" | cmp - /bin/ls && echo OK
xxd -p输出不是空间有效的,因为它在2个字节中编码了1个字节,但是它使得使用它进行操作(连接,提取部分)更加容易。base64是一种以4为单位编码3个字节的格式,但使用起来并不容易。
该ksh93外壳具有内置的编码格式(uses base64),您可以将其read与printf/ 和print实用程序一起使用:
typeset -b var # marked as "binary"/"base64-encoded"
IFS= read -rn 988 var < input
printf %B var > output
现在,如果没有通过shell或env变量或命令参数进行传递,那么只要您使用的实用程序可以处理任何字节值,就可以了。但是请注意,对于文本实用程序,大多数非GNU实现无法处理NUL字节,并且您需要将语言环境固定为C,以避免出现多字节字符问题。最后一个字符(不是换行符)也会引起问题以及行很长(两个0xa字节之间的字节序列长于LINE_MAX)。
head -c这里可用的位置应该可以,因为它可以使用字节,并且没有理由将数据视为文本。所以
head -c 988 < input > output
应该可以。实际上,至少GNU,FreeBSD和ksh93内置实现是可以的。POSIX未指定-c选项,但表示head应支持任意长度的行(不限于LINE_MAX)
与zsh:
IFS= read -rk988 -u0 var < input &&
print -rn -- $var > output
要么:
var=$(head -c 988 < input && echo .) && var=${var%.}
print -rn -- $var > output
即使在中zsh,如果$var包含NUL字节,您也可以将其作为zsh内置变量(print如上)或函数的参数传递,但不能作为可执行文件的参数传递,因为传递给可执行文件的参数是NUL分隔的字符串,这是内核限制,独立于shell。
dd用来复制单个字节(将其设置count为1)。不过,我不确定要存储它们。