Как написать бинарный файл с помощью Bash?

Моя проблема в том, что мне нужно создать файл с такими точными байтами: 48, 00, 49, 00.

Я не могу использовать C, perl и другие языки сценариев (целью является встроенное устройство). Я попробовал это с помощью awk, и на рабочем столе это работает:

# awk  'BEGIN{ printf "%c%c%c%c", 48, 00, 49, 00 }' | hexdump
0000000 0030 0031                              
0000004

Однако на целевой платформе работает busybox v1.13.2, и этот код там не работает. Версия awk не выводит ascii "0" (все остальные значения в порядке).

Каковы ваши рекомендации?


person elcuco    schedule 07.04.2011    source источник


Ответы (6)


вы можете использовать следующую команду:

echo -n -e \\x48\\x00\\x49\\x00 > myfile
person yohann.martineau    schedule 05.10.2011
comment
Спасибо. Та же проблема возникла, только bash доступен внутри маршрутизатора. Perl и C — это мечта. Я использую устройство для связи rs485 с другим ведомым устройством, и обмен работает отлично! - person Orlov Const; 17.12.2019
comment
Спасибо. Вещь красоты, это радость навсегда - person eigenfield; 21.12.2019

Стандарт POSIX AWK говорит, что передача 0 в printf AWK с форматом %c может привести к неуказанному поведению. Однако... Эхо POSIX также очень ограничено, и хотя восьмеричные и шестнадцатеричные спецификаторы (и -n) будут работать на встроенном эхе GNU и BASH... Они могут работать не везде. Чтобы максимизировать вероятность того, что вы получите согласованное поведение во всех системах POSIX, лучше использовать printf командной строки оболочки, чем любой из них.

$ printf '\060\000\061\000' | od -An -tx1
 30 00 31 00

Хотя мне это кажется странным... Возможно, вы захотите вывести 0x48, 0x00, 0x49, 0x00, что выглядит как красивое пилотное число в восьмеричном виде:

$ printf '\110\000\111\000' | od -An -tx1
 48 00 49 00
person Michael Back    schedule 16.06.2014

вы можете попробовать эхо, которое также позволяет использовать произвольные символы ascii (эти числа являются восьмеричными числами).

echo -n -e \\0060\\0000\\0061\\0000  | hexdump
person flolo    schedule 07.04.2011
comment
... и в шестнадцатеричном формате..? Это возможно? - person elcuco; 07.04.2011
comment
нет, эхо просто принимает восьмеричное число. Но вы просили конкретную заданную шестнадцатеричную последовательность (и я даже перевел их для вас в восьмеричные). Если вы не знаете, как конвертировать, ищите другую шестнадцатеричную последовательность на справочной странице ascii. Это даст вам таблицу с десятичными, шестнадцатеричными и восьмеричными числами ;-). - person flolo; 07.04.2011
comment
просто для справки в будущем он принимает шестнадцатеричный код. просто используйте \\xNN, где N - шестнадцатеричное число. - person Velocibadgery; 11.08.2017

Мне нужно было записать двоичные файлы из шестнадцатеричного кода, используя busybox в старой оболочке Android. Этот printf с перенаправлением работал в моем случае использования.

Запишите двоичные данные в шестнадцатеричном формате:

# busybox printf '\x74\x65\x73\x74' > /sdcard/test.txt

Отобразить результат в шестнадцатеричном формате:

# busybox hexdump -C /sdcard/test.txt
00000000  74 65 73 74                                       |test|
00000004

Отобразить результат в ascii:

# cat /sdcard/test.txt
test
person BuvinJ    schedule 18.07.2016
comment
Почему вам нужно использовать, чтобы использовать dd? Почему busybox printf '\x74\x65\x73\x74' > /sdcard/test.txt не работает? - person Keith Thompson; 19.07.2016
comment
Вау ты прав! Я был уверен, что пробовал это. Я попробовал все эти ответы и дюжину других, но все они потерпели неудачу. Это так просто. В миксе должна быть какая-то другая переменная. Я пересмотрю свой ответ. Спасибо! - person BuvinJ; 19.07.2016

Пара более общих функций для вывода целых чисел:

le16 () { # little endian 16 bit binary output 1st param: integer to 2nd param: file 
  v=`awk -v n=$1 'BEGIN{printf "%04X", n;}'`
  echo -n -e "\\x${v:2:2}\\x${v:0:2}" >> $2
}

le32 () { # 32 bit version
  v=`awk -v n=$1 'BEGIN{printf "%08X", n;}'`
  echo -n -e "\\x${v:6:2}\\x${v:4:2}\\x${v:2:2}\\x${v:0:2}" >> $2
}

Используйте, чтобы сделать заголовок звукового файла WAV для потока данных iio:

channels=2
bits_per_sample=16
let "block_align = channels * bits_per_sample / 8"    

wave_header () { # pass file name and data size as parameters; rest are constants set elsewhere
  data_size=$2
  let "RIFFsize = data_size + 44 - 8"
  let "bytes_per_sec = sampleHz * block_align"

  echo -e -n "RIFF" > $1
    le32 $RIFFsize $1
  echo -e -n "WAVEfmt " >> $1
    le32 16 $1  # format size
    le16 1 $1   #format tag: 1 = PCM
    le16 $channels $1
    le32 $sampleHz $1
    le32 $bytes_per_sec $1
    le16 $block_align $1
    le16 $bits_per_sample $1   # bits per sample
  echo -e -n "data" >> $1
    le32 $data_size $1
}

Захват данных Linux iio ADC в файл WAV:

sampleHz=8000
milliseconds=15  # capture length 

cd /sys/bus/iio/devices/iio:device0

cat /sys/bus/iio/devices/trigger0/name > trigger/current_trigger

echo 0 > buffer/enable

echo 0 > scan_elements/in_voltage0_en  #
echo 1 > scan_elements/in_voltage1_en  #  
echo 1 > scan_elements/in_voltage2_en  # 
echo 0 > scan_elements/in_voltage3_en  #

echo $sampleHz > sampling_frequency
sampleHz=`cat sampling_frequency`  # read back actual sample rate

let "buffer_length = block_align * sampleHz * milliseconds / 1000"
echo $buffer_length > buffer/length

cd $HOME

echo 1 > /sys/bus/iio/devices/iio:device0/buffer/enable
wave_header data.wav $buffer_length
head -c $buffer_length /dev/iio:device0 >> data.wav  # LE16 data
echo 0 > /sys/bus/iio/devices/iio:device0/buffer/enable
person Hal Sampson    schedule 18.06.2019

Я не знаю, что находится в busybox, но это может сработать, потому что printf меньше, чем awk.

$ printf "%c%c%c%c" 48 0 49 0 | hexdump

Это результат:

$ printf "%c" 1 | hexdump
0000000 0031                    
person drysdam    schedule 07.04.2011
comment
Я отредактировал ваш ответ тем, что вижу, и это не то, о чем я спрашивал. Это печатает 0x31, который является значением ASCII символа 1. - person elcuco; 07.04.2011
comment
Поэтому, если вы замените 1 на H и I, вы получите нужные вам значения 0x48, 0x49 — вместо десятичных 48/49 (используя 0 и 1). Проблемная часть - получить нулевые байты, чтобы не прерывать вывод. Вышеприведенное затем преобразуется в printf "%c%c%c%c" 72 0 73 0 | hexdump для вывода 0x48 0x00 0x49 0x00. - person starturtle; 08.06.2016