如何确定运行tar是否会导致磁盘已满


22

如果我tar -cvf在一个大小为937MB的目录上运行,以创建一个易于下载的深层嵌套文件夹结构副本,那么在给出以下df -h输出的情况下,我是否冒着填充磁盘的风险:

/dev/xvda1            7.9G  3.6G  4.3G  46% /
tmpfs                 298M     0  298M   0% /dev/shm

相关问题:

  • 如果磁盘可能已满,为什么tar要这样做(例如Linux(Amazon AMI)和/或在后台执行)?
  • 我如何自己准确地确定此信息,而无需再次询问?

我不确定是否可以不处理存档,但是您可以--totals选择使用。无论哪种方式,如果您填满磁盘,都可以简单地删除存档,恕我直言。要检查所有可用选项,您可以通过tar --help
2014年

4
切线地:不要将tarfile创建为root,而是将磁盘上一定百分比的空间专门用于root,这恰好是“我已填满磁盘,现在我无法登录,因为那样会写”。 bash_history或其他情况”。
Ulrich Schwarz 2014年

Answers:


24

tar -c data_dir | wc -c 没有压缩

要么

tar -cz data_dir | wc -c 使用gzip压缩

要么

tar -cj data_dir | wc -c 使用bzip2压缩

将打印将以字节为单位创建的归档文件的大小,而无需写入磁盘。然后,您可以将其与目标设备上的可用空间量进行比较。

如果对数据目录的大小作出了错误的假设,则可以使用以下命令检查数据目录本身的大小:

du -h --max-depth=1 data_dir

正如已经回答的那样,tar将头文件添加到存档中的每个记录,并且还将每个记录的大小四舍五入为512字节的倍数(默认情况下)。归档的结尾至少由两个连续的零填充记录标记。因此,通常情况下,未压缩的tar文件会比文件本身大,文件的数量以及它们与512字节边界的对齐方式将决定所使用的额外空间。

当然,文件系统本身使用的块大小可能大于单个文件的内容,因此请小心将其解压缩,即使文件系统的可用空间大于tar大小,它也可能无法容纳许多小文件!

https://zh.wikipedia.org/wiki/塔尔(计算)#Format_details


谢谢杰米!“-mysql”在这里做什么?那是你的文件名吗?
codecowboy

只是更改而已...这是您的数据目录的路径。
FantasticJamieBurns'Apr

1
并不是真的很重要,但是-f -对tar 使用参数组合是多余的,因为您可以简单地-f完全省略参数以将结果写入stdout(即tar -c data_dir)。

6

tar文件的大小将为937MB,再加上每个文件或目录所需的元数据的大小(每个对象512字节),并添加了填充以将文件对齐到512字节边界。

一个非常粗略的计算告诉我们,您的另一份数据副本将为您提供3.4GB的可用空间。在3.4GB中,假设没有填充,我们有大约700万个元数据记录的空间;如果假设每个文件平均有256个字节的填充,则我们有更少的空间。因此,如果您有数百万个要压缩的文件和目录,则可能会遇到问题。

您可以通过缓解问题

  • 使用zj选项动态压缩tar
  • tar以普通用户的身份执行操作,以便在空间/不足的情况下不会触及分区上的保留空间。

2

tar本身可以使用以下--test选项报告其档案的大小:

