Как использовать сценарий удара для чтения содержания двоичного файла?

Сокет является просто логической конечной точкой для коммуникации. Они существуют на транспортном уровне. Можно отправить и получить вещи на сокете, можно связать и слушать сокет. Сокет характерен для протокола, машины и порта, и обращен как таковой в заголовке пакета.

У руководств Beej по Сетевому программированию и Межпроцессному взаимодействию и есть хорошая информация о том, как использовать сокеты и даже ответить на этот точный вопрос.

15
15.10.2016, 03:44
5 ответов

Если Вы хотите придерживаться утилит оболочки, можно использовать 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, как большинство оболочек, плох при контакте с пустыми байтами. С удара 4.1, пустые байты просто отбрасываются от результата замены команды. Тире 0.5.5 и pdksh 5.2 имеют то же поведение, и ATT ksh прекращает читать на уровне первого пустого байта. В целом оболочки и их утилиты не приспособлены к контакту с двоичными файлами. (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
'
19
27.01.2020, 19:49
  • 1
    +1 являются не всегда соответствующим –  forcefsck 08.04.2011, 01:40
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
2
27.01.2020, 19:49
  • 1
    read -N остановки на уровне пустых байтов, таким образом, это не подходящий способ работать с двоичными данными. В целом оболочки кроме zsh не могут справиться, аннулирует. сценарии оболочки –  Gilles 'SO- stop being evil' 08.04.2011, 01:30

ОБНОВЛЕНИЕ (с непредусмотрительностью):... этот вопрос/ответ (мой ответ) заставляет меня думать о собаке, которая продолжает преследовать автомобиль.. Однажды, наконец, он ловит до автомобиля.. Хорошо, он поймал его, но он действительно не может сделать многого с ним... Этот anser 'ловит' строки, но затем Вы не можете сделать многого с ними, если они встроили пустые байты... (так большой +1 к ответу Gilles.. другой язык может быть в порядке здесь.)

dd чтения любой и все данные... Это, конечно, не откажется от нуля как от "длины"..., но если у Вас будет \x00 где-нибудь в Ваших данных, то необходимо будет быть творческими, как Вы обрабатываете его; dd не имеет никакого propblems с ним, но Ваш сценарий оболочки будет иметь проблемы (но это зависит от того, что Вы хотите сделать с данными)... Следующие в основном выводы каждые "данные представляют в виде строки" в файл с делителем строки между каждой строкой...

btw: Вы говорите "символ", и я предполагаю, что Вы имеете в виду "байт"...
но слово "символ" стало неоднозначным в эти дни UNICODE, где только 7-разрядный набор символов ASCII использует единственный байт на символ... И даже в системе Unicode, количества байта варьируются в зависимости от метода кодирования символов, например, UTF-8, UTF-16, и т.д.

Вот простой сценарий для выделения различия между текстом "символ" и байтами.

STRING="௵"  
echo "CHAR count is: ${#STRING}"  
echo "BYTE count is: $(echo -n $STRING|wc -c)" 
# CHAR count is: 1
# BYTE count is: 3  # UTF-8 ecnoded (on my system)

Если Ваш символ длины 1 байт длиной и указывает на длину байта, то этот сценарий должен добиться цели, даже если данные содержат символы Unicode... dd только видит байты независимо от любой установки локали...

Этот сценарий использование dd считать двоичный файл и производит строки, разделенные "====" делителем... См. следующий сценарий для данных тестирования

#   
div="================================="; echo $div
((skip=0)) # read bytes at this offset
while ( true ) ; do
  # Get the "length" byte
  ((count=1)) # count of bytes to read
  dd if=binfile bs=1 skip=$skip count=$count of=datalen 2>/dev/null
  (( $(<datalen wc -c) != count )) && { echo "INFO: End-Of-File" ; break ; }
  strlen=$((0x$(<datalen xxd -ps)))  # xxd is shipped as part of the 'vim-common' package
  #
  # Get the string
  ((count=strlen)) # count of bytes to read
  ((skip+=1))      # read bytes from and including this offset
  dd if=binfile bs=1 skip=$skip count=$count of=dataline 2>/dev/null
  ddgetct=$(<dataline wc -c)
  (( ddgetct != count )) && { echo "ERROR: Line data length ($ddgetct) is not as expected ($count) at offset ($skip)." ; break ; }
  echo -e "\n$div" >>dataline # add a newline for TEST PURPOSES ONLY...
  cat dataline
  #
  ((skip=skip+count))  # read bytes from and including this offset
done
#   
echo

выход

Этот сценарий создает данные тестирования, которые включают 3-байтовый префикс на строку...
Префикс является закодированным символом Unicode единственного UTF-8...

# build test data
# ===============
  prefix="௵"   # prefix all non-zero length strings will this obvious 3-byte marker.
  prelen=$(echo -n $prefix|wc -c)
  printf \\0 > binfile  # force 1st string to be zero-length (to check zero-length logic) 
  ( lmax=3 # line max ... the last on is set to  255-length (to check  max-length logic)
    for ((i=1;i<=$lmax;i++)) ; do    # add prefixed random length lines 
      suflen=$(numrandom /0..$((255-prelen))/)  # random length string (min of 3 bytes)
      ((i==lmax)) && ((suflen=255-prelen))      # make last line full length (255) 
      strlen=$((prelen+suflen))
      printf \\$((($strlen/64)*100+$strlen%64/8*10+$strlen%8))"$prefix"
      for ((j=0;j<suflen;j++)) ; do
        byteval=$(numrandom /9,10,32..126/)  # output only printabls ASCII characters
        printf \\$((($byteval/64)*100+$byteval%64/8*10+$byteval%8))
      done
        # 'numrandom' is from package 'num-utils"
    done
  ) >>binfile
#
1
27.01.2020, 19:49
  • 1
    Ваш код выглядит более сложным, чем он, должен быть, особенно случайный генератор данных для тестирования. Можно получить случайные байты от /dev/urandom на большинстве нельдов. И случайные данные тестирования не являются лучшими данными тестирования, необходимо удостовериться, что обратились к трудным случаям такой как, здесь, нулевые символы и новая строка в граничных местах. –  Gilles 'SO- stop being evil' 09.04.2011, 19:01
  • 2
    Да спасибо. Я думал об использовании/dev/random, но полагал, что генерал данных тестирования не имел большого импорта, и я хотел к тест-драйву 'numrandom' (whicn, Вы упомянули в другом месте; 'цифровые-utils'some хорошие функции.). Я только что более тщательно изучил Ваш ответ и понял, что Вы делаете в значительной степени то же самое, за исключением того, что это более сжато :).. У меня не было уведомления, что Вы заявили ключевые пункты в 3 строках! Я сфокусировался на Ваших ссылках другого-языка.. Получение этого работать было хорошим опытом, и я теперь понимаю лучше Ваши ссылки на другие-языки! \x00 может быть стопором оболочки –  Peter.O 09.04.2011, 20:13

Этот просто скопируйте двоичный файл :

 while read -n 1 byte ; do printf "%b" "$byte" ; done < "$input" > "$output"
0
27.01.2020, 19:49

Если вы хотите работать с бинарными файлами в оболочке, лучший вариант только (? )предназначен для работы с инструментом hexdump .

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
6
27.01.2020, 19:49

Теги

Похожие вопросы