
Mir gefällt sehr gut hexdump
, insbesondere weil man ein benutzerdefiniertes Format definieren kann, beispielsweise:
$ echo -e '\x00\x01\x02\x03' | hexdump -v -e '1/1 "%_ad: "' -e '4/1 "%02X "' -e '1/1 " : "' -e '4/1 "%_p"' -e '1/1 "\n"'
0: 00 01 02 03 : ....
4: 0A : .
Ich kann also beispielsweise 4 Bytes pro Zeile wählen, die zuerst hexadezimal und dann als Zeichen geschrieben werden. Was mir hier jedoch fehlt, ist ein Formatierungszeichen für „Binärzeichenfolgen“ (oder „Bitfolgen“). Ich möchte beispielsweise -e '4/1 "%08b "'
irgendwo in dieser Befehlszeile etwas wie Folgendes schreiben und beispielsweise Folgendes erhalten:
0: 00 01 02 03 : 00000000 00000001 00000010 00000011 : ....
4: 0A : 00001010 : .
Natürlich müsste man dann wahrscheinlich noch die Byte-Reihenfolge angeben (wenn Gruppen von mehr als einem Byte formatiert werden sollen) usw.... Aber diese Art der Formatierung gibt es jedenfalls nicht, soweit ich das im Handbuch sehen kann hexdump
.
Meine Frage ist also: Welche Alternativen habe ich in einer Linux-Befehlszeile, damit ich einen formatierten Dump erhalten kann, der Binärzeichenfolgen wie oben enthält und dennoch die Anpassbarkeit des hexdump
Programms (hinsichtlich der Bytegruppierung) bei Verwendung seiner -e
Option so weit wie möglich bewahrt?
Antwort1
Wenn Sie kein Dump-Programm mit geeigneten Dump-Optionen haben, können Sie immer etwas zusammenschustern, indem Sie sowohl als auch verwenden hexdump
und xdd
die Ausgabe dann mit Paste zusammenfügen. Das ist nicht schön, aber die Verwendung einer Shell, die Prozesssubstitution unterstützt ( bash
reicht aus):
mkfifo fifo
echo -e '\x00\x01\x02\x03' |
tee fifo |
paste -d' ' \
<(hexdump -v -e '1/1 "%_ad: "' -e '4/1 "%02X "' -e '1/1 " :\n"') \
<(xxd -b -c 4 fifo | cut -d' ' -f 2-)
Ausgabe:
0: 00 01 02 03 : 00000000 00000001 00000010 00000011 ....
4: 0A : 00001010 .
Antwort2
Hier ist mein Vorschlag für die Verwendung von Perl unter Verwendung der Formatierungsbezeichner für die Funktion pack()
/ unpack()
. Der Testaufruf sähe dann folgendermaßen aus:
$ echo -e '\x00\x01\x02\x03' | perl hexdump-00.pl --offset 120 --group 4 --add '(H2)*' --add '(B8)*'
Opening '' STDIN
Cannot seek!
0
00000000: 00 01 02 03 00000000 00000001 00000010 00000011 '....'
00000004: 0a 00001010 '.'
Es ist ziemlich schwierig, dazwischen String-Markierungen einzufügen – aber das Schöne ist, dass Sie Bytes trotzdem „gruppieren“ können – Sie können z. B. zwei Bytes gruppieren und sie als vorzeichenbehaftete (kurze) Ganzzahlen interpretieren, Beispiel:
$ perl -e 'print pack("s*\n", (-124))' | hexdump -C
00000000 84 ff |..|
00000002
$ echo -e '\x00\x01\x84\xff' | perl hexdump.pl \
--offset 120 --group 4 \
--add '(H2)*' \
--add '(B8)*' \
--add '(s2)*'
Opening '' STDIN
Cannot seek!
0
00000000: 00 01 84 ff 00000000 00000001 10000100 11111111 256 -124 '....'
00000004: 0a 00001010 '.'
Hier ist hexdump-00.pl
:
#!/usr/bin/perl
# perl hexdump-00.pl --offset 120 --group 4 --add '(H2)*' --add '(B8)*' test.file
use strict;
use warnings;
use Getopt::Long;
use Fcntl qw(SEEK_CUR SEEK_SET);
my $offset = 0;
my $groupsize = 1;
my $length = 128;
my @list=();
my $result = GetOptions (
"offset=i" => \$offset,
"group=i" => \$groupsize,
"length=i" => \$length,
"add=s" => \@list,
);
my $inputfname="";
my $inputfh;
$inputfname = $ARGV[0] if defined $ARGV[0];
if (($inputfname eq "") || ($inputfname eq "-")) {
printf(STDERR "Opening '%s' STDIN\n", $inputfname);
$inputfh = *STDIN;
} else {
printf(STDERR "Opening '%s'\n", $inputfname);
open ($inputfh, "<$inputfname");
}
binmode($inputfh);
my $startaddr=0;
if( not(defined($startaddr = sysseek($inputfh, $offset-1, SEEK_SET))) ) {
printf(STDERR "Cannot seek!\n");
#~ $startaddr = sysseek($inputfh, 0, 0); // cannot reset like this
$startaddr = 0; # just avoid errors
}
print(STDERR $startaddr . "\n");
my $buffer=undef;
my $nread;
my $total=0;
while (($nread=sysread($inputfh, $buffer, $groupsize)) > 0) { # , $startaddr
#~ printf("%08X: nr: %d, buf '%s'\n",$startaddr,$nread,$buffer);
printf("%08X: ", $startaddr);
foreach my $tformat (@list) {
foreach my $tentry (unpack($tformat, $buffer)) {
printf("%s ", $tentry);
}
}
(my $newbuf = $buffer) =~ s/[^[:print:]]/./g; # make non-printable into '.'
printf(" '%s'", $newbuf);
print("\n");
$startaddr += $nread;
$total += $nread;
if ($total > $length) { last; }
}
close($inputfh);
Antwort3
So sed
können Sie die Ausgabe von in die Basis 2 dc
übersetzen :od
od -t d1z -w4 -v -N12 </dev/urandom |
sed -e '1i2o' -e 's/.*/[&]p/p;$d
s/>/]n [>/;s/[^ ]*/&]n [/;h;s/>.*//;
s/ -/ _/g;s/ [^] [][^ ]*/ ]n&n [ /g;G
s/\n[^>]*//' |
dc
Es ist jetzt etwas einfacher – und schneller – aber immer noch keine Schönheitskönigin. Es druckt auch die Dezimal- und Basis-2-Werte aller Bytes.
Wenn ich es ausführe, erhalte ich:
0000000 -43 125 -117 -39 >.}..<
0000000 -101011 1111101 -1110101 -100111 >.}..<
0000004 62 28 80 61 >>.P=<
0000004 111110 11100 1010000 111101 >>.P=<
0000010 6 14 120 -16 >..x.<
0000010 110 1110 1111000 -10000 >..x.<
0000014
Oder...
echo aBcD | od -t d1z -w4 -v | sed ... | dc
0000000 97 66 99 68 >aBcD<
0000000 1100001 1000010 1100011 1000100 >aBcD<
0000004 10 >.<
0000004 1010 >.<
0000005
Die Feldbreiten könnten ein wenig Arbeit vertragen, aber das liegt ganz bei Ihnen. Sie brauchen die -N12
Option nicht – ich habe sie nur verwendet, damit ich nicht an einer endlosen Pipe pseudozufälliger Daten ersticke. Und die -w4
gibt 4 Bytes pro Zeile an, aber Sie sollten in der Lage sein, jede beliebige Anzahl von Bytes zu verwenden. Außerdem 1i2o
sed
ist der Befehl eine dc
Anweisung bezüglich seiner Ausgabebasis – 2
für Binärzahlen –, aber jede Basis zwischen 2 und 16 sollte genauso gut funktionieren. Wenn Sie beispielsweise eine hexadezimale und eine Basis-2-Ausgabe sehen möchten, müssen Sie dieser ersten sed
Anweisung „16i“ hinzufügen und die Option od
von in ändern .-t d1z
t x1z
Weitere Optionen sind ...
printf macht Folgendes:
printf '%o\n%x\n' 128 128
200
80
...sogar...
printf '%o\n%x\n' "'a" "'a"
141
61
Binär ist nicht ganz so einfach, bc
kann aber alles, wenn Sie es obase=
entsprechend Ihren Spezifikationen einstellen:
printf 'obase=2;%d
obase=8;%d
obase=16;%d
obase=2;%d
' 64 128 "'A" "'a" |
bc
AUSGABE
1000000
200
41
1100001
dc
ist nicht ganz so gesprächig:
printf '%do%dn10P' 2 64 8 128 16 "'A" 2 "'a" |dc
AUSGABE
1000000
200
41
1100001
man dc bc
Für weitere Informationen klicken Sie hier .
Und für Dateiströme können Sie immer Folgendes verwenden od
:
for o in o d x ; do
echo aBcD |
od -A n -t ${o}1z -v -w4
done
AUSGABE
141 102 143 104 >aBcD<
012 >.<
97 66 99 68 >aBcD<
10 >.<
61 42 63 44 >aBcD<
0a >.<
Mit^das^eine, die ich anweise, od
keine Offsets zu drucken - was ich jetzt bezweifle -, dass ich Ausgaben vom -t
Typ o
, d
oder x
ein Byte nach dem anderen haben möchte und dass ich die ASCII-Darstellung z
jedes Bytes an das Ende der Zeile angehängt haben möchte, -v
erbosely(damit es mir nicht nur ein 0*
für ausgibt 0000
)bei -w4
Bytes pro Zeile.
Ohne -A n
wird Folgendes gedruckt:
0000000 141 102 143 104 >aBcD<
0000004 012 >.<
0000005
0000000 97 66 99 68 >aBcD<
0000004 10 >.<
0000005
0000000 61 42 63 44 >aBcD<
0000004 0a >.<
0000005
Und jede Kombination von dc
bc
od
ist natürlich in einem möglich |pipeline
.