在BASH中按字节读取文件

mic*_*kov 13 bash

我需要读取我指定的文件的第一个字节,然后是第二个字节,第三个,依此类推.我怎么能在BASH上做到这一点?PS我需要得到这个字节的HEX

F. *_*uri 17

2016年9月新帖!

由于这是非常具体的,这个添加将在最底层呈现.

升级以添加特定的bash版本(使用bashisms)

使用$foo内置的新版本,您可以做很多事情而无需fork(\0)使您的脚本更快.

首先让我们看看(通过使用man bash$OUTBIN)如何解析高清输出:

LANG=C IFS= read -r -d '' -n 1 foo
Run Code Online (Sandbox Code Playgroud)

十六进制部分是从col 10开始并在col 56结束,间隔3个字符并且在col 34处有一个额外的空间.

所以解析这个可以通过以下方式完成:

 printf [-v var] format [arguments]
 ...
     Arguments to non-string format specifiers are treated as C constants,
     except that ..., and if  the leading character is a  single or double
     quote, the value is the ASCII value of the following character.
Run Code Online (Sandbox Code Playgroud)

老原帖

编辑2为十六进制,你可以使用$OUTBIN

read8() {
    local _r8_var=${1:-OUTBIN} _r8_car LANG=C IFS=
    read -r -d '' -n 1 _r8_car
    printf -v $_r8_var %d \'$_r8_car
}
Run Code Online (Sandbox Code Playgroud)

要么 source

read16() {
    local _r16_var=${1:-OUTBIN} _r16_lb _r16_hb
    read8 _r16_lb &&
    read8 _r16_hb
    printf -v $_r16_var %d $(( _r16_hb<<8 | _r16_lb ))
}
Run Code Online (Sandbox Code Playgroud)

不久

    read8 _r16_hb &&
    read8 _r16_lb
Run Code Online (Sandbox Code Playgroud)

尝试一下:

# Usage:
#       read[8|16|32|64] [varname] < binaryStdInput

read8() {  local _r8_var=${1:-OUTBIN} _r8_car LANG=C IFS=
    read -r -d '' -n 1 _r8_car
    printf -v $_r8_var %d \'$_r8_car ;}
read16() { local _r16_var=${1:-OUTBIN} _r16_lb _r16_hb
    read8  _r16_lb && read8  _r16_hb
    printf -v $_r16_var %d $(( _r16_hb<<8 | _r16_lb )) ;}
read32() { local _r32_var=${1:-OUTBIN} _r32_lw _r32_hw
    read16 _r32_lw && read16 _r32_hw
    printf -v $_r32_var %d $(( _r32_hw<<16| _r32_lw )) ;}
read64() { local _r64_var=${1:-OUTBIN} _r64_ll _r64_hl
    read32 _r64_ll && read32 _r64_hl
    printf -v $_r64_var %d $(( _r64_hl<<32| _r64_ll )) ;}
Run Code Online (Sandbox Code Playgroud)

说明:

read totsize < <(blockdev --getsz /dev/sda)
read64 gptbackup < <(dd if=/dev/sda bs=8 skip=68 count=1 2>/dev/null)
echo $[totsize-gptbackup]
1
Run Code Online (Sandbox Code Playgroud)

编辑 ; 编辑问题:需要十六进制值!?

echo ;sed <(seq -f %02g 0 $[COLUMNS-1]) -ne '
    /0$/{s/^\(.*\)0$/\o0337\o033[A\1\o03380/;H;};
    /[1-9]$/{s/^.*\(.\)/\1/;H};
    ${x;s/\n//g;p}';hd < <(echo Hello good world!)
0         1         2         3         4         5         6         7
012345678901234567890123456789012345678901234567890123456789012345678901234567
00000000  48 65 6c 6c 6f 20 67 6f  6f 64 20 77 6f 72 6c 64  |Hello good world|
00000010  21 0a                                             |!.|
00000012
Run Code Online (Sandbox Code Playgroud)

演示:

while read line ;do
    for x in ${line:10:48};do
        printf -v x \\%o 0x$x
        printf $x
      done
  done < <( ls -l --color | hd )
Run Code Online (Sandbox Code Playgroud)

演示2:我们有十六进制和二进制

echo Hello world | hd
00000000  48 65 6c 6c 6f 20 77 6f  72 6c 64 0a              |Hello world.|
Run Code Online (Sandbox Code Playgroud)

2016年9月的新帖子:

这可能对非常具体的情况很有用,(我已经用它们来制作复制两个磁盘之间的GPT分区,在低级别,没有/dev/sda安装......)

是的,bash可以读二进制!

...但只有一个字节,一个......(因为`char(0)'无法正确读取,正确读取它们的唯一方法是考虑文件结束,如果没有读取字符的话并且未到达文件结尾,则字符读取为char(0)).

这更像是一个概念证明,而不是一个非常有用的工具:有一个纯粹的版本gpt(hexdump).

这种使用最近bash化,下1或更高.

echo Hello world | od -t x1 -t c
0000000  48  65  6c  6c  6f  20  77  6f  72  6c  64  0a
          H   e   l   l   o       w   o   r   l   d  \n
Run Code Online (Sandbox Code Playgroud)

while IFS= read -r -n1 car;do [ "$car" ] && echo -n "$car" || echo ; done
Run Code Online (Sandbox Code Playgroud)

你可以尝试/使用它,但不要试图比较性能!

while IFS= read -rn1 c;do [ "$c" ]&&echo -n "$c"||echo;done < <(ls -l --color)
Run Code Online (Sandbox Code Playgroud)

同样的工作:20毫秒bs=8vs 2000 毫秒我的printf.

...但是如果你想读取文件头中的4个字节甚至硬盘中的扇区地址,这可以完成工作......


ani*_*ane 5

你尝试了xxd吗?它可以根据需要直接给十六进制转储。

对于您的情况,命令将是:

xxd -c 1 /path/to/input_file | while read offset hex char; do
  #Do something with $hex
done
Run Code Online (Sandbox Code Playgroud)

注意:从十六进制中提取字符,而不是在读取行时。这是必需的,因为读取无法正确捕获空白。