명령줄에서 바이너리 문자열을 포함하는 hexdump와 유사한 형식을 달성하시겠습니까?

명령줄에서 바이너리 문자열을 포함하는 hexdump와 유사한 형식을 달성하시겠습니까?

hexdump특히 사용자 정의 형식을 정의할 수 있기 때문에 정말 마음에 듭니다 . 말하다:

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

따라서 한 줄에 4바이트를 선택하여 먼저 16진수로 쓴 다음 문자로 쓸 수 있습니다. 그러나 여기서 누락된 것은 "이진 문자열"(또는 "비트 문자열") 형식 지정 문자입니다. 예를 들어 -e '4/1 "%08b "'해당 명령줄 어딘가에 다음 과 같은 내용을 작성하고 싶습니다. 예:

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

물론 엔디안(1바이트 이상의 그룹을 형식화해야 하는 경우) 등을 지정해야 할 수도 있습니다. 그러나 어쨌든 매뉴얼에서 볼 수 있는 한 이러한 종류의 형식화는 존재하지 않습니다 hexdump. .

그래서 내 질문은 - 위와 같이 바이너리 문자열을 포함하는 형식화된 덤프를 얻을 수 있으면서도 가능한 최대 범위까지 프로그램의 사용자 정의 가능성을 보존할 수 있도록 Linux 명령줄에 어떤 대안이 있습니까 hexdump(바이트 그룹화 측면에서) 입니다. ) 해당 옵션을 사용할 때 -e?

답변1

적절한 덤프 옵션이 있는 덤프 프로그램이 실패하면 언제든지 와 붙여넣기를 사용하여 출력을 결합하여 무언가를 함께 엮을 수 hexdump있습니다 xdd. 예쁘지는 않지만 프로세스 대체를 지원하는 쉘을 사용하면 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-)

산출:

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

답변2

pack()/ unpack()함수 에 대한 형식 지정자를 활용하여 Perl을 사용하는 제안은 다음과 같습니다 . 테스트 호출은 다음과 같습니다:

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

사이에 문자열 마커를 삽입하는 것은 다소 어렵습니다. 그러나 좋은 점은 여전히 ​​내부에서 바이트를 "그룹화"할 수 있다는 것입니다. 예를 들어 두 바이트를 그룹화하고 부호 있는(짧은) 정수로 해석할 수 있습니다. 예:

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

여기 있습니다 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);

답변3

다음은 의 출력을 베이스 2로 변환하기 위해 sed동축으로 만드는 몇 가지 사항입니다 .dcod

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

지금은 좀 더 단순해졌지만(빠른 것은 말할 것도 없고) 여전히 뷰티 퀸은 아닙니다. 또한 모든 바이트의 10진수 및 밑수 2 값을 인쇄합니다.

내가 그것을 실행하면 나는 얻는다 :

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

또는...

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

필드 너비에는 약간의 작업이 필요할 수 있지만 모두 귀하의 것입니다. 이 옵션은 필요하지 않습니다 -N12. 저는 단지 그것을 사용했기 때문에 끝없는 의사 무작위 데이터 파이프에 질식하지 않았습니다. 그리고 -w4한 줄에 4바이트를 지정하지만 원하는 수의 바이트를 사용할 수 있어야 합니다. 또한 이 1i2o sed명령은 dc출력 기준( 2이진수)에 관한 명령이지만 2에서 16 사이의 모든 기준도 잘 작동합니다. 예를 들어 16진수 및 기본 2 출력을 보려면 첫 번째 sed명령문에 '16i'를 추가하고 od-t d1z옵션을 로 변경해야 합니다 t x1z.

다른 옵션은 다음과 같습니다...

printf는 다음을 수행합니다.

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

200

80

...심지어...

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

141

61

바이너리는 그다지 간단하지는 않지만 사양에 맞게 bc설정하면 모든 작업을 수행할 수 있습니다 .obase=

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

산출

1000000
200
41
1100001

dc그다지 말이 많지는 않습니다.

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

산출

1000000
200
41
1100001

자세한 내용을 보려면 하세요 man dc bc.

그리고 파일 스트림의 경우 언제든지 다음을 사용할 수 있습니다 od.

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

산출

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

와 함께^그^하나는 오프셋을 인쇄하지 말라고 말한 것 od입니다. 지금은 추측 중입니다. -type o, d또는 한 번에 한 바이트의 출력을 원하고 각 바이트의 ASCII 표현을 줄 끝에 추가 x하기를 원합니다 .z-v(그래서 그것은 단지 나를 인쇄하지 않습니다 0*for 0000)-w4한 줄당 바이트로 .

그것이 없으면 -A n다음과 같이 인쇄됩니다.

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

dc bc od물론 의 모든 조합은 |pipeline.

관련 정보