我正在编写一个bash脚本,需要获取文件的头部(前10个字节),然后在另一个部分获取除前10个字节之外的所有内容。这些是二进制文件,并且可能在前10个字节中包含\0
和\n
。似乎大多数工具都适用于ASCII文件。有什么好的方法来完成这个任务吗?
如前所述,要获取前10个字节:
head -c 10
要获取除了前10个字节之外的所有内容(至少使用GNU的 tail
命令):
tail -c+11
dd
的想法,但这个选项不需要改变缓冲区大小,所以它适用于大文件。谢谢。 - User1head -c 10
在这里做了正确的事情。
dd
命令从二进制文件中复制任意数量的字节。dd if=infile of=outfile1 bs=10 count=1
dd if=infile of=outfile2 bs=10 skip=1
{ printf a; sleep 1; printf b; }|cat | dd bs=2 count=1 iflag=fullblock 2>/dev/null | wc -c
中使用iflag=fullblock
。请参考man dd
和dd --help
。 - F. Hauri - Give Up GitHub阅读SO请求:
获取文件的头部(前10个字节),然后在另一部分中获取除前10个字节以外的所有内容。
我理解为:
如何在特定点分割文件
由于所有答案都访问同一个文件两次,而不是仅仅将其分割!
{ head -c 10 >head_part; cat >tail_part;} <file
head_part
中,剩余的部分则被放到tail_part
中。
注意:第二个重定向>tail_part
也可以放在整个list ({ ...;}
) 的外面。
dd
来实现同样的功能:{ dd count=1 bs=10 of=head_part; cat;} <file >tail_part
这种方法比运行两个dd
进程两次打开同一个文件更有效率。
...并且仍然使用标准的块大小来处理其余部分的文件:
将HTTP(或邮件)流根据几乎为空的行(只包含回车符:\r
)进行拆分:
nc google.com 80 <<<$'GET / HTTP/1.0\r\nHost: google.com\r\n\r' |
{ sed -u '/^\r$/q' >/tmp/so_head.raw; cat;} >/tmp/so_body.raw
nc google.com 80 <<<$'GET / HTTP/1.0\r\nHost: google.com\r\n\r' |
{ sed -nu '/^\r$/q;p' >/tmp/so_head.raw; cat;} >/tmp/so_body.raw
ls -l so_*.raw
-rw-r--r-- 1 root root 307 Apr 25 11:40 so_head.raw
-rw-r--r-- 1 root root 219 Apr 25 11:40 so_body.raw
grep www so_*.raw
so_body.raw:<A HREF="http://www.google.com/">here</A>.
so_head.raw:Location: http://www.google.com/
如果目标是在一个可用的bash变量中获取前10个字节的值,这里有一种不错且高效的方法:
因为只有十个字节,可以避免使用head
命令。参考在BASH中按字节读取文件:
read8() {
local _r8_var=${1:-OUTBIN} _r8_car LANG=C IFS=
read -r -d '' -n 1 _r8_car || { printf -v $_r8_var '';return 1;}
printf -v $_r8_var %02X "'"$_r8_car
}
{
first10=()
for i in {0..9};do
read8 first10[i] || break
done
cat
} < "$infile" >"$outfile"
${first10[@]}
,其中包含$infile
的前十个字节的十六进制值,并将其余数据存储到$outfile
中。declare -p first10
declare -a first10=([0]="25" [1]="50" [2]="44" [3]="46" [4]="2D" [5]="31" [6]="2E"
[7]="34" [8]="0A" [9]="25")
%PDF
-> 25 50 44 46
)... 这里有另一个示例:{
first10=()
for i in {0..9};do
read8 first10[i] || break
done
cat
} <<<"Hello world!"
d!
d!
将在终端上输出。echo ${first10[@]}
48 65 6C 6C 6F 20 77 6F 72 6C
printf '%b%b%b%b%b%b%b%b%b%b\n' ${first10[@]/#/\\x}
Hello worl
您说:
这些是二进制文件,前10个字节很可能会有
\0
和\n
。
{
first10=()
for i in {0..9};do
read8 first10[i] || break
done
cat
} < <(gzip <<<"Hello world!") >/dev/null
echo ${first10[@]}
1F 8B 08 00 00 00 00 00 00 03
read8() { local _r8_var=${1:-OUTBIN} _r8_car LANG=C IFS=
read -r -d '' -n 1 _r8_car || { printf -v $_r8_var '';return 1;}
printf -v $_r8_var %02X "'"$_r8_car ;}
get10() {
local -n result=${1:-first10} # 1st arg is array name
local -i _i
result=()
for ((_i=0;_i<${2:-10};_i++));do # 2nd arg is number of bytes
read8 result[_i] || { unset result[_i] ; return 1 ;}
done
cat
}
⛶
表示:没有换行符)。get10 pdf 4 <$infile >$outfile
printf %b ${pdf[@]/#/\\x}
%PDF⛶
echo $(( $(stat -c %s $infile) - $(stat -c %s $outfile) ))
4
get10 test 8 <<<'Hello world'
rld!
printf %b ${test[@]/#/\\x}
Hello Wo⛶
get10 test 24 <<<'Hello World!'
printf %b ${test[@]/#/\\x}
Hello World!
\n
!;)
get10 test 256 < <(gzip <<<'Hello world!')
printf '%b' ${test[@]/#/\\x} | gunzip
Hello world!
printf " %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s\n" ${test[@]}
1F 8B 08 00 00 00 00 00 00 03 F3 48 CD C9 C9 57
28 CF 2F CA 49 51 E4 02 00 41 E4 A9 B2 0D 00 00
00