Sh, awk: как преобразовать целые числа, видимые в оболочке в виде строки, в 16-битные двоичные числа с младшим / старшим порядком байтов? - PullRequest
2 голосов
/ 11 мая 2011

У меня есть последовательность bash,

grep "integer =" $1 | awk -F= '{printf("%d\n",int($2*327))}'

, которая фильтрует что-то, производящее что-то вроде:

6768
6572
6638
8403
8436
8436
8305
8502

Однако мне нужно, чтобы все эти числа были помещены в двоичный файл как 16-битовые слова с прямым порядком байтов (или байты с обратным порядком байтов, если указаны).Есть ли какой-нибудь способ сделать это?

В идеале это может выглядеть так:

grep "integer =" $1 | awk -F='{TO16BIT_LENDIAN(printf("%d\n",int($2*327)))}' >> out.bin

Ответы [ 3 ]

4 голосов
/ 11 мая 2011

Это должно работать:

cat $1 | grep "integer =" | awk -F='
function out(b)
{
  if(b==0)
  {
    system("printf \"\\00\"");
  }
  else
  {
    printf("%c",b);
  }
}
function shortToLE(n)
{
  n%=65536;
  msb=n/256;
  lsb=n%256;
  out(lsb);
  out(msb);
}

{
  shortToLE($2*327)
}
' >> out.bin

и оптимизированный способ удаления ненужных котов и grep:

awk -F" =" '
function out(b)
{
  if(b==0)
  {
    system("printf \"\\00\"");
  }
  else
  {
    printf("%c",b);
  }
}
function shortToLE(n)
{
  n%=65536;
  msb=n/256;
  lsb=n%256;
  out(lsb);
  out(msb);
}

$1 == "integer" {
  shortToLE($2*327)
}
' $1 >> out.bin
1 голос
/ 11 мая 2011

Запись в файл определенного формата обычно выполняется на языке более высокого уровня. Пример с Ruby (где ваш входной файл находится в $1:

ruby -e '
  nums = File.readlines(ARGV[0]).collect {|line| (Float(line) * 327).to_i}
  File.open("out.bin", "wb") do |fh|
    fh.write( nums.pack("v*") )
  end
' "$1"

Метод Ruby's Array # pack задокументирован здесь .

Обновление:

с помощью переключателя -n:

ruby -ne '
  BEGIN {fh = File.open("out.bin","wb")}
  fh.write( [(Float($_) * 327).to_i].pack("v") )
' numbers
0 голосов
/ 14 августа 2012

А теперь для ужасной правды, что сценарий, использующий printf ("% c", data), больше не работает

И вот мой ужасный адский * * * * обходной путь.Ауг!

# This ugly hack forces our broken system to pretend it works
MAGIC_SHIT=((ENVIRON[LANG]=="C")?0:0xd800);
function TO16BIT_LENDIAN(n){return sprintf("%c%c",(MAGIC_SHIT+and(n,0xff)),(MAGIC_SHIT+rshift(and(n,0xff00),8)));}

Здесь могут потребоваться некоторые объяснения.Когда мы пишем наши сценарии, предполагается, что установлено

export LANG=C

.Однако, когда у кого-то есть

en_US.UTF-8

, включается правильность POSIX, и вы больше не можете играть с байтами, как если бы вы были, вместо этого вынуждены рассматривать каждый символ как наименьшую единицу.Это означает, что

0x00 up to 0x7f = 0xYY  // sprintf("%c",n) prints ok
0x80 up to 0xbf = 0xc2 0xYY  // sprintf("%c",n) prints 0xc2 in front
0xc0 up to 0xff = 0xc3 + 0x80..0xb0  // Totally junk, not what we want.

Вы теперь больше не можете печатать терку необработанных байтов, что 128 .

Теперь это потому, что спецификация UTF-8 сообщаетнам нужно сделать это.
И вот важная часть
Большинство прасеров, которые конвертируют код символа utf-8, для этого выполняют простую битовую операцию. Когда мы вводим 0xd800 или значение терки в эти прасеры, чаще всего, когда недокументированная функция, позволяет вам печатать необработанные байты, как это было бы в старых системах

Это совершенно безобразный хак, который Вы не должны зависеть от .Насколько я знаю, таких спецификаций не существует, или не идет мне в голову.Скажите, пожалуйста, есть ли один такой.

Однако, когда вы работаете в системе с неверным значением LANG или когда вашему сценарию нужно обрабатывать символы utf-8, на большей части сценария, крометолько вывод данных, тогда это можно было бы считать временным обходным решением, пока мы не сможем установить LANG или эквивалент в скрипте.

Последняя проверка на gawk 4.0.1

Ненавижуэтот хак

...