Шестнадцатеричные дампы - инструмент, который кажется атавизмом из эпохи перфокарт до тех пор, пока не приходится разбираться с повреждённым файлом, анализировать сетевой пакет или искать скрытые символы в подозрительном документе. Тогда быстро выясняется, что без возможности заглянуть в сырые байты ничего не получится. Стандартные текстовые редакторы здесь бессильны - они видят только то, что считают текстом. Утилиты уровня 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 прячет ещё целый набор полезных режимов. Каждый из них закрывает конкретную нишу, и знание о них превращает утилиту из инструмента разового применения в постоянного помощника. Набор неочевидных возможностей выглядит так.

  1. Режим обратного преобразования через флаг -r собирает бинарный файл обратно из шестнадцатеричного дампа, что позволяет редактировать содержимое файлов вручную
  2. Формат plain hexadecimal через -p выводит только байты без смещений и ASCII-колонки, удобно для вставки в программный код
  3. Режим -i генерирует включаемый заголовок на C с массивом байтов, незаменимый при встраивании бинарных ресурсов в программы
  4. Параметр -u переключает вывод букв a-f на заглавные A-F, что бывает важно для совместимости с определёнными форматами документации
  5. Флаг -g задаёт размер группы байтов между пробелами, стандартное значение 2 можно менять на 1, 4, 8 или 16 для разных представлений
  6. Комбинация -r -p позволяет обрабатывать дампы из документации, где нет смещений и дополнительного форматирования
  7. Поддержка чтения из стандартного входа делает 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 решают те же задачи несколькими командами в терминале. Эффективность, которая не видна новичкам, но моментально считывается опытными специалистами.