如何使用bash脚本读取二进制文件内容?

Ama*_*nda 16 bash text-processing binary

我想读取一个字符,然后是一个固定长度的字符串(该字符串在文件中不是空终止的,其长度由前面的字符给出)。

如何在 bash 脚本中执行此操作?如何定义字符串变量以便我可以对其进行一些后期处理?

Gil*_*il' 19

如果您想坚持使用 shell 实用程序,您可以使用head提取多个字节,od并将一个字节转换为一个数字。

export LC_ALL=C    # make sure we aren't in a multibyte locale
n=$(head -c 1 | od -An -t u1)
string=$(head -c $n)
Run Code Online (Sandbox Code Playgroud)

但是,这不适用于二进制数据。有两个问题:

  • 命令替换$(…)最终换行符在命令输出。有一个相当简单的解决方法:确保输出以换行符以外的字符结尾,然后删除该字符。

    string=$(head -c $n; echo .); string=${string%.}
    
    Run Code Online (Sandbox Code Playgroud)
  • Bash 和大多数 shell 一样,不擅长处理null bytes。从 bash 4.1 开始,空字节只是从命令替换的结果中删除。Dash 0.5.5 和 pdksh 5.2 具有相同的行为,并且 ATT ksh 在第一个空字节处停止读取。通常,shell 及其实用程序不适合处理二进制文件。(Zsh 是个例外,它旨在支持空字节。)

如果您有二进制数据,则需要切换到 Perl 或 Python 之类的语言。

<input_file perl -e '
  read STDIN, $c, 1 or die $!;    # read length byte
  $n = read STDIN, $s, ord($c);   # read data
  die $! if !defined $n;
  die "Input file too short" if ($n != ord($c));
  # Process $s here
'
Run Code Online (Sandbox Code Playgroud)
<input_file python -c '
  import sys
  n = ord(sys.stdin.read(1))      # read length byte
  s = sys.stdin.read(n)           # read data
  if len(s) < n: raise ValueError("input file too short")
  # Process s here
'
Run Code Online (Sandbox Code Playgroud)


Clé*_*ezo 6

如果您希望能够在 shell 中处理二进制文件,最好的选择(仅?)是使用hexdump工具。

hexdump -v -e '/1 "%u\n"' binary.file | while read c; do
  echo $c
done
Run Code Online (Sandbox Code Playgroud)

只读 X 字节:

head -cX binary.file | hexdump -v -e '/1 "%u\n"' | while read c; do
  echo $c
done
Run Code Online (Sandbox Code Playgroud)

读取长度(并使用 0 作为长度),然后将“字符串”作为字节十进制值:

len=$(head -c1 binary.file | hexdump -v -e '/1 "%u\n"')
if [ $len -gt 0 ]; then
  tail -c+2 binary.file | head -c$len | hexdump -v -e '/1 "%u\n"' | while read c; do
    echo $c
  done
fi
Run Code Online (Sandbox Code Playgroud)

  • 好吧,我可以在这里复制联机帮助页,但我不明白这一点。这里只使用了基本命令,唯一的技巧是使用 hexdump。 (2认同)
  • 拒绝投票是因为你不喜欢/不理解我的回答,真的吗? (2认同)