Erreichen eines hexdumpartigen Formats, das Binärzeichenfolgen enthält, in der Befehlszeile?

7

Ich mag es wirklich hexdump, besonders weil Sie ein benutzerdefiniertes Format definieren können; sagen:

$ 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"). zB möchte ich so etwas wie -e '4/1 "%08b "'irgendwo in diese Kommandozeile schreiben und erhalten, zB:

0: 00 01 02 03 : 00000000 00000001 00000010 00000011 : ....
4: 0A          : 00001010 : .

Natürlich müsste man dann wahrscheinlich die Endianness angeben (wenn Gruppen mit mehr als einem Byte formatiert werden sollen) usw. Aber diese Art der Formatierung gibt es auf keinen Fall, soweit ich im hexdumpHandbuch sehen kann .

Meine Frage ist also: Welche Alternativen habe ich in einer Linux-Befehlszeile, damit ich einen formatierten Speicherauszug erhalten kann, der die oben genannten Binärzeichenfolgen enthält und dennoch die Anpassbarkeit des hexdumpProgramms (in Bezug auf die Byte-Gruppierung) so weit wie möglich beibehält ) bei Verwendung seiner -eOption?

sdaau
quelle
1
Ich weiß nicht, wie Endianess hier eine Rolle spielt?! Gruppen von mehr als einem Byte sind immer noch nur Gruppen von Bytes. Andernfalls sollten Sie angeben, was Sie interpretieren möchten - vorzeichenlose Xbit-Ganzzahl, vorzeichenbehaftete ... float ... viele Möglichkeiten. Hast du ausgecheckt xxd?
0xC0000022L
Vielen Dank für den Kommentar, @ 0xC0000022L - ja, ich habe das mit der Endianness nicht vollständig durchdacht :). Ich habe ausgecheckt xxd, und es gibt ein -b: Switch to bits (binary digits) dump,, aber ich kann kein Beispiel finden, in dem diese Ausgabe mit hex gemischt wird (wie ich im OP ein Beispiel angegeben habe); Wenn jemand ein Beispiel dafür mit posten kann xxd, wäre das eine akzeptable Antwort. Prost!
Sdaau
@ 0xC0000022L - Nur überprüft xxdmit : echo -e '\x00\x01\x02\x03' | xxd -c 2 -b; Das Vorhandensein des -bSchalters ändert alles in eine binäre Zeichenfolge und kann daher anscheinend nicht mit hexadezimal "gemischt" werden.
Sdaau
1
Jetzt verstehe ich was du meinst. Ich bin mir nicht sicher, wie ich das ohne ein komplexeres Skript erreichen kann. Von der Kommandozeile aus würde ich denken, dass dies als "Einzeiler" ziemlich komplex wird.
0xC0000022L

Antworten:

5

In Ermangelung einer Dump - Programm mit geeigneten Dump - Optionen können Sie immer Cobble etwas gemeinsam durch beide mit hexdumpund xddund dann die Ausgabe mit Paste verbinden. Es ist nicht schön, aber es wird eine Shell verwendet, die die Prozessersetzung unterstützt (reicht aus bash):

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                             .
Graeme
quelle
2
Ordentlich. Vielen Dank. Jeder Tag mit etwas Neuem ist ein guter Tag. Ich hatte einfach nicht daran gedacht paste.
0xC0000022L
Vielen Dank für die Antwort, @Graeme - Ich habe Ihren Beitrag bearbeitet und die Ausgabe hinzugefügt. Ich akzeptiere dies vorerst - aber wenn jemand einen bequemeren Ansatz veröffentlicht, kann ich die Annahme möglicherweise verschieben. Prost!
Sdaau
3

Hier ist mein Vorschlag, Perl zu verwenden und seine Formatierungsspezifizierer für die Funktion pack()/ zu unpack()verwenden. Der Testanruf wäre wie folgt:

$ 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 etwas schwierig, String-Marker dazwischen einzufügen - aber das Schöne ist, dass Sie immer noch Bytes darin "gruppieren" können - z. B. können Sie zwei Bytes gruppieren und sie als vorzeichenbehaftete (kurze) Ganzzahl 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);
sdaau
quelle
2

Hier sind einige sedzu überreden dc, oddie Ausgabe auf Basis 2 zu übersetzen :

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 - was nicht schneller zu erwähnen ist - aber es ist immer noch keine Schönheitskönigin. Es werden auch die Dezimal- und Basis-2-Werte aller Bytes gedruckt.

Wenn ich es starte, bekomme 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 gebrauchen, aber es liegt ganz bei Ihnen. Sie brauchen die -N12Option nicht - ich habe sie nur verwendet, damit ich nicht an einer endlosen Pipe pseudozufälliger Daten erstickt bin. Und das -w4gibt 4 Bytes pro Zeile an, aber Sie sollten in der Lage sein, eine beliebige Anzahl von Bytes zu verwenden. Der 1i2o sedBefehl ist auch eine dcAnweisung bezüglich seiner Ausgangsbasis - 2für Binär - aber jede Basis zwischen 2 und 16 sollte genauso gut funktionieren. Wenn Wunsch zu sehen, zum Beispiel, hexadezimal und Basis 2 Ausgang müssen Sie hinzufügen ‚16i‘ zu dieser ersten sedErklärung und Veränderung od‚s - -t d1zOption t x1z.

Weitere Optionen sind ...

printf macht das:

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, bckann aber alles, wenn Sie es obase=Ihren Spezifikationen anpassen:

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

Haben man dc bcfür weitere Informationen.

Und für Dateistreams 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 ^ ^ dass man sagen , dass ich odnicht Offsets drucken - was ich jetzt zweite Mutmaßung - dass ich Ausgänge will -typ o, doder xein Byte zu einem Zeitpunkt , und dass ich die ASCII - Darstellung will zjede am Ende angefügt Byte die Zeile -verbosely (so druckt es mich nicht nur ein 0*für 0000) bei -w4Bytes pro Zeile.

Ohne -A nes druckt:

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 odist natürlich in a möglich |pipeline.

mikeserv
quelle
Vielen Dank dafür, @mikeserv - schön, dies im Hinterkopf zu behalten, aber es erfordert noch einige zusätzliche Arbeit, um es pro Zeile (mit versetzter Adresse in die Datei usw.) wie bei zu formatieren hexdump. Prost!
Sdaau
1
@sddau - nicht viel. Ich kann das zeigen ... Tatsächlich habe ich ausdrücklich gesagt od, dass Offsets nicht mit ausgegeben werden sollen -A n, um eine Verwechslung der Ausgabe zu vermeiden. Es tut uns leid. Ich werde es wieder zeigen.
Mikesserv
Das war ordentlich, @mikeserv - danke für die Bearbeitung!
Sdaau