我想要tar
一个目录并将结果写入stdout
,然后将其通过管道传输到压缩程序,如下所示:
tar -cvf - /tmp/source-dir | lzip -o /media/my-usb/result.lz -
我一直使用管道来输出多行文本的命令。现在我想知道当我通过管道传输一个具有非常大输出的(快速)命令(例如,tar
随后是一个非常慢的压缩命令)时会发生什么?会tar
等待其输出被 消耗掉吗lzip
?或者它只是尽可能快地将所有内容输出到 RAM?如果后者属实,那么对于低 RAM 系统来说这将是一场灾难。
答案1
当数据生产者 ( tar
) 尝试太快地写入管道以使消费者 ( lzip
) 没有时间读取所有数据时,它将堵塞直到lzip
有时间阅读tar
所写的内容。有一个与管道关联的小缓冲区,但其大小可能小于大多数tar
档案的大小。不存在管道填满系统 RAM 的风险。
“阻塞”只是意味着当tar
调用库函数(或等效函数)时,调用不会返回,直到数据被传递到管道缓冲区,如果读取速度很慢,write()
这可能需要一些时间lzip
相同的缓冲区。您应该能够在与 相比(假设实际上比 更快)的top
地方看到这一点,其中tar
会减慢速度并睡眠很多。lzip
tar
lzip
因此你会不是使用管道填充大量 RAM。为此(如果您愿意),您可以pv
在中间使用类似的东西,并带有一些大缓冲区(此处为千兆字节):
tar -cvf - /tmp/source-dir | pv --buffer-size 1G | lzip -o /media/my-usb/result.lz -
tar
无论何时pv
阻塞, 这仍然会阻塞。pv
当缓冲区已满且无法写入时会阻塞lzip
。
相反的情况以类似的方式工作,即,如果管道的左侧缓慢写入右侧快速,则右侧的消费者将阻塞,read()
直到有数据可从管道读取。
这(数据 I/O)是唯一同步参与管道的进程的东西。除了读取和写入(偶尔会在等待其他人读取或写入时发生阻塞)之外,它们将彼此独立运行。
答案2
GNU柏油有--lzip选项“通过lzip过滤存档”,所以你可能想改用:
tar -cvf --lzip /media/my-usb/result.lz /tmp/source-dir
回答问题:在您的情况下,系统将使用默认的系统缓冲区大小正确管理管道。