Шестнадцатеричные дампы - инструмент, который кажется атавизмом из эпохи перфокарт до тех пор, пока не приходится разбираться с повреждённым файлом, анализировать сетевой пакет или искать скрытые символы в подозрительном документе. Тогда быстро выясняется, что без возможности заглянуть в сырые байты ничего не получится. Стандартные текстовые редакторы здесь бессильны - они видят только то, что считают текстом. Утилиты уровня xxd работают глубже и показывают истинное содержимое файла так, как его видит операционная система.
Что именно делает команда xxd и почему она остаётся незаменимой для администраторов и разработчиков
По своей сути xxd - это конвертер между бинарным представлением данных и их читаемой формой. В одну сторону она берёт любой файл и показывает его содержимое в виде аккуратных строк из шестнадцатеричных чисел. В обратную сторону работает тоже - принимает текстовый дамп и собирает из него исходный бинарник. Такой двусторонний режим делает утилиту популярным инструментом для патчинга программ, передачи бинарных данных через каналы, которые умеют работать только с ASCII, и массы других задач на стыке низкоуровневой работы с файлами.
Синтаксис выглядит обманчиво просто и не намекает на всё богатство возможностей, скрытых внутри.
xxd [OPTIONS] [file]
Официальное описание из man-страницы раскрывает суть инструмента точнее.
xxd creates a hex dump of a given file or standard input. It can also convert a hex dump back to its original binary form. Like
uuencode(1) and uudecode(1) it allows the transmission of binary data in a `mail-safe' ASCII representation, but has the advantage
of decoding to standard output. Moreover, it can be used to perform binary file patching.
Сравнение с uuencode и uudecode здесь не случайное. Раньше двоичные файлы через электронную почту приходилось пропускать именно через такие конвертеры, поскольку протокол SMTP исторически работал только с семибитным текстом. Xxd унаследовал эту идею и при этом добавил удобство - вывод идёт прямо в стандартный поток, что облегчает встраивание команды в любые скрипты и конвейеры обработки.
Все примеры ниже проверены на Ubuntu 22.04 LTS, но утилита входит в стандартный набор vim-common практически во всех современных дистрибутивах. Поэтому работать приведённые команды будут и на CentOS, и на Debian, и на Arch, и даже в macOS через Homebrew.
Базовое использование xxd для получения шестнадцатеричного представления обычного текстового файла
Лучше всего принцип работы xxd понимается на конкретном примере. Предположим, существует текстовый файл с таким содержимым.
No.|Country|Yes/No
01|India|Y
02|US|Y
03|Australia|Y
04|China|N
05|Russia|Y
06|Japan|Y
07|Singapore|Y
08|South Korea|N
09|Finland|Y
10|Ireland|Y
На первый взгляд - обычная табличка с разделителем в виде вертикальной черты. Но что именно хранится в файле на уровне байтов, не видно. Запускаем xxd с единственным аргументом.
xxd test.txt
Результат выглядит так.
00000000: 4e6f 2e7c 436f 756e 7472 797c 5965 732f No.|Country|Yes/
00000010: 4e6f 0a30 317c 496e 6469 617c 590a 3032 No.01|India|Y.02
00000020: 7c55 537c 590a 3033 7c41 7573 7472 616c |US|Y.03|Austral
00000030: 6961 7c59 0a0a 3034 7c43 6869 6e61 7c4e ia|Y..04|China|N
00000040: 0a30 357c 5275 7373 6961 7c59 0a30 367c .05|Russia|Y.06|
00000050: 4a61 7061 6e7c 590a 0a30 377c 5369 6e67 Japan|Y..07|Sing
00000060: 7061 6f72 657c 590a 3038 7c53 6f75 7468 paore|Y.08|South
00000070: 204b 6f72 6561 7c4e 0a30 397c 4669 6e61 Korea|N.09|Fina
00000080: 6c61 6e64 7c59 0a31 307c 4972 656c 616e land|Y.10|Irelan
00000090: 647c 590a d|Y.
Структура вывода заслуживает отдельного разбора, поскольку именно она делает формат xxd таким удобным для глазного анализа. Каждая строка состоит из трёх смысловых блоков. Слева - смещение текущей позиции от начала файла, записанное в шестнадцатеричной системе. В середине - сами данные, сгруппированные по два байта и разделённые пробелами. Справа - ASCII-представление тех же байтов, где непечатаемые символы заменяются точками.
Именно такой трёхчастный формат позволяет моментально видеть и числовые значения, и их человеческий эквивалент одновременно. Код 0a, видимый между строками таблицы - это стандартный символ перевода строки в Unix, он же LF или line feed. Две подряд точки на позиции 0a 0a обозначают пустые строки, которые визуально разделяют блоки в исходном файле. Символы с кодами 20 - обычные пробелы, заметные в названии South Korea.
Пропуск заданного количества байтов с помощью параметра -s для работы с большими файлами
При анализе больших файлов редко требуется видеть всё содержимое целиком. Обычно интерес представляет конкретный фрагмент - заголовок, середина, конкретная структура данных в известной позиции. Параметр -s позволяет пропустить начало файла и сразу перейти к нужной точке.
xxd -s 0x30 test.txt
Значение 0x30 здесь - это шестнадцатеричное число, эквивалентное десятичному 48. То есть команда просит xxd пропустить первые 48 байтов файла и начать вывод с этой позиции. В контексте тестового файла такой отступ примерно соответствует третьей строке таблицы.
00000030: 6961 7c59 0a0a 3034 7c43 6869 6e61 7c4e ia|Y..04|China|N
00000040: 0a30 357c 5275 7373 6961 7c59 0a30 367c .05|Russia|Y.06|
00000050: 4a61 7061 6e7c 590a 0a30 377c 5369 6e67 Japan|Y..07|Sing
00000060: 7061 6f72 657c 590a 3038 7c53 6f75 7468 paore|Y.08|South
00000070: 204b 6f72 6561 7c4e 0a30 397c 4669 6e61 Korea|N.09|Fina
00000080: 6c61 6e64 7c59 0a31 307c 4972 656c 616e land|Y.10|Irelan
00000090: 647c 590a d|Y.
Смещения слева сохраняют абсолютные значения, а не начинают отсчёт заново. Такое поведение правильное - при анализе файла важно знать реальную позицию байтов, а не их относительное положение в выводе. Значение после -s можно задавать и в десятичном виде без префикса 0x, что удобно при работе с размерами, выраженными в байтах без преобразования.
Отрицательные значения тоже работают. Параметр -s -0x30 отступит 48 байтов от конца файла, что полезно для анализа финальных блоков, контрольных сумм или метаданных в конце структуры.
Ограничение длины вывода через параметр -l и анализ только нужных фрагментов
Противоположная задача - посмотреть не весь файл, а только его начало или конкретный кусок заданной длины. Здесь в дело вступает параметр -l, который ограничивает количество обрабатываемых байтов.
xxd -l 0x30 test.txt
Команда просит показать первые 48 байтов файла и на этом остановиться. Результат соответствует запросу.
00000000: 4e6f 2e7c 436f 756e 7472 797c 5965 732f No.|Country|Yes/
00000010: 4e6f 0a30 317c 496e 6469 617c 590a 3032 No.01|India|Y.02
00000020: 7c55 537c 590a 3033 7c41 7573 7472 616c |US|Y.03|Austral
Три строки по 16 байтов каждая - ровно 48 байтов, как и было запрошено. Комбинация флагов -s и -l открывает широкие возможности для точечного анализа. Указав начальную позицию и длину, можно вытащить любой произвольный диапазон из большого файла. Такой подход особенно полезен при работе с форматами, где структуры имеют фиксированные смещения - заголовками исполняемых файлов, таблицами разделов на диске, метаданными в мультимедийных контейнерах.
Практический сценарий из жизни выглядит так. Администратор подозревает, что в лог-файле размером в несколько гигабайт есть повреждённые записи. Прочитать его целиком глазами невозможно. Но зная, что подозрительная область находится примерно в середине, легко выделить нужный кусок одной командой и увидеть его содержимое без нагрузки на память и терминал.
Изменение ширины вывода через параметр -c для удобства чтения и специальных задач
Стандартные 16 байтов на строку - оптимум для большинства ситуаций, но не для всех. Иногда хочется видеть данные в более узком формате, особенно если в байтах чётко прослеживается какая-то повторяющаяся структура с другим периодом. Параметр -c меняет количество столбцов в выводе.
xxd -c 5 test.txt
Результат заметно отличается от стандартного.
00000000: 4e6f 2e7c 43 No.|C
00000005: 6f75 6e74 72 ountr
0000000a: 797c 5965 73 y|Yes
0000000f: 2f4e 6f0a 30 /No.0
00000014: 317c 496e 64 1|Ind
00000019: 6961 7c59 0a ia|Y.
0000001e: 3032 7c55 53 02|US
00000023: 7c59 0a30 33 |Y.03
00000028: 7c41 7573 74 |Aust
0000002d: 7261 6c69 61 ralia
00000032: 7c59 0a0a 30 |Y..0
00000037: 347c 4368 69 4|Chi
0000003c: 6e61 7c4e 0a na|N.
00000041: 3035 7c52 75 05|Ru
00000046: 7373 6961 7c ssia|
0000004b: 590a 3036 7c Y.06|
00000050: 4a61 7061 6e Japan
00000055: 7c59 0a0a 30 |Y..0
0000005a: 377c 5369 6e 7|Sin
0000005f: 6770 616f 72 gpaor
00000064: 657c 590a 30 e|Y.0
00000069: 387c 536f 75 8|Sou
0000006e: 7468 204b 6f th Ko
00000073: 7265 617c 4e rea|N
00000078: 0a30 397c 46 .09|F
0000007d: 696e 616c 61 inala
00000082: 6e64 7c59 0a nd|Y.
00000087: 3130 7c49 72 10|Ir
0000008c: 656c 616e 64 eland
00000091: 7c59 0a |Y.
Каждая строка теперь содержит ровно пять байтов, а количество строк выросло пропорционально. Смещения тоже шагают на пять позиций. Для данных с пятибайтной структурой такой формат давал бы идеально выровненные колонки, и любые нарушения структуры сразу бросались бы в глаза.
Выбор ширины колонки имеет и практическое обоснование, связанное с размером терминала. На узких экранах стандартные 16 байтов могут не помещаться в строку и переноситься, что разрушает читаемость. Ширина 8 или 12 в таких случаях даёт более опрятный вид. Максимум составляет 256 байтов на строку, чего точно хватит для любых задач.
Отдельная хитрость - комбинация -c с большими значениями для генерации сводных представлений. При -c 32 удобно просматривать длинные структуры целиком в одну строку, а при -c 4 каждая строка превращается в удобное представление 32-битного слова.
Переключение в двоичный режим вывода через флаг -b для анализа битовых структур
Шестнадцатеричный формат компактен и удобен, но иногда нужно видеть именно отдельные биты. Работа с флагами процессоров, анализ битовых полей в структурах, отладка сетевых протоколов - вот типичные задачи, где битовое представление даёт больше информации, чем байтовое. Флаг -b переключает xxd в такой режим.
Официальное описание из man-страницы поясняет особенности режима.
-b | -bits
Switch to bits (binary digits) dump, rather than hexdump. This option writes octets as eight digits "1"s and "0"s instead
of a normal hexadecimal dump. Each line is preceded by a line number in hexadecimal and followed by an ascii (or ebcdic)
representation. The command line switches -r, -p, -i do not work with this mode.
Ключевое ограничение здесь - несовместимость с рядом других флагов. Обратное преобразование через -r, форматы plain и include через -p и -i в битовом режиме не работают. Это логично, поскольку битовое представление занимает в восемь раз больше места, чем шестнадцатеричное, и его конвертация обратно потребовала бы отдельной логики. Сама команда проста.
xxd -b test.txt
Вывод получается существенно шире обычного - каждый байт превращается в восемь символов из нулей и единиц. Для коротких файлов такое представление нагляднее, для длинных - становится утомительным. Поэтому битовый режим часто комбинируют с параметрами -s и -l, чтобы ограничить вывод конкретным фрагментом.
Практическое применение битового режима выходит далеко за рамки учебных примеров. Разработчики встроенных систем используют его для отладки работы с регистрами периферии. Специалисты по сетям изучают заголовки пакетов, где отдельные биты кодируют флаги TCP или параметры IP. Реверс-инженеры анализируют обфусцированные данные, где важна последовательность битов независимо от байтовой границы.
Дополнительные возможности утилиты которые редко используются но резко выручают в нестандартных ситуациях
За рамками базовых примеров xxd прячет ещё целый набор полезных режимов. Каждый из них закрывает конкретную нишу, и знание о них превращает утилиту из инструмента разового применения в постоянного помощника. Набор неочевидных возможностей выглядит так.
- Режим обратного преобразования через флаг -r собирает бинарный файл обратно из шестнадцатеричного дампа, что позволяет редактировать содержимое файлов вручную
- Формат plain hexadecimal через -p выводит только байты без смещений и ASCII-колонки, удобно для вставки в программный код
- Режим -i генерирует включаемый заголовок на C с массивом байтов, незаменимый при встраивании бинарных ресурсов в программы
- Параметр -u переключает вывод букв a-f на заглавные A-F, что бывает важно для совместимости с определёнными форматами документации
- Флаг -g задаёт размер группы байтов между пробелами, стандартное значение 2 можно менять на 1, 4, 8 или 16 для разных представлений
- Комбинация -r -p позволяет обрабатывать дампы из документации, где нет смещений и дополнительного форматирования
- Поддержка чтения из стандартного входа делает xxd удобным звеном в конвейерах обработки, где данные приходят от других команд
Режим patching через обратное преобразование заслуживает отдельного упоминания. Схема выглядит так. Берётся исходный файл, прогоняется через xxd в текстовый дамп, дамп редактируется в любом текстовом редакторе, затем через xxd -r превращается обратно в бинарник. Такой подход давно используется для локализации программ без исходников, исправления жёстко зашитых строк или банальной подмены значений в файлах конфигурации закрытых приложений.
Генерация C-заголовков через -i превращает любой файл в готовый к компиляции массив. Типичная команда выглядит так - xxd -i image.png > image.h. В результате получается корректный код на языке C с массивом unsigned char и переменной для размера. Разработчики игр давно используют такой трюк для вшивания текстур, шрифтов и звуков прямо в исполняемый файл, чтобы программа оставалась единым бинарником без внешних ресурсов.
Практические сценарии применения xxd в реальной работе системного администратора и программиста
Теория и учебные примеры - одно, реальные задачи на практике - совсем другое. Именно в повседневной работе xxd показывает свою истинную ценность. Первый классический сценарий - проверка кодировок. Когда текстовый файл выглядит корректно в одном редакторе и крякозяблами в другом, причина почти всегда кроется в несовпадении кодировок. Быстрый взгляд через xxd сразу покажет, есть ли в начале файла BOM-маркер UTF-8, или там чистый ASCII, или речь о чём-то другом.
Второй сценарий - поиск скрытых символов. Нулевые байты, непечатаемые управляющие последовательности, символы из других письменностей, выглядящие как латиница - всё это отлично видно в ASCII-колонке xxd. Классическая ситуация, когда скрипт не работает по непонятной причине, а внутри строки пряталась невидимая запятая из другой кодировки, решается одной командой.
Третий сценарий - анализ испорченных файлов. Если архив повреждён или документ не открывается, первое правило - посмотреть в сигнатуру файла. Каждый формат имеет характерное начало из нескольких байтов, так называемый magic number. Zip начинается с PK, PNG с последовательности 89 50 4e 47, PDF с %PDF. Если эти байты на месте - формат распознан правильно, проблема глубже. Если их нет или они искажены - файл повреждён, нужно искать резервную копию.
Четвёртый сценарий - сравнение бинарников. Две версии одной и той же программы, подозрение на подмену файла, необходимость понять, что именно изменилось между двумя релизами. Дампы обоих файлов через xxd и последующее сравнение утилитой diff выдают точный список различий с привязкой к смещениям.
В итоге xxd - не просто вспомогательная утилита, а полноценный швейцарский нож для работы с бинарными данными. Освоение её глубоких возможностей окупается многократно. Пока одни тратят часы на ручной анализ сырых байтов через бесконечный скроллинг hex-редакторов, знакомые с xxd решают те же задачи несколькими командами в терминале. Эффективность, которая не видна новичкам, но моментально считывается опытными специалистами.