Если вы хотите придерживаться утилит оболочки, вы можете использовать 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 прекращает чтение с первого нулевого байта. В общем, оболочки и их утилиты не предназначены для работы с двоичными файлами. (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
'
Жиль "ТАК - перестань быть злым"
источник
источник
read -N
останавливается на нулевых байтах, так что это не подходящий способ работы с двоичными данными. В общем случае оболочки, отличные от zsh, не справляются с нулями.Если вы хотите иметь дело с двоичным файлом в оболочке, лучший вариант (только?) - это работать с инструментом hexdump .
Только для чтения X байтов:
Считайте длину (и работайте с 0 как длина) и затем "строка" как десятичное значение байта:
источник
ОБНОВЛЕНИЕ (задним числом): ... Этот вопрос / ответ (мой ответ) заставляет меня думать о собаке, которая продолжает преследовать машину .. Однажды, наконец, он догоняет машину .. Хорошо, он поймал ее, но он действительно ничего не может с этим поделать ... Этот ансер "ловит" строки, но тогда вы не сможете с ними многое сделать, если они имеют встроенные нулевые байты ... (так что большой ответ +1 для Жиля .. другой язык может быть в порядке здесь.)
dd
читает любые и все данные ... Это, конечно, не будет показывать ноль как "длину" ... но если у вас есть \ x00 где-нибудь в ваших данных, вам нужно проявить изобретательность в том, как вы справляетесь с этим;dd
не имеет никаких проблем с этим, но у вашего сценария оболочки будут проблемы (но это зависит от того, что вы хотите сделать с данными) ... Следующее в основном выводит каждую «строку данных» в файл с разделителем строк между каждой строкой ...Кстати: вы говорите «символ», и я предполагаю, что вы имеете в виду «байт» ...
но слово «символ» стало двусмысленным в наши дни UNICODE, где только 7-битный набор символов ASCII использует один байт на символ ... И даже в системе Unicode количество байтов варьируется в зависимости от метода кодирования символов , например. UTF-8, UTF-16 и др.
Вот простой скрипт, чтобы выделить разницу между текстовым «символом» и байтами.
Если длина вашего символа составляет 1 байт и указывает длину в байтах , то этот сценарий должен справиться с задачей, даже если данные содержат символы Юникода ...
dd
видит только байты независимо от настроек локали ...Этот скрипт использует
dd
для чтения двоичного файла и выводит строки, разделенные разделителем "====" ... Смотрите следующий скрипт для тестовых данныхвыход
Этот скрипт создает тестовые данные, которые включают в себя 3-байтовый префикс на строку ...
Префикс представляет собой один кодированный в кодировке UTF-8 символ Unicode ...
источник
/dev/urandom
большинства юнитов. А данные случайных тестов не самые лучшие тестовые данные, вы должны убедиться, что решаете сложные случаи, такие как, здесь, нулевые символы и символ новой строки в граничных местах.Это просто скопировать двоичный файл:
источник