tar -cf - ./* | tar --totals -tvf -

上面的命令不向磁盘写入任何内容,并且具有列出tarball中包含的每个文件的单个文件大小的附加好处。将各种z/j/xz操作数添加 到的任意一侧|pipe将按您的意愿处理压缩。

输出:

...
-rwxr-xr-x mikeserv/mikeserv         8 2014-03-13 20:58 ./somefile.sh
-rwxr-xr-x mikeserv/mikeserv        62 2014-03-13 20:53 ./somefile.txt
-rw-r--r-- mikeserv/mikeserv       574 2014-02-19 16:57 ./squash.sh
-rwxr-xr-x mikeserv/mikeserv        35 2014-01-28 17:25 ./ssh.shortcut
-rw-r--r-- mikeserv/mikeserv        51 2014-01-04 08:43 ./tab1.link
-rw-r--r-- mikeserv/mikeserv         0 2014-03-16 05:40 ./tee
-rw-r--r-- mikeserv/mikeserv         0 2014-04-08 10:00 ./typescript
-rw-r--r-- mikeserv/mikeserv       159 2014-02-26 18:32 ./vlc_out.sh
Total bytes read: 4300943360 (4.1GiB, 475MiB/s)

不能完全确定您的目的,但是如果要下载压缩包,则可能更重要:

ssh you@host 'tar -cf - ./* | cat' | cat >./path/to/saved/local/tarball.tar

或简单地复制tar

ssh you@host 'tar -cf - ./* | cat' | tar -C/path/to/download/tree/destination -vxf -

我这样做的原因是,我相信所讨论的目录已导致df -i的输出达到99%。我想保留目录的副本以进行进一步分析,但想清除空间
codecowboy14年

@codecowboy在这种情况下,您绝对应该先执行上述操作。tar然后,它将树以流的形式复制到本地磁盘,而根本不保存任何内容到远程磁盘,之后您可以将其从远程主机中删除并稍后还原。-z正如goldilocks指出的那样,您可能应该添加压缩功能,以节省传输中的带宽。
mikeserv

@ TAFKA'goldilocks'不,因为它是inode的99%,而不是99%的空间。
吉尔斯(Gilles)'所以

-i对,对不起!
goldilocks 2014年

@mikeserv您的开头行提到--test选项,但是您似乎没有在紧随其后的命令中使用它(它使用--totals)
codecowboy 2014年

2

我对此做了很多研究。您可以使用字数统计功能对文件进行测试,但不会为您提供与相同的数字du -sb adir

tar -tvOf afile.tar | wc -c

du将每个目录计数为4096字节,并将tar目录计数为0字节。您必须将4096添加到每个目录:

$(( $(tar -tvOf afile.tar 2>&1 | grep '^d' | wc -l) * 4096)))

那么您必须添加所有字符。对于看起来像这样的东西:

$(( $(tar -tvOf afile.tar 2>&1 | grep '^d' | wc -l) * 4096 + $(tar -xOf afile.tar | wc -c) ))

我不确定这是否完美,因为我没有尝试触摸过的文件(0字节的文件)或具有1个字符的文件。这应该使您更接近。


1

-cvf不包含任何压缩,因此在〜1 GB的文件夹上执行此操作将导致〜1 GB的tar文件(Flub的答案提供了有关tar文件中其他大小的更多详细信息,但请注意,即使有10,000个文件,这也只是5 MB)。由于您有4 GB以上的可用空间,因此不会填充分区。

易于下载的副本

在下载方面,大多数人会认为“轻松”与“较小”同义,因此您应在此处使用一些压缩方式。 bzip2我认为,现在应该可以在任何具有tar的系统上使用它,因此,将其包含j在交换机中可能是最佳选择。 zgzip)甚至更常见,还有其他(较不普遍)壁球的可能性。

如果您的意思是确实tar在执行任务时确实使用了额外的磁盘空间,那么我可以肯定它并不是出于一些原因,一个原因可以追溯到磁带驱动器是主存储形式的时候,另外两个可以有数十年的发展历史(而且我敢肯定,即使涉及压缩,也不必使用临时的中间空间)。


0

如果速度是重要的并且不需要压缩,你可以连接所使用的系统调用包装tar使用LD_PRELOAD,改变tar计算对我们来说。通过重新实现其中的一些功能,以满足我们的需要(计算潜在产出焦油数据的大小),我们能够消除大量的read,并write认为在正常操作中执行tar。这样可以tar更快地进行操作,因为它不需要上下文切换到内核附近的任何地方,并且只需stat要从磁盘读取请求的输入文件/文件夹而不是实际的文件数据即可。

下面的代码包括的实施方式closereadwritePOSIX功能。宏OUT_FD控制我们希望tar将哪个文件描述符用作输出文件。当前将其设置为stdout。

read更改为仅返回count字节的成功值,而不是用数据填充buf,因为未读取实际数据buf不会包含传递给压缩的有效数据,因此,如果使用压缩,我们将计算出错误的值尺寸。

write更改为将输入count字节加到全局变量中,total在文件描述符匹配时返回count字节的成功值,否则它将调用通过获取的原始包装器以执行相同名称的syscall。OUT_FDdlsym

close仍然会执行其所有原始功能,但是如果文件描述符与OUT_FD相匹配,它将知道tar尝试写入tar文件已完成,因此该total数字是最终的,并将其打印到stdout。

#define _GNU_SOURCE
#include <unistd.h>
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdlib.h>
#include <errno.h>
#include <dlfcn.h>
#include <string.h>

#define OUT_FD 1
uint64_t total = 0;
ssize_t (*original_write)(int, const void *, size_t) = NULL;
int (*original_close)(int) = NULL;
void print_total(void)
{
    printf("%" PRIu64 "\n", total);
}

int close(int fd)
{
    if(! original_close)
    {
        original_close = dlsym(RTLD_NEXT, "close");
    }
    if(fd == OUT_FD)
    {
        print_total();
    }
    return original_close(fd);
}

ssize_t read(int fd, void *buf, size_t count)
{
    return count;
}

ssize_t write(int fd, const void *buf, size_t count)
{
    if(!original_write)
    {
        original_write = dlsym(RTLD_NEXT, "write");
    }
    if(fd == OUT_FD)
    {
        total += count;
        return count;
    }
    return original_write(fd, buf, count);
}

基准比较解决方案,其中对解决方案执行了读取磁盘访问和正常tar操作的所有系统调用LD_PRELOAD

$ time tar -c /media/storage/music/Macintosh\ Plus-\ Floral\ Shoppe\ \(2011\)\ \[Flac\]/ | wc -c
332308480
real    0m0.457s
user    0m0.064s
sys     0m0.772s
tarsize$ time ./tarsize.sh -c /media/storage/music/Macintosh\ Plus-\ Floral\ Shoppe\ \(2011\)\ \[Flac\]/
332308480
real    0m0.016s
user    0m0.004s
sys     0m0.008s

存储库中提供了以上代码,将上述内容构建为共享库的基本构建脚本以及使用该脚本的“ LD_PRELOAD技术” 脚本:https : //github.com/G4Vi/tarsize

有关使用LD_PRELOAD的一些信息:https : //rafalcieslak.wordpress.com/2013/04/02/dynamic-linker-tricks-using-ld_preload-to-cheat-inject-features-and-investigate-programs/


代码是可以的,但是可以描述它的作用吗?请不要在评论中回复;编辑  您的答案,使其更清晰,更完整。
G-Man说“恢复莫妮卡”
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.