Đạt được định dạng giống như hexdump, bao gồm các chuỗi nhị phân, trên dòng lệnh?


7

Tôi thực sự thích hexdump, đặc biệt là vì bạn có thể xác định một định dạng tùy chỉnh; Nói:

$ 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          : .

Vì vậy, tôi có thể chọn có 4 byte trên mỗi dòng, được viết dưới dạng thập lục phân trước, sau đó là ký tự. Nhưng, cái tôi thiếu ở đây, là một ký tự định dạng "chuỗi nhị phân" (hoặc "chuỗi bit"); ví dụ: tôi muốn viết một cái gì đó giống như -e '4/1 "%08b "'ở đâu đó trong dòng lệnh đó và lấy, vd:

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

Tất nhiên, sau đó có lẽ người ta sẽ phải xác định tuổi thọ (nếu các nhóm nhiều hơn một byte phải được định dạng) v.v ... Nhưng trong mọi trường hợp, loại định dạng này không tồn tại, theo như tôi có thể thấy trong hexdumphướng dẫn .

Vì vậy, câu hỏi của tôi là - tôi có những lựa chọn thay thế nào trên dòng lệnh Linux, để tôi có thể có được một bãi chứa được định dạng bao gồm các chuỗi nhị phân như trên, và ở mức độ lớn nhất có thể duy trì khả năng tùy biến của hexdumpchương trình (về cách phân nhóm byte ) khi sử dụng -etùy chọn của nó ?


1
Tôi không biết làm thế nào Endianess đóng một vai trò ở đây?! Các nhóm nhiều hơn một byte vẫn chỉ là các nhóm byte. Nếu không, bạn nên chỉ định như những gì bạn muốn giải thích nó - số nguyên Xbit không dấu, đã ký ... thả nổi ... nhiều khả năng. Bạn đã kiểm tra xxdchưa?
0xC0000022L

Cảm ơn vì nhận xét, @ 0xC0000022L - vâng, tôi đã không hoàn toàn nghĩ về điều đó với sự chứng thực :). Tôi đã kiểm tra xxd, và có một -b: Switch to bits (binary digits) dump,, nhưng tôi không thể tìm thấy một ví dụ trong đó đầu ra đó sẽ được trộn với hex (như tôi đã đưa ra một ví dụ cho trong OP); nếu ai đó có thể đăng một ví dụ cho điều đó với xxd, đó sẽ là một câu trả lời chấp nhận được. Chúc mừng!
sdaau

@ 0xC0000022L - Chỉ cần kiểm tra xxdvới : echo -e '\x00\x01\x02\x03' | xxd -c 2 -b; sự hiện diện của công -btắc thay đổi mọi thứ thành chuỗi nhị phân và vì vậy rõ ràng nó không thể được "trộn" với thập lục phân.
sdaau

1
Bây giờ tôi hiểu ý của bạn. Tôi không chắc chắn làm thế nào để đạt được điều đó mà không có một kịch bản phức tạp hơn. Từ dòng lệnh tôi nghĩ rằng điều này sẽ trở nên khá phức tạp như là một "lớp lót".
0xC0000022L

Câu trả lời:


5

Không một chương trình bãi với các tùy chọn bãi phù hợp, bạn luôn có thể sỏi gì đó với nhau bằng cách sử dụng cả hai hexdumpxddvà sau đó tham gia đầu ra với dán. Nó không đẹp, nhưng sử dụng shell hỗ trợ quá trình thay thế ( bashsẽ làm):

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

Đầu ra:

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

2
Khéo léo. Cảm ơn. Mỗi ngày với một cái gì đó mới học là một ngày tốt. Đơn giản là không nghĩ đến paste.
0xC0000022L

Rất cám ơn câu trả lời, @Graeme - Tôi đã chỉnh sửa bài đăng của bạn và thêm đầu ra; hiện đang chấp nhận điều này - nhưng nếu bất cứ ai đăng một cách tiếp cận thuận tiện hơn, cuối cùng tôi có thể chuyển sự chấp nhận. Chúc mừng!
sdaau

3

Dưới đây là đề xuất của tôi bằng cách sử dụng Perl, sử dụng các chỉ định định dạng của nó cho hàm pack()/ unpack(); cuộc gọi thử nghiệm sẽ như sau:

$ 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  '.'

Thật khó để chèn các dấu chuỗi ở giữa - nhưng điều tuyệt vời là, bạn vẫn có thể "nhóm" các byte bên trong - ví dụ: bạn có thể nhóm hai byte và diễn giải chúng thành số nguyên (ngắn) đã ký, ví dụ:

$ 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  '.'

Đây là 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);

2

Đây là một số sedđể dỗ dcđể dịch odđầu ra của cơ sở 2:

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

Bây giờ thì đơn giản hơn một chút - điều này không được đề cập nhanh hơn - nhưng nó vẫn không phải là nữ hoàng sắc đẹp. Nó cũng in các giá trị thập phân và cơ sở 2 của tất cả các byte.

Khi tôi chạy nó, tôi nhận được:

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

Hoặc là...

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

Độ rộng trường có thể sử dụng một công việc nhỏ, nhưng đó là tất cả của bạn. Bạn không cần -N12tùy chọn - Tôi chỉ sử dụng nó để tôi không bị nghẹt thở trong một ống dữ liệu giả ngẫu nhiên vô tận. Và -w4chỉ định 4 byte trên mỗi dòng nhưng bạn sẽ có thể sử dụng bất kỳ số byte nào. Ngoài ra 1i2o sedlệnh là một dclệnh liên quan đến cơ sở đầu ra của nó - 2đối với nhị phân - nhưng bất kỳ cơ sở nào từ 2 đến 16 cũng sẽ hoạt động tốt. Nếu mong muốn nhìn thấy, ví dụ, thập lục phân và cơ sở 2 đầu ra bạn sẽ cần phải thêm '16I' để mà lần đầu tiên sedtuyên bố và biến đổi od's -t d1ztùy chọn để t x1z.

Các tùy chọn khác bao gồm ...

printf làm điều này:

printf '%o\n%x\n' 128 128

200

80

...cũng...

printf '%o\n%x\n' "'a" "'a"

141

61

Nhị phân không hoàn toàn đơn giản, nhưng bccó thể thực hiện tất cả nếu bạn đặt obase=thông số kỹ thuật của mình:

printf 'obase=2;%d
        obase=8;%d
        obase=16;%d
        obase=2;%d
        ' 64 128 "'A" "'a" |
bc

ĐẦU RA

1000000
200
41
1100001

dc không hoàn toàn như trò chuyện:

printf '%do%dn10P' 2 64 8 128 16 "'A" 2 "'a" |dc

ĐẦU RA

1000000
200
41
1100001

Làm man dc bcđể biết thêm.

Và một lần nữa, đối với các luồng tệp bạn luôn có thể sử dụng od:

for o in o d x ; do
    echo aBcD | 
    od -A n -t ${o}1z -v -w4
done

ĐẦU RA

 141 102 143 104  >aBcD<
 012              >.<
  97  66  99  68  >aBcD<
  10              >.<
  61  42  63  44  >aBcD<
  0a              >.<

Với ^ ^ rằng một tôi nói odkhông in offset - mà tôi là bây giờ thứ hai đoán - mà tôi muốn kết quả đầu ra của -type o, dhoặc xmột byte tại một thời điểm và tôi muốn đại diện ASCII zcủa mỗi byte nối vào cuối của dòng, -verbosely (vì vậy nó không chỉ cần in cho tôi một 0*cho 0000) tại -w4byte trên mỗi dòng.

Không có -A nnó in:

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

Và bất kỳ sự kết hợp dc bc odcủa tất nhiên là có thể trong một |pipeline.


Cảm ơn vì điều đó, @mikeerv - rất vui khi ghi nhớ điều này, nhưng vẫn cần thêm một số công việc để định dạng nó trên mỗi dòng (với địa chỉ offset vào tệp, v.v.) như với hexdump. Chúc mừng!
sdaau

1
@sddau - không nhiều. Tôi có thể chỉ ra rằng ... Trên thực tế - Tôi đã nói rõ ràng là odkhông nên bù đầu ra -A nđể tránh nhầm lẫn đầu ra. Lấy làm tiếc. Tôi sẽ hiển thị lại.
mikeerv

Thật là gọn gàng, @mikeerv - cảm ơn vì đã chỉnh sửa!
sdaau
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.