我用来awk
解析文本文件。该文本文件有四个字节数据字段,如下所示:
11110000 10100000 10110000 10010000
我想读取这些字段并将它们从二进制转换为十六进制。目前我正在使用printf %x
.这样就变成11110000
了十进制数,然后变成了十六进制数。这表示 的值1111000
是0xA98760
而不是0xF0
。
我的代码很简单,而且我对 BASH 和 Linux 很陌生。
awk'{printf(%x %x %x %x, $1, $2, $3, $4)};
如何将字符串字段存储为二进制文件,然后转换为十六进制?我可以使用“ bc <<<”obase=16;ibase=2; 从终端获取十六进制数字。 $变量""。当我尝试编写此脚本时,出现语法错误。
答案1
awk
只支持十进制、八进制和十六进制,不支持二进制。你可以使用perl
:
perl -lane 'BEGIN{$, = " "} print unpack "(H2)*", pack("(B8)4", @F)'
对于dc
GNU tac
(另请参阅tail -r
某些系统):
{ echo 16o2i; cat; echo f; } < file.txt | dc | tac
使用(假设您的语法错误与在 shell 中使用的运算符bc
有关,而不是最新版本的// / )<<<
zsh
zsh
bash
ksh93
mksh
yash
{ echo 'obase=16; ibase=2'; tr -cs 01 '[\n*]'; } < file.txt | bc
答案2
这是一个不优雅的黑客,但它确实有效。声明一个函数 b,它采用数字的二进制表示形式并返回十进制值。然后依靠printf
它的 %x 以十六进制显示。
$ awk 'func b(i, t,a,c){a=1;for(c=length(i);c>0;c--){t+=substr(i,c,1)=="1"?a:0;a*=2}return t}{printf "0x%x 0x%x 0x%x 0x%x\n",b($1),b($2),b($3),b($4)}' bin.txt
0xf0 0xa0 0xb0 0x90
答案3
perl -pale '$_ = join $", map { sprintf "%X", oct "0b$_" } @F'
简短的:
Perl options: -p => autoprint + implcit file read in/line, a.la., awk -a => autosplit line into fields using default delimiter ' ' -l => ORS=IRS="\n" Perl standard variables: $" => list separator, by default it is a single space " " $_ => refers to the whole line, equivalent to $0 in awk @F => fields got by splitting the current line, $1, $2,$3, ... $NF in awk Perl code: map { body } list_of_items Map takes in an input list and applies the code present in it's body on each element of this list to generate an output list.
join <separator>, <list>
Join takes in an input list and joins their elements by the
separator provided in the first argument.
oct <number>
When the input to this function is prefixed by a "0b", then
it is treated to be a binary number and outputs the decimal
equivalent.
sprintf "%x" <decimal>
This function whose format is "%x" treats the input as
decimal and returns the equivalent number in hex.
答案4
如果您的目标系统具有 GNU Bash,您可以利用其算术表达式中对八进制和十六进制以外的基数的支持。例如:
bash$ echo $(( 2#1011 | 2#1100 )) # bitwise OR of 11 and 12
15
好的,如果我们获取这些数据:
11110000 10100000 10110000 10010000
并以某种方式将其融入此语法并对其进行评估:
$(( 2#11110000101000001011000010010000 ))
我们得到了值
4037062800
(是的,这适用于 32 位 bash 版本;我们没有得到否定结果。)
我们可以非常简单地做到这一点:
echo $(( 2#$(tr -d ' ' < file) ))
4037062800
唯一的问题是,这在某种程度上是eval
伪装的。我们根据文件的内容将某个命令的输出插入到一个表达式中,然后对其进行求值。如果file
从不受信任的来源获得,可能会存在安全隐患。例如,我不会将其放入 Apache 下的 CGI 脚本中,其中file
包含任意 Internet 用户提交的表单的 POST 数据。