여러 줄의 문자열이 있는데 그 안에 있는 항목이 짧다고 가정해 보겠습니다. 16진수 덤프를 시도하면 다음과 같은 결과가 나타납니다.
echo "something
is
being
written
here" | hexdump -C
#00000000 73 6f 6d 65 74 68 69 6e 67 0a 69 73 0a 62 65 69 |something.is.bei|
#00000010 6e 67 0a 77 72 69 74 74 65 6e 0a 68 65 72 65 0a |ng.written.here.|
#00000020
대부분의 16진수 덤프 프로그램은 hexdump
단순히 2D 매트릭스로 작동하므로(각 행의 바이트/열 수를 정의할 수 있음) 이 경우 전체 출력은 2행 덤프로 압축됩니다.
평소처럼 계속 실행되는 프로그램이 있습니까? 새 줄( 0x0a
- 그러나 다른 문자나 그 시퀀스도 가능)을 만나지 않는 한 새 줄도 시작합니까? 이 경우 다음과 같은 출력을 원합니다.
00000000 73 6f 6d 65 74 68 69 6e 67 0a |something.|
0000000a 69 73 0a |is.|
0000000d 62 65 69 6e 67 0a |being.|
00000013 77 72 69 74 74 65 6e 0a |written.|
0000001b 68 65 72 65 0a |here.|
00000020
답변1
read
다음은 읽는 문자 수를 제한하는 기능을 활용하는 컴팩트 솔루션 중 하나입니다 .
c=0
while IFS= read -n16 -r line
do
len=${#line}
((len<16)) && { ((len++)) ; line+=$'\n' ;}
printf "%08x " $c
for ((i=0; i<len; i++))
do printf " %02x" "'${line:i:1}"
done
printf " %*s %s\n" $((50-3*len)) "" "'${line//[^[:print:]]/.}'"
((c+=len))
done
답변2
글쎄요 printf
...
hex_split()( unset c dump slice rad pend
_get(){ dd bs=1024 count=1; echo .; } 2>/dev/null
_buf() case $((${#dump}>0)):$((${#slice}>0)) in
(0:*) dump=$(_get); dump=${dump%.}
[ -n "$dump" ] || [ -n "$slice" ];;
(*:0) [ "${#dump}" -lt 16 ] &&
slice=${dump:-$slice} dump= && return
slice=${dump%"${dump#$q}"} dump=${dump#$q};;esac
_out(){ printf "%08x%02.0s" "$rad" "$((rad+=$#/2))"
printf "%02x %.0s" "$@"
printf "%-$(((16-($#/2))*3))s"
printf "%.0s%.1s" '' ' ' '' \| "$@" '' \| '' "$nl"
}; q=$(printf %016s|tr \ \?) ; IFS=\ nl='
' rad=0 c=0 split=${split:-$nl} slice="$*"; set --
while [ -n "$slice" ] || _buf || ! ${1:+"_out"} "$@" &&
c=${slice%"${slice#?}"} slice=${slice#?}
do set "$@" "'$c" "${c#[![:print:]]}."
case $#$c in (32*|*$split) _out "$@"; set --;;esac
done
)
표준 입력이나 인수 또는 둘 다를 제공할 수 있습니다. 그래서...
echo "something
is
being
written
here" | hex_split something else besides
...위의 내용이 인쇄됩니다...
00000000 73 6f 6d 65 74 68 69 6e 67 20 65 6c 73 65 20 62 |something else b|
00000010 65 73 69 64 65 73 00 73 6f 6d 65 74 68 69 6e 67 |esides.something|
00000020 0a |.|
00000021 69 73 0a |is.|
00000024 62 65 69 6e 67 0a |being.|
0000002a 77 72 69 74 74 65 6e 0a |written.|
00000032 68 65 72 65 0a |here.|
기본 구분 기호 문자를 변경합니다. 예를 들어...
split=${somechar} hex_split
답변3
difftool을 사용하여 두 파일을 비교하려면 이것이 필요하지만 여전히 인쇄할 수 없는 문자가 다른지 확인할 수 있습니다.
이 기능은 -n
옵션 을 추가합니다 hexdump
. 지정된 경우 -n
일반 16진수 덤프가 호출되지 않으면 출력은 개행에서 분할됩니다. @Janis의 답변과 비교할 때 이것은 hexdump를 완전히 다시 작성하는 것이 아니라 지정된 추가 인수(제공된 경우)를 사용하여 hexdump를 호출합니다. 그러나 hexdump는 Skip 옵션을 사용하여 head
입력을 한 줄씩 가져와 -s
오프셋을 유지합니다. 이 함수는 파이프될 때와 파일이 지정될 때 작동합니다. hexdump와 같이 지정된 여러 파일에서는 작동하지 않습니다.
나는 이것이 더 간단하고 더 짧은 대안 답변이 되기를 원했지만 이러한 모든 극단적인 입력 사례를 방지하면 실제로 더 길어집니다.
hexdump()
{
# introduces artifical line breaks in hexdump output at newline characters
# might be useful for comparing files linewise, but still be able to
# see the differences in non-printable characters utilizing hexdump
# first argument must be -n else normal hexdump will be used
local isTmpFile=0
if [ "$1" != '-n' ]; then command hexdump "$@"; else
if [ -p /dev/stdin ]; then
local file="$( mktemp )" args=( "${@:2}" )
isTmpFile=1
cat > "$file" # save pipe to temporary file
else
local file="${@: -1}" args=( "${@:2:$#-2}" )
fi
# sed doesn't seem to work on file descripts for some very weird reason,
# the linelength will always be zero, so check for that, too ...
local readfile="$( readlink -- "$file" )"
if [ -n "$readfile" ]; then
# e.g. readlink might return pipe:[123456]
if [ "${readfile::1}" != '/' ]; then
readfile="$( mktemp )"
isTmpFile=1
cat "$file" > "$readfile"
file="$readfile"
else
file="$readfile"
fi
fi
# we can't use read here else \x00 in the file gets ignored.
# Plus read will ignore the last line if it does not have a \n!
# Unfortunately using sed '<linenumbeer>p' prints an additional \n
# on the last line, if it wasn't there, but I guess still better than
# ignoring it ...
local linelength offset nBytes="$( cat "$file" | wc -c )" line=1
for (( offset = 0; offset < nBytes; )); do
linelength=$( sed -n "$line{p;q}" -- "$file" | wc -c )
(( ++line ))
head -c $(( offset + $linelength )) -- "$file" |
command hexdump -s $offset "${args[@]}" | sed '$d'
(( offset += $linelength ))
done
# Hexdump displays a last empty line by default showing the
# file size, bute we delete this line in the loop using sed
# Now insert this last empty line by letting hexdump skip all input
head -c $offset -- "$file" | command hexdump -s $offset "$args"
if [ "$isTmpFile" -eq 1 ]; then rm "$file"; fi
fi
}
다음을 사용하여 인쇄 해 볼 수 있습니다 echo -e "test\nbbb\nomg\n" | hexdump -n -C
.
00000000 74 65 73 74 0a |test.|
00000005 62 62 62 0a |bbb.|
00000009 6f 6d 67 0a |omg.|
0000000d 0a |.|
0000000e
보너스로 내 hexdiff
기능은 다음과 같습니다.
hexdiff()
{
# compares two files linewise in their hexadecimal representation
# create temporary files, because else the two 'hexdump -n' calls
# get executed multiple times alternatingly when using named pipes:
# colordiff <( hexdump -n -C "${@: -2:1}" ) <( hexdump -n -C "${@: -1:1}" )
local a="$( mktemp )" b="$( mktemp )"
hexdump -n -C "${@: -2:1}" | sed -r 's|^[0-9a-f]+[ \t]*||;' > "$a"
hexdump -n -C "${@: -1:1}" | sed -r 's|^[0-9a-f]+[ \t]*||;' > "$b"
colordiff "$a" "$b"
rm "$a" "$b"
}
예를 들어 테스트에 사용하면 다음과 같이 hexdiff <( printf "test\nbbb\x00 \nomg\nbar" ) <( printf "test\nbbb\nomg\nfoo" )
인쇄됩니다.
2c2
< 62 62 62 11 20 0a |bbb. .|
---
> 62 62 62 0a |bbb.|
4,5c4,5
< 62 61 72 |bar|
< 00000012
---
> 0c 6f 6f |.oo|
> 00000010
편집: 글쎄, 이 기능은 8MB와 같은 대용량 파일에는 적합하지 않으며 comparehex
또는 같은 도구는 dhex
줄 바꿈을 무시하므로 차이점이 잘 일치하지 않기 때문에 충분하지 않습니다. od
및 의 조합을 사용하는 것이 훨씬 빠릅니다 sed
.
hexlinedump()
{
local nChars=$1 file=$2
paste -d$'\n' -- <( od -w$( cat -- "$file" | wc -c ) -tx1 -v -An -- "$file" |
sed 's| 0a| 0a\n|g' | sed -r 's|(.{'"$(( 3*nChars ))"'})|\1\n|g' |
sed '/^ *$/d' ) <(
# need to delete empty lines, because 0a might be at the end of a char
# boundary, so that not only 0a, but also the character limit introduces
# a line break
sed -r 's|(.{'"$nChars"'})|\1\n|g' -- "$file" | sed -r 's|(.)| \1 |g' )
}
hexdiff()
{
colordiff <( hexlinedump 16 "${@: -2:1}" ) <( hexlinedump 16 "${@: -1:1}" )
}