我想在Linux桌面(RHEL4)中从一个大于1 GB的文件中提取一定范围的字节(通常少于1000个),我知道在文件中的偏移量和块的大小。
我可以编写代码来实现这个功能,但是否有命令行解决方案呢?
理想情况下,类似这样的命令:
magicprogram --offset 102567 --size 253 < input.binary > output.binary
试试dd
命令:
dd skip=102567 count=253 if=input.binary of=output.binary bs=1
选项bs=1
设置块大小,使得dd
一次只读/写一个字节。默认块大小为512个字节。
bs
的值还会影响skip
和count
的行为,因为在skip
和count
中的数字是dd将要跳过和读/写的块数。
这是一个老问题,但我想增加另一种版本的 dd
命令,它更适合处理大块字节:
dd if=input.binary of=output.binary skip=$offset count=$bytes iflag=skip_bytes,count_bytes
$offset
和$bytes
是以字节为单位的数字。
与Thomas的答案不同之处在于这里没有出现bs=1
。bs=1
将输入和输出块大小设置为1个字节,当要提取的字节数很大时,这会使速度变得非常慢。
这意味着我们将块大小(bs
)保留为默认值512个字节。使用iflag=skip_bytes,count_bytes
,我们告诉dd
将skip
和count
后面的值视为字节数量,而不是块数量。
iflag
是一个未知的操作数,如果没有它,你将得到整个代码块。 - Timmmmdd
可以用于支持 iflag
(安装 coreutils
后使用 brew install
)。注意:默认情况下,这些实用程序会带有“g”前缀(例如 gdd
而不是 dd
)。 - Shakilhead -c
+ tail -c
不确定它在效率上如何比较dd
,但它很有趣:
printf "123456789" | tail -c+2 | head -c3
选择从第二个字节开始的3个字节:
234
另请参阅:
printf '\x01\x02' > f
和 hd
即可。 - Ciro Santilli OurBigBook.com我曾经遇到同样的问题,试图剪切一个RAW磁盘映像的部分。 使用bs=1的dd是无法使用的,因此我编写了一个简单的C程序来完成这个任务。
// usage:
// ./cutfile srcfile destfile offset length
// ./cutfile my.image movie.avi 4524 20412452
// compile, presuming it is saved as cutfile.cc:
// gcc cutfile.cc -o cutfile -std=c11 -pedantic -W -Wall -Werror
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
int main(int argc, char *argv[])
{
if(argc != 5) {
printf("error, need 4 arguments!\n");
return 1;
}
const unsigned blocksize = 16*512; // can adjust
unsigned char buffer[blocksize];
FILE *f = fopen(argv[1], "rb");
FILE *fout = fopen(argv[2], "wb");
long offset = atol(argv[3]);
long length = atol(argv[4]);
if(f==NULL || fout==NULL) {
perror("cannot open file");
return 1;
}
fseek(f, offset, SEEK_SET);
while(length > blocksize) {
fread(buffer, 1, blocksize, f);
fwrite(buffer, 1, blocksize, fout);
length -= blocksize;
}
if(length>0) { // copy rest
fread(buffer, 1, length, f);
fwrite(buffer, 1, length, fout);
}
fclose(fout);
fclose(f);
return 0;
}
std::ifstream
和std::ofstream
是很正常的。 - Alexis Wilkedd bs=<req len> count=1 skip=<req offset> if=input.binary of=output.binary
req_offset=$(bc <<< "$offset/$bs")
并确保它是一个整数。 - Tchakabamdd 命令可以完成所有这些操作。请查看调用的 seek 和/或 skip 参数。
crunch() {
if [ "$#" -ne 3 ]; then
echo "usage: crunch <file.bin> <start address> <end address>"
echo ""
echo "example: crunch myfile.bin 0x1000 0x2000"
else
local file="$1"
local start_addr="$2"
local end_addr="$3"
local difference="$(($end_addr - $start_addr))"
local out_name="${file%%.*}_crunch.${file#*.}"
echorun_conf "tail -c +$(($start_addr+1)) $file | head -c $difference > $out_name"
fi
}
munch() {
if [ "$#" -ne 3 ]; then
echo "usage: munch <(head|tail)> <file.bin> <offset>"
echo ""
echo "example: munch head myfile.bin 0x100"
else
local op="$1"
local file="$2"
local offset="$3"
local out_name="${file%%.*}_munch.${file#*.}"
case "$op" in
"head") echorun_conf "head -c $((offset)) $file > $out_name" ;;
"tail") echorun_conf "tail -c +$((offset+1)) $file > $out_name" ;;
*)
echo "usage: munch <(head|tail)> <file.bin> <offset>"
echo ""
echo "example: munch head myfile.bin 0x100" ;;
esac
fi
}
# echo and run command with y/n confirmation
echorun_conf() {
echo "$@"
echo -n "Execute [y/n]? "
read reply
echo
if [ "$reply" != "${reply#[Yy]}" ]; then
eval "$@"
fi
}
status=none
以抑制输出到标准错误流。 - kenorbdd if=in.bin bs=1 status=none skip=$((0x88)) count=$((0x80)) of=out.bin
。 - kenorb