Обработка двоичных файлов данных в bash, поиск элементов, которые больше некоторого числа - PullRequest
0 голосов
/ 07 декабря 2010

Я обрабатываю разные двоичные данные. В основном это подписанные 16-битные потоки. С hexdump это выглядит так:

...
2150     -191    -262    15      -344    -883    -820    -1038   -780
-1234   -1406   -693    131     433     396     241     600     1280
...

Я хотел бы видеть только те элементы потока данных, которые больше или меньше некоторого порогового значения (данные являются 16-битными двоичными знаками). Это может выглядеть так:

cat data.pcm | $($here_some_filtering) 2100 -2100

где выходные данные должны давать только элементы, которые больше 2100 и меньше -2100. Есть ли простой способ командной строки, как это сделать?

Ответы [ 5 ]

0 голосов
/ 07 декабря 2010

Всякий раз, когда я хочу извлечь числовые значения из двоичного файла, я использую od (восьмеричный дамп). Он имеет много опций для извлечения символов, целых чисел (8, 16, 32 и 64 бит) и чисел с плавающей запятой (32 и 64 бит). Вы также можете указать смещение на точное значение, которое вы ищете.

Чтобы узнать больше об этом, введите:

man od

Тогда фильтрация на выходе od не должна быть сложной в bash.

0 голосов
/ 07 декабря 2010

Bash может использоваться для обработки двоичных данных.

getbyte () {
    local IFS= LC_CTYPE=C res c
    read -r -d '' -n 1 c
    res=$?
    # the single quote in the argument of the printf 
    # yields the numeric value of $c (ASCII since LC_CTYPE=C)
    [[ -n $c ]] && c=$(printf '%d' "'$c") || c=0
    printf "$c"
    return $res
}

filter () {
    local b1 b2 val
    while b1=$(getbyte)
    do
        b2=$(getbyte)
        (( val = b2 * 256 + b1 ))
        (( val = val > 32767 ? val - 65536 : val ))
        if (( val > ${1:-0} || val < ${2:-0} ))
        then
            echo $val
        fi
    done
}

Примеры (данные намеренно имеют нечетное число байтов, чтобы показать, что функция соответствует этому условию):

$ data='\0\01\010\0377\0377\0100\0300\0200\0333'
$ echo -en "$data" | filter
256
-248
16639
-32576
219
$ echo -en "$data" | filter 222 -333
256
16639
-32576

Тогда ваша команда будет:

filter 2100 -2100 < data.pcm
0 голосов
/ 07 декабря 2010
$ cat pcm
2150     -191    -262    15      -344    -883    -820    -1038   -780
-1234   -1406   -693    131     433     396     241     600     1280

$ for num in $(< pcm); do ((num > 2100 || num < -2100)) && echo $num; done
2150
0 голосов
/ 07 декабря 2010

Ну, бинарный ... личное предложение: не используйте простую старую оболочку - используйте подходящий для работы инструмент.Perl, Python, даже программа на C / C ++ - в большинстве случаев они будут однострочными.

Ниже приведен неоптимизированный хак, чтобы дать вам представление:

#!/bin/bash
lowerlimit=-333;
upperlimit=333;
filesize=`wc -c "$1" | cut -d' ' -f1`;

off=0;
while [ $off -lt $filesize ]; do
    shortval=$(od -An -s -N 2 -j $off "$1")
    test $shortval -gt $lowerlimit &&
    test $shortval -lt $upperlimit &&
    dd if="$1" bs=1 count=2 skip=$off 2>/dev/null
    off=$(($off + 2))
done

IЯ не уверен, что это можно сделать простым способом из-за того, что оболочка использует разделители строк для разделения входных блоков.

0 голосов
/ 07 декабря 2010

Один лайнер для этого будет что-то вроде:

for c in `cat data.pcm`; do if [ $c -lt -2100 -o $c -gt 2100 ]; then echo $c; fi; done
...