BusyBox tar:在给定有限磁盘 space 的情况下追加解决方法?
BusyBox tar: append workaround given limited disk space?
我在 Linux 系统上,资源和 BusyBox 有限 -- 这个版本的 tar 不支持 --append, -r。在 [2] 使 B 文件看起来来自目录 A 之后,是否有一种解决方法允许我 [1] 将目录 B 中的文件附加到目录 A 中现有的 tar 文件? (稍后,当有人提取文件时,它们应该都在同一个目录 A 中。)
情况:我有一个我想要 tar 的文件列表,但我必须先处理其中的一些文件。这些文件可能会被其他进程使用,所以我不想就地编辑它们。我想在使用磁盘 space 时保持保守,所以我的脚本只复制它需要更改的那些文件(与复制所有文件然后处理一些文件并最终使用 tar 将它们全部归档 - 如果我复制他们所有我可能 运行 进入磁盘 space 问题)。
这意味着我要存档的文件最终位于两个不同的位置。但我希望生成的 tar 文件看起来好像它们都在同一位置。在我的脚本接近尾声时,我得到了两个按名称列出 A 和 B 文件的文本文件。
我认为这对于 tar 的完整版本来说很简单,但我必须使用 BusyBox 版本(下面的用法)。提前感谢任何想法!
Usage: tar -[cxtzjaZmvO] [-X FILE] [-f TARFILE] [-C DIR] [FILE]...
Create, extract, or list files from a tar file
Operation:
c Create
x Extract
t List
Options:
f Name of TARFILE ('-' for stdin/out)
C Change to DIR before operation
v Verbose
z (De)compress using gzip
j (De)compress using bzip2
a (De)compress using lzma
Z (De)compress using compress
O Extract to stdout
h Follow symlinks
m Don't restore mtime
exclude File to exclude
X File with names to exclude
T File with names to include
原则上,您只需将包含附加文件的tar
存储库追加到tar
文件的末尾即可。只是比那个稍微难一点。
一个tar文件由任意数量的header + file
重复组成。 header 始终是一个 512 字节的块,文件被填充为 512 字节的倍数,因此您可以将这些单元视为可变数量的 512 字节块。每个块都是独立的;它是 header starts 以及文件的完整路径名。所以没有要求目录中的文件一起tar红色。
有一个并发症。在 tar 文件的末尾,至少有两个 512 字节的块完全用 0 填充。当 tar 正在读取 tar 文件时,它将忽略单个 zero-filled header,但第二个将导致它停止读取文件。如果它到达 EOF,它会报错,所以终止空 headers 是必需的。
可能有两个以上的header,因为tar实际上写入的块是512字节的倍数。例如,Gnu tar,默认情况下写入 20 512 字节块的倍数,因此最小的 tar 文件通常为 10240 字节。
为了追加新数据,您需要先截断现有文件以消除空块。
我相信如果tar文件是由busybox生成的,那么只有两个空块,但我没有检查代码。那很容易;您只需在附加其他文件之前截断文件的最后 1024 个字节。
对于一般的 tar 文件,比较棘手。如果你知道文件本身没有 NUL 字节(即它们都是简单的文本文件),你可以删除空的 headers 直到你找到一个包含非 0 字节的块,这不会太难。
我会做的是:
- 截断 tar 文件的最后 1024 个字节。
- 记住 tar 文件的当前大小。
- 附加一个测试 tar 文件,该文件由带有简单短消息的文件 tar 组成
- 验证
tar tf
是否正确显示测试文件
- 将文件截断回记忆的长度,
- 如果
tar tf
找到测试文件名,则成功
- 如果tar文件的最后512字节全为0,则截断文件的最后512字节,return到第2步
- 否则失败
如果上述过程成功,您可以继续将新文件附加到 tar 存储库。
不知道你有没有trunc命令。如果没有,您可以使用 dd
将文件复制到指定偏移量处的旧文件之上(请参阅 seek=
选项)。 dd
将在复制结束时自动截断文件。您还可以使用 dd
读取 512 字节的块(请参阅 skip
和 count
选项)。
最好的解决方案是将最后的 1024 个字节截断并在其后连接一个新的 tar。为了将 tar 附加到现有的 tar 文件,必须将它们解压缩。
对于像这样的文件:
$ find a b
a
a/file1
b
b/file2
您可以:
$ tar -C a -czvf a.tar.gz .
$ gunzip -c a.tar.gz | { head -c -$((512*2)); tar -C b -c .; } | gzip > a+b.tar.gz
结果:
$ tar -tzvf a+b.tar.gz
drwxr-xr-x 0/0 0 2018-04-20 16:11:00 ./
-rw-r--r-- 0/0 0 2018-04-20 16:11:00 ./file1
drwxr-xr-x 0/0 0 2018-04-20 16:11:07 ./
-rw-r--r-- 0/0 0 2018-04-20 16:11:07 ./file2
或者您可以在同一命令中同时创建两个 tar:
$ tar -C a -c . | { head -c -$((512*2)); tar -C b -c .; } | gzip > a+b.tar.gz
尽管这是针对由 busybox tar 生成的 tar。如前一个答案所述,GNU tar 添加 20 个块的倍数。你需要强制块数为1(--blocking-factor=1)才能提前知道要切割多少块:
$ tar --blocking-factor=1 -C a -c . | { head -c -$((512*2)); tar -C b -c .; } | gzip | tar --blocking-factor=1 -tzv
无论如何,GNU tar 确实有 --append。最后一个 --blocking-factor=1 仅当您缩进并再次附加结果 tar 时才需要。
我在 Linux 系统上,资源和 BusyBox 有限 -- 这个版本的 tar 不支持 --append, -r。在 [2] 使 B 文件看起来来自目录 A 之后,是否有一种解决方法允许我 [1] 将目录 B 中的文件附加到目录 A 中现有的 tar 文件? (稍后,当有人提取文件时,它们应该都在同一个目录 A 中。)
情况:我有一个我想要 tar 的文件列表,但我必须先处理其中的一些文件。这些文件可能会被其他进程使用,所以我不想就地编辑它们。我想在使用磁盘 space 时保持保守,所以我的脚本只复制它需要更改的那些文件(与复制所有文件然后处理一些文件并最终使用 tar 将它们全部归档 - 如果我复制他们所有我可能 运行 进入磁盘 space 问题)。
这意味着我要存档的文件最终位于两个不同的位置。但我希望生成的 tar 文件看起来好像它们都在同一位置。在我的脚本接近尾声时,我得到了两个按名称列出 A 和 B 文件的文本文件。
我认为这对于 tar 的完整版本来说很简单,但我必须使用 BusyBox 版本(下面的用法)。提前感谢任何想法!
Usage: tar -[cxtzjaZmvO] [-X FILE] [-f TARFILE] [-C DIR] [FILE]...
Create, extract, or list files from a tar file
Operation:
c Create
x Extract
t List
Options:
f Name of TARFILE ('-' for stdin/out)
C Change to DIR before operation
v Verbose
z (De)compress using gzip
j (De)compress using bzip2
a (De)compress using lzma
Z (De)compress using compress
O Extract to stdout
h Follow symlinks
m Don't restore mtime
exclude File to exclude
X File with names to exclude
T File with names to include
原则上,您只需将包含附加文件的tar
存储库追加到tar
文件的末尾即可。只是比那个稍微难一点。
一个tar文件由任意数量的header + file
重复组成。 header 始终是一个 512 字节的块,文件被填充为 512 字节的倍数,因此您可以将这些单元视为可变数量的 512 字节块。每个块都是独立的;它是 header starts 以及文件的完整路径名。所以没有要求目录中的文件一起tar红色。
有一个并发症。在 tar 文件的末尾,至少有两个 512 字节的块完全用 0 填充。当 tar 正在读取 tar 文件时,它将忽略单个 zero-filled header,但第二个将导致它停止读取文件。如果它到达 EOF,它会报错,所以终止空 headers 是必需的。
可能有两个以上的header,因为tar实际上写入的块是512字节的倍数。例如,Gnu tar,默认情况下写入 20 512 字节块的倍数,因此最小的 tar 文件通常为 10240 字节。
为了追加新数据,您需要先截断现有文件以消除空块。
我相信如果tar文件是由busybox生成的,那么只有两个空块,但我没有检查代码。那很容易;您只需在附加其他文件之前截断文件的最后 1024 个字节。
对于一般的 tar 文件,比较棘手。如果你知道文件本身没有 NUL 字节(即它们都是简单的文本文件),你可以删除空的 headers 直到你找到一个包含非 0 字节的块,这不会太难。
我会做的是:
- 截断 tar 文件的最后 1024 个字节。
- 记住 tar 文件的当前大小。
- 附加一个测试 tar 文件,该文件由带有简单短消息的文件 tar 组成
- 验证
tar tf
是否正确显示测试文件 - 将文件截断回记忆的长度,
- 如果
tar tf
找到测试文件名,则成功 - 如果tar文件的最后512字节全为0,则截断文件的最后512字节,return到第2步
- 否则失败
- 如果
如果上述过程成功,您可以继续将新文件附加到 tar 存储库。
不知道你有没有trunc命令。如果没有,您可以使用 dd
将文件复制到指定偏移量处的旧文件之上(请参阅 seek=
选项)。 dd
将在复制结束时自动截断文件。您还可以使用 dd
读取 512 字节的块(请参阅 skip
和 count
选项)。
最好的解决方案是将最后的 1024 个字节截断并在其后连接一个新的 tar。为了将 tar 附加到现有的 tar 文件,必须将它们解压缩。
对于像这样的文件:
$ find a b
a
a/file1
b
b/file2
您可以:
$ tar -C a -czvf a.tar.gz .
$ gunzip -c a.tar.gz | { head -c -$((512*2)); tar -C b -c .; } | gzip > a+b.tar.gz
结果:
$ tar -tzvf a+b.tar.gz
drwxr-xr-x 0/0 0 2018-04-20 16:11:00 ./
-rw-r--r-- 0/0 0 2018-04-20 16:11:00 ./file1
drwxr-xr-x 0/0 0 2018-04-20 16:11:07 ./
-rw-r--r-- 0/0 0 2018-04-20 16:11:07 ./file2
或者您可以在同一命令中同时创建两个 tar:
$ tar -C a -c . | { head -c -$((512*2)); tar -C b -c .; } | gzip > a+b.tar.gz
尽管这是针对由 busybox tar 生成的 tar。如前一个答案所述,GNU tar 添加 20 个块的倍数。你需要强制块数为1(--blocking-factor=1)才能提前知道要切割多少块:
$ tar --blocking-factor=1 -C a -c . | { head -c -$((512*2)); tar -C b -c .; } | gzip | tar --blocking-factor=1 -tzv
无论如何,GNU tar 确实有 --append。最后一个 --blocking-factor=1 仅当您缩进并再次附加结果 tar 时才需要。