长话短说:最新提供的 busybox (1.23.2)head
有问题,并且会很乐意在提供的数据中删除 NUL 字符。替换二进制文件不是一个选择。我在我的脚本中使用head -[nc] -X
,有没有办法可以用其他 busybox 提供的工具来模拟它?
不熟悉文件上传和 busybox httpd 处理方式的人可能想阅读这在继续之前。
我正在尝试在安装了 Busybox 的嵌入式系统上处理 CGI 脚本收到的数据上传。发送的数据如下:
$ hexdump -C foo.bin
00000000 03 15 20 00 00 00 75 73 74 61 72 30 30 30 2e 30 |.. ...ustar000.0|
00000010 00 11 00 |...|
00000013
当通过 POST 请求发送时,处理数据的 CGI 脚本接收以下数据:
$ hexdump -C 24593.tmp
00000000 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d |----------------|
00000010 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 30 65 34 32 32 64 |----------0e422d|
00000020 63 39 65 64 65 32 34 36 34 30 0d 0a 43 6f 6e 74 |c9ede24640..Cont|
00000030 65 6e 74 2d 44 69 73 70 6f 73 69 74 69 6f 6e 3a |ent-Disposition:|
00000040 20 66 6f 72 6d 2d 64 61 74 61 3b 20 6e 61 6d 65 | form-data; name|
00000050 3d 22 66 69 6c 65 22 3b 20 66 69 6c 65 6e 61 6d |="file"; filenam|
00000060 65 3d 22 66 6f 6f 2e 62 69 6e 22 0d 0a 43 6f 6e |e="foo.bin"..Con|
00000070 74 65 6e 74 2d 54 79 70 65 3a 20 61 70 70 6c 69 |tent-Type: appli|
00000080 63 61 74 69 6f 6e 2f 6f 63 74 65 74 2d 73 74 72 |cation/octet-str|
00000090 65 61 6d 0d 0a 0d 0a 03 15 20 00 00 00 75 73 74 |eam...... ...ust|
000000a0 61 72 30 30 30 2e 30 00 11 00 0d 0a 2d 2d 2d 2d |ar000.0.....----|
000000b0 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d |----------------|
000000c0 2d 2d 2d 2d 2d 2d 30 65 34 32 32 64 63 39 65 64 |------0e422dc9ed|
000000d0 65 32 34 36 34 30 2d 2d 0d 0a |e24640--..|
000000da
从上面检索原始数据很容易:
$ tail -n +5 24593.tmp | head -n -1 | head -c -2 | hexdump -C
00000000 03 15 20 00 00 00 75 73 74 61 72 30 30 30 2e 30 |.. ...ustar000.0|
00000010 00 11 00 |...|
00000013
然而,busybox 有一个坏处head
,会删除数据中的所有 NUL 字符:
$ /firmware/system/xbin/tail -n +5 24593.tmp | /firmware/system/xbin/head -n -1 | /firmware/system/xbin/head -c -2 | hexdump -C
00000000 03 15 20 75 73 74 61 72 30 30 30 2e 30 11 |.. ustar000.0.|
0000000e
是否有任何其他方法可以使用head -[nc] -X
busybox 提供的其他工具来模拟(或至少执行工作)行为?
最谨慎的做法是引入/替换具有正确行为的新二进制文件,但由于多种原因(我们不必在此讨论)而无法这样做。
这篇文章似乎主要致力于提及与当前问题无关的细节,但我在这里介绍细节是为了避免XY问题。
答案1
如果我正确理解您的问题,您想从包含以下内容的请求中提取上传的文件:
- 由破折号后跟十六进制数字组成的线;
- 更多非空行(标题);
- 空行;
- 要提取的内容;
- 换行符;
- 重复第一行;
其中换行符是 CRLF 序列,内容可以包含任意字节,但标头不包含空字节。
您可以通过两个步骤来完成此操作,而不是依赖head
并tail
解析行:
- 确定要提取的字节位置的范围。
- 提取这些字节。
第一步,为了避免空字节问题,请使用tr
将它们转换为其他内容。然后,您可以使用基于行的工具来检测第一个空行并检测最后一行的开头。我在下面使用 awk,并借此机会也提取文件名。如果你没有 awk 那么你可以使用head
, tail
, sed
, ...
对于第二步,您可以使用dd
块大小为 1 的块。这很慢但可靠。
upload=24593.tmp
filename=$(<"$upload" tr '\0' _ | awk '
{line_start = line_end; line_end += length($0)+1}
!content_start && /^Content-Disposition:.*filename="/ {
sub(/.*filename="/, ""); sub(/".*/, "");
filename = $0
}
!content_start && $0=="\r" {content_start=line_end}
END {print content_start, line_start-2-content_start, filename}
')
skip=${filename%% *}; filename=${filename#* }
count=${filename%% *}; filename=${filename#* }
if [ -z "$filename" ]; then filename=$(mktemp); fi
<$upload dd bs=1 skip="$skip" count="$count" >"$filename"
答案2
Busybox 是高度可配置的,因此答案将取决于编译的内容。以下是一些选项。
catv -v
会将空值显示为“^@”。
split -l 1
将创建文件xaa
xab
等,每个文件中包含一行。