#linux #bash #shell #awk #sh
#linux #bash #оболочка #awk #sh
Вопрос:
У меня есть последовательность bash,
grep "integer =" $1 | awk -F= '{printf("%dn",int($2*327))}'
которые фильтруют что-то, производящее что-то вроде:
6768
6572
6638
8403
8436
8436
8305
8502
Однако мне нужно, чтобы все эти числа были помещены в двоичный файл в виде 16-разрядных слов младшего порядка (или с большим порядком, если указано). Есть ли какой-либо awk-, bash-способ сделать это?
В идеале это могло бы выглядеть как:
grep "integer =" $1 | awk -F='{TO16BIT_LENDIAN(printf("%dn",int($2*327)))}' >> out.bin
Комментарии:
1. 1. вы хотите, чтобы ваши выходные данные в .bin разделялись новыми строками? 2. Возможно, в Perl есть что-то, что может сделать это так, как вы себе это представляете (я буду удивлен, если это возможно с помощью предлагаемых вами инструментов). 3. Для чего-то такого простого вы могли бы написать код на языке C. (возможно, сделать проги 2 сентября для больших и маленьких конечных чисел). 4. удачи!
2. @shellter: 1.no, просто поток байтов 2. ну, может быть, python, но я бы хотел остаться с awk / bash, если это возможно 3.python -c «blabla», вероятно, лучше, потому что компиляции можно избежать 4. спасибо!
Ответ №1:
Это должно сработать:
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%6;
out(lsb);
out(msb);
}
{
shortToLE($2*327)
}
' >> out.bin
и оптимизированный способ удаления бесполезных cat и 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%6;
out(lsb);
out(msb);
}
$1 == "integer" {
shortToLE($2*327)
}
' $1 >> out.bin
Комментарии:
1. Черт возьми! Ты опередил меня в этом. Однако вы можете избавиться от
cat
и просто поместить имя файла в концеawk
команды. Вы также можете избавиться от grep, выполнив поиск «integer=» в awk, а затем используя «index» и «substr», чтобы удалить часть «integer=». В итоге вы просто остаетесь с одной awk-программой. Несмотря на «бесполезный cat», я все равно поставлю вам 1.2. Спасибо, что указали на это. Я был слишком сосредоточен на несколько сложной части awk и упустил из виду то, что ее окружало, что я в основном просто вырезал и вставлял. Добавляю оптимизированный способ к моему ответу.
Ответ №2:
Запись в файл с определенным форматом обычно выполняется с помощью языка более высокого уровня. Пример с 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 Array#pack описан здесь.
Обновить:
используя -n
переключатель:
ruby -ne '
BEGIN {fh = File.open("out.bin","wb")}
fh.write( [(Float($_) * 327).to_i].pack("v") )
' numbers
Комментарии:
1. Вероятно, выглядело бы менее загроможденным использование
ruby -ne
2. @glenn: есть ли причина записать это в файл, а не в стандартный вывод?
3. @ninjalj, это требование вопроса.
4. @glenn: Я не думаю, что обязательно делать все на одном языке, просто перенаправьте стандартный вывод в файл, для этого есть
-n
и-p
, чтобы включить однострочники вместе с оболочкой.
Ответ №3:
А теперь о неприятной правде, что скрипт, использующий printf(«%c», данные), больше не работает
И вот мое чертовски уродливое, полностью измененное решение. Ого!
# 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 или grater в эти празеры, чаще всего, хотя функция недокументирована, она позволяет печатать необработанные байты, как в старых системах
Это совершенно уродливый взлом, от которого вы не должны зависеть. Насколько я знаю, такой спецификации не существует или она не приходит мне в голову. Пожалуйста, скажите мне, есть ли одно такое.
Однако, когда вы работаете в системе, которая имеет неправильное значение LANG, или когда вашему скрипту необходимо обрабатывать символы utf-8 в большей части скрипта, за исключением только выходных данных, тогда это можно считать временным обходным путем, пока каким-то образом мы не сможем установить LANG или equlavant из скрипта.
Последняя проверка на gawk 4.0.1
Я ненавижу этот взлом