Как написать бинарный файл, используя 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" (все остальные значения в порядке).

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

Ответ 1

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

echo -n -e \\x48\\x00\\x49\\x00 > myfile

Ответ 2

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

$ 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

Ответ 3

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

echo -n -e \\0060\\0000\\0061\\0000  | hexdump

Ответ 4

Мне нужно было написать двоичные файлы из hex с помощью 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

Ответ 5

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

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

Ответ 6

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

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

Это вывод:

$ printf "%c" 1 | hexdump
0000000 0031