Bash is the wrong tool altogether. Shells are good at gluing bits and pieces together; text processing and arithmetic are provided on the side, and data processing isn't in their purview at all.
I'd go for Python over Perl, because Python has bignums right off the bat. Use struct.unpack
to unpack the data.
#!/usr/bin/env python
import os, struct, sys
fmt = "<" + "Q" * 8192
header_bytes = sys.stdin.read(65536)
header_ints = list(struct.unpack(fmt, header_bytes))
sys.stdin.seek(-65536, 2)
footer_bytes = sys.stdin.read(65536)
footer_ints = list(struct.unpack(fmt, header_bytes))
# your calculations here
Here's my answer to the original question. The revised question doesn't have much to do with the original, which was about converting one 8-byte sequence into the 64-bit integer it represents in little-endian order.
I don't think bash has any built-in feature for this. The following snippet sets a
to a string that is the hexadecimal representation of the number that corresponds to the bytes in the specified string in big endian order.
a=0x$(printf "%s" "$string" |
od -t x1 -An |
tr -dc '[:alnum:]')
For little-endian order, reverse the order of the bytes in the original string. In bash, and for a string of known length, you can do
a=0x$(printf "%s" "${string:7:1}${string:6:1}${string:5:1}${string:4:1}${string:3:1}${string:2:1}${string:1:1}${string:0:1}" |
od -t x1 -An |
tr -dc '[:alnum:]')
You can also get your platform's prefered endianness if your od
supports 8-byte types.
a=0x$(printf "%s" "$string" |
od -t x8 -An |
tr -dc '[:alnum:]')
Whether you can do arithmetic on $a
will depend on whether your bash supports 8-byte arithmetic. Even if it does, it'll treat it as a signed value.
Alternatively, use Perl:
a=0x$(perl -e 'print unpack "Q<", $ARGV[0]' "$string")
If your perl is compiled without 64-bit integer support, you'll need to break the bytes up.
a=0x$(perl -e 'printf "%x%08x\n", reverse unpack "L<L<", $ARGV[0]' "$string")
(Replace <
by >
for big-endian or remove it to get the platform endianness.)
I used the -r and -p switch to xxd:
$ echo '0006303030304e43' | xxd -r -p | nc -l localhost 8181
Thanks to inspiration from @Gilles answer, here's a perl version:
$ echo '0006303030304e43' | perl -e 'print pack "H*", <STDIN>' | nc -l localhost 8181
Best Answer
You can use
perl
: