gpt4 book ai didi

bash - 在 BASH 中按字节读取文件

转载 作者:行者123 更新时间:2023-11-29 08:48:58 27 4
gpt4 key购买 nike

我需要读取指定文件的第一个字节,然后是第二个字节、第三个字节,依此类推。我怎么能在 BASH 上做呢?P.S 我需要得到这个字节的十六进制

最佳答案

完全重写:2019 年 9 月!

比以前的版本更短更简单! (更快,但没那么快)

是的,可以读写二进制:

语法:

LANG=C IFS= read -r -d '' -n 1 foo

将用 1 个二进制字节填充 $foo。不幸的是,由于 bash 字符串不能包含空字节 ($\0),因此需要读取一个字节一次

但是对于字节读取的,我在 man bash 中错过了这个(查看 2016 年的帖子,在底部):

 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.

所以:

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
}

将使用来自 STDIN 的第一个字节的十进制 ascii 值填充提交的变量名称(默认为 $OUTBIN)

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 ))
}

将使用来自 STDIN 的前 16 位字的十进制值填充提交的变量名称(默认为 $OUTBIN)...

当然,为了切换 Endianness ,你必须切换:

    read8 _r16_hb &&
read8 _r16_lb

等等:

# 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 )) ;}

所以你可以source这个,然后如果你的/dev/sdagpt分区的,

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

答案可以是 1(第一个 GPT 在扇区 1,一个扇区是 512 字节。GPT 备份位置在字节 32。使用 bs=8 512 -> 64 + 32 -> 4 = 544 -> 68 个要跳过的 block ...参见 GUID Partition Table at Wikipedia)。

快速小写函数...

write () { 
local i=$((${2:-64}/8)) o= v r
r=$((i-1))
for ((;i--;)) {
printf -vv '\%03o' $(( ($1>>8*(0${3+-1}?i:r-i))&255 ))
o+=$v
}
printf "$o"
}

此函数默认为 64 位,小端。

Usage: write <integer> [bits:64|32|16|8] [switchto big endian]
  • 有两个参数,第二个参数必须是8163264之一,以是生成的输出的位长度。
  • 使用任何虚拟的第 3 个参数(即使是空字符串),函数将切换到大端。

.

read64 foo < <(write -12345);echo $foo
-12345

...

2015 年第一篇文章...

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

使用新版本的 printf 内置,你可以做很多事情而不必 fork ($(...)) 使你的脚本更快.

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

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

十六进制部分是从第 10 列开始到第 56 列结束,间隔 3 个字符并在第 34 列有一个额外的空格。

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

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 )

旧原帖

编辑 2 为十六进制,您可以使用 hd

echo Hello world | hd
00000000 48 65 6c 6c 6f 20 77 6f 72 6c 64 0a |Hello world.|

od

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

不久

while IFS= read -r -n1 car;do [ "$car" ] && echo -n "$car" || echo ; done

尝试一下:

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

解释:

while IFS= read -rn1 car  # unset InputFieldSeparator so read every chars
do [ "$car" ] && # Test if there is ``something''?
echo -n "$car" || # then echo them
echo # Else, there is an end-of-line, so print one
done

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

od -An -t x1 | while read line;do for char in $line;do echo $char;done ;done

演示:

od -An -t x1 < <(ls -l --color ) |        # Translate binary to 1 byte hex 
while read line;do # Read line of HEX pairs
for char in $line;do # For each pair
printf "\x$char" # Print translate HEX to binary
done
done

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

od -An -t x1 < <(ls -l --color ) |        # Translate binary to 1 byte hex 
while read line;do # Read line of HEX pairs
for char in $line;do # For each pair
bin="$(printf "\x$char")" # translate HEX to binary
dec=$(printf "%d" 0x$char) # translate to decimal
[ $dec -lt 32 ] || # if caracter not printable
( [ $dec -gt 128 ] && # change bin to a single dot.
[ $dec -lt 160 ] ) && bin="."
str="$str$bin"
echo -n $char \ # Print HEX value and a space
((i++)) # count printed values
if [ $i -gt 15 ] ;then
i=0
echo " - $str"
str=""
fi
done
done

2016 年 9 月的新帖子:

这在非常具体的情况下可能很有用,(我用它们在两个磁盘之间手动复制 GPT 分区,在低级别,没有安装 /usr...)

是的,bash 可以读取二进制文件!

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

这与其说是一个非常有用的工具,不如说是一个概念证明:有一个 pure 版本的 hd (hexdump)。

这使用最近的 bashisms,在 bash v4.3 或更高版本下。

#!/bin/bash

printf -v ascii \\%o {32..126}
printf -v ascii "$ascii"

printf -v cntrl %-20sE abtnvfr

values=()
todisplay=
address=0
printf -v fmt8 %8s
fmt8=${fmt8// / %02x}

while LANG=C IFS= read -r -d '' -n 1 char ;do
if [ "$char" ] ;then
printf -v char "%q" "$char"
((${#char}==1)) && todisplay+=$char || todisplay+=.
case ${#char} in
1|2 ) char=${ascii%$char*};values+=($((${#char}+32)));;
7 ) char=${char#*\'\\};values+=($((8#${char%\'})));;
5 ) char=${char#*\'\\};char=${cntrl%${char%\'}*};
values+=($((${#char}+7)));;
* ) echo >&2 ERROR: $char;;
esac
else
values+=(0)
fi

    if [ ${#values[@]} -gt 15 ] ;then
printf "%08x $fmt8 $fmt8 |%s|\n" $address ${values[@]} "$todisplay"
((address+=16))
values=() todisplay=
fi
done

if [ "$values" ] ;then
((${#values[@]}>8))&&fmt="$fmt8 ${fmt8:0:(${#values[@]}%8)*5}"||
fmt="${fmt8:0:${#values[@]}*5}"
printf "%08x $fmt%$((
50-${#values[@]}*3-(${#values[@]}>8?1:0)
))s |%s|\n" $address ${values[@]} ''""'' "$todisplay"
fi
printf "%08x (%d chars read.)\n" $((address+${#values[@]})){,}

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

time hd < <(seq 1 10000|gzip)|wc
1415 25480 111711
real 0m0.020s
user 0m0.008s
sys 0m0.000s

time ./hex.sh < <(seq 1 10000|gzip)|wc
1415 25452 111669
real 0m2.636s
user 0m2.496s
sys 0m0.048s

相同的工作:hd 为 20 毫秒,而我的 bash 脚本 为 2000 毫秒。

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

关于bash - 在 BASH 中按字节读取文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13889659/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com