bash 스크립트를 사용하여 바이너리 파일 내용을 읽는 방법은 무엇입니까?

bash 스크립트를 사용하여 바이너리 파일 내용을 읽는 방법은 무엇입니까?

문자를 읽은 다음 고정 길이 문자열(파일에서 null로 끝나지 않고 앞의 문자로 길이가 지정됨)을 읽고 싶습니다.

Bash 스크립트에서 이 작업을 어떻게 수행할 수 있나요? 후처리를 수행할 수 있도록 문자열 변수를 어떻게 정의합니까?

답변1

쉘 유틸리티를 계속 사용하려면 head여러 바이트를 추출하고 od바이트를 숫자로 변환하는 데 사용할 수 있습니다.

export LC_ALL=C    # make sure we aren't in a multibyte locale
n=$(head -c 1 | od -An -t u1)
string=$(head -c $n)

그러나 이작동하지 않습니다바이너리 데이터의 경우. 두 가지 질문이 있습니다:

  • 명령 대체 $(…)마지막 개행 문자명령 출력에서. 매우 간단한 해결 방법이 있습니다. 출력이 개행 문자가 아닌 문자로 끝나는지 확인한 다음 해당 문자를 제거하십시오.

    string=$(head -c $n; echo .); string=${string%.}
    
  • 대부분의 쉘과 마찬가지로 Bash는 처리에 능숙하지 않습니다.널 바이트. Bash 4.1부터 명령 대체 결과에서 널 바이트가 간단히 제거됩니다. Dash 0.5.5와 pdksh 5.2는 동일한 동작을 가지며 ATT ksh는 첫 번째 null 바이트에서 읽기를 중지합니다. 일반적으로 셸과 해당 유틸리티는 바이너리 파일을 처리하는 데 적합하지 않습니다. (널 바이트를 지원하도록 설계된 Zsh는 예외입니다.)

바이너리 데이터가 있는 경우 Perl 또는 Python과 같은 언어로 전환해야 합니다.

<input_file perl -e '
  read STDIN, $c, 1 or die $!;    # read length byte
  $n = read STDIN, $s, ord($c);   # read data
  die $! if !defined $n;
  die "Input file too short" if ($n != ord($c));
  # Process $s here
'
<input_file python -c '
  import sys
  n = ord(sys.stdin.read(1))      # read length byte
  s = sys.stdin.read(n)           # read data
  if len(s) < n: raise ValueError("input file too short")
  # Process s here
'

답변2

쉘에서 바이너리를 처리하고 싶다면 가장 좋은 옵션은 (유일한?) 다음을 사용하는 것입니다.16진수 덤프도구.

hexdump -v -e '/1 "%u\n"' binary.file | while read c; do
  echo $c
done

X바이트만 읽기:

head -cX binary.file | hexdump -v -e '/1 "%u\n"' | while read c; do
  echo $c
done

길이를 읽은 다음(길이로 0을 사용) 바이트 십진수 값으로 "문자열"을 읽습니다.

len=$(head -c1 binary.file | hexdump -v -e '/1 "%u\n"')
if [ $len -gt 0 ]; then
  tail -c+2 binary.file | head -c$len | hexdump -v -e '/1 "%u\n"' | while read c; do
    echo $c
  done
fi

답변3

exec 3<binary.file     # open the file for reading on file descriptor 3
IFS=                   #
read -N1 -u3 char      # read 1 character into variable "char"

# to obtain the ordinal value of the char "char"
num=$(printf %s "$char" | od -An -vtu1 | sed 's/^[[:space:]]*//')

read -N$num -u3 str    # read "num" chars
exec 3<&-              # close fd 3

답변4

이것은 바이너리 파일을 복사합니다.

 while read -n 1 byte ; do printf "%b" "$byte" ; done < "$input" > "$output"

관련 정보