Разбить двоичные данные на строки в однострочной строке bash?

#bash

Вопрос:

Есть ли какой-нибудь однострочный bash, который позволил бы мне разбивать двоичные данные, поступающие из канала, на строки?

В качестве примера:

 $ echo -ne 'x31x00x32rnx33x34x35x00rn' | xxd 
 

Это приводит к:

 00000000: 3100 320d 0a33 3435 000d 0a              1.2..345...
 

И я хотел бы иметь:

 00000000: 3100 320d 0a                             1.2..
00000005: 3334 3500 0d0a                           345...
 

В случае, если двоичные данные содержат новую строку, я не возражаю, что сообщение будет разделено на две или более строк (в моем случае это произойдет редко).

У меня много устройств в этой области, и необходимость отправлять сценарии или программы для этого была бы громоздкой. Сообщения имеют переменный размер, поэтому xxd -c будут работать только для некоторых сообщений.

Я попытался передать сообщения по конвейеру read , что правильно разбивает сообщение на строки. Но по какой-то причине (вероятно, сам баш) нули удаляются из моих сообщений:

 echo -ne 'x31x00x32rnx33x34x35x00rn' | while read; do echo "$REPLY" | xxd; done

00000000: 3132 0d0a                                12..
00000000: 3334 350d 0a                             345..
 

(ПРАВКА: смещения байтов могут быть равны нулю, это не проблема. Проблема в этом последнем примере заключается в отсутствующих нулях в части данных.)

Может быть, есть способ сохранить нули при использовании read ? Или, может быть, мой вариант использования слишком волосатый?

Комментарии:

1. Вам нужно смещение байта слева, как в вашем первом примере? В read примере xxd работает только на отдельных строках, поэтому вы теряете смещения слева.

2. Я придерживаюсь менталитета «если этого не существует, то создайте его сами». Хотя я не уверен, что bash может сделать то, о чем вы просите изначально (по крайней мере, без какого-либо фанкового синтаксиса), я уверен, что вы могли бы создать простое решение на выбранном вами языке и вызвать свое решение из bash. Мне на ум приходит Python (предпочтение). Вы не возражаете против решения на Python, которое можно вызвать из вашей оболочки?

3. Вы можете довольно близко сойтись с: printf 'x31x00x32rnx33x34x35x00rn' | perl -ne 'printf "d: ", $c; print unpack("H* ", "$_") . "n"; $c = length'

4. @JardelLucca возможно, лучшее в bash или любой командной оболочке то, что она предназначена для взаимодействия с другими программами, включая программы, которые вы написали сами. Просто передайте данные в пользовательскую программу, предназначенную для выполнения того, что вы, что все равно будет выглядеть очень элегантно в bash. Создание гораздо более крупной команды (которая все еще технически вызывает другие программы), безусловно, должно сработать, но это будет менее элегантно. Когда я говорю здесь «элегантный», я имею в виду простоту использования и удобочитаемость.

5. @JardelLucca на самом деле, ваше второе решение echo -ne 'x31x00x32rnx33x34x35x00rn' | while read; do echo "$REPLY" | xxd; done работает для меня. Я использую zsh. Возможно, рассмотрим новую оболочку 🙂

Ответ №1:

Вы можете получить 90% того, что хотите, с помощью:

 $ printf 'x31x00x32rnx33x34x35x00rn' | 
    perl -nE 'printf "d: ", $c;  say unpack("H*", "$_") ; $c  = length'
00000000: 3100320d0a
00000005: 333435000d0a
 

Комментарии:

1. Вот еще одна причина перестать откладывать и сразу начать изучать perl : )