我处理不同的二进制数据。大多数情况下,这些都是带符号的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的元素。有没有简单的命令行方法怎么做?
答案 0 :(得分:0)
这样的一个班轮就像是:
for c in `cat data.pcm`; do if [ $c -lt -2100 -o $c -gt 2100 ]; then echo $c; fi; done
答案 1 :(得分:0)
$ 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
答案 2 :(得分:0)
好吧,二进制...个人建议:不要使用普通的旧shell - 使用适合工作的工具。 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
由于shell使用行分隔符来分割输入块,因此我不确定这是否可以通过简单的方法进行管道化。
答案 3 :(得分:0)
可以使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
答案 4 :(得分:0)
每当我想从二进制文件中提取数值时,我都使用od
(八进制转储)。它有许多选项可用于提取字符,整数(8,16,32和64位)和浮点数(32位和64位)。您还可以指定要查找的确切值的偏移量。
要了解有关它的更多信息,请输入:
man od
然后,对bash中的od
输出进行过滤不应该很复杂。