跳转至

归档和压缩文件的命令

恭喜你,进入这一章,你就已经完成了初级篇最核心的内容了。从这一章开始以及初级篇接下来的几章,我将介绍一些常用但是没那么核心的命令。

这一章我们将先开始学习归档和压缩文件的方法。

归档和压缩

在开始之前我认为有必要先介绍一下这两个基本概念。实际上对于绝大多数初学者,似乎会将归档也称为压缩,但是这两个概念其实有本质的不同。它们的概念如下: 1. 归档(archiving):将多个文件合并成一个文件,不减少体积。通过归档,我们可以简化文件的管理,因为文件的数量减少了。同时我们可以统一管理多个文件的权限和元数据(这两个概念在第6章中讲到过),更准确地说,我们可以给一批文件添加一个统一的权限和元数据。 2. 压缩(compression):通过算法将减小文件体积。通过压缩,我们可以减小文件在存储中占用的空间大小,也可以减小文件在传输过程中占用的带宽和流量大小。

也就是说,归档侧重于文件的合并,压缩侧重于减小文件体积。虽然被常常称作压缩文件的一些文件格式,例如zip,7z等常常也起到归档的作用,但是同样也存在属于压缩文件但不属于归档文件的例子,各种图片和音视频等多媒体文件通常都属于这样的例子,例如jpg,mp3,mp4等。当然,同样也存在属于归档文件但不属于压缩文件的例子,tar格式文件就是一个例子。

由于还是存在一些相似之处,所以这里我还是将两个主题合成一个章节。需要注意,在这一章中我们会讲到的压缩文件将会仅仅指那些同时具有归档功能的压缩文件格式。

最常用的归档工具——tar

对于归档来说,我们最常用的工具将会tar,而且本章我们将只会介绍这一个归档工具。

tar命令的名字是Tape Archive的缩写,不过很有趣的是,这个名称本身也是一个有意义的英文单词。使用tar命令将文件归档之后会得到.tar文件。

归档

tar最主要的用法就是归档。在这之前,我们先介绍一下tar采用的命令行参数的模式。tar采用和ps类似的模式,同时支持两种风格的参数。也就是你可以使用-[abc..]形式的缩写以及--[...]形式的全称,也可以使用不带-的缩写形式。(如果你不太理解,看看下面的例子就懂了)那么,tar的新建归档文件的参数就是-c/c/--create。例如,将两个文件a.txtb.txt归档到一个新的文件test.tar中就可以使用下面三种形式中的一种。

tar cf test.tar a.txt b.txt
tar -cf test.tar a.txt b.txt
tar --create --file test.tar a.txt b.txt
其中-f(或者--file)参数的值用于指定归档文件的路径,用于创建归档的文件使用位置参数(也就是必须放到命令最后)。如果你不使用-f选项来指定归档文件的话,归档文件的内容会直接从标准输出流输出,但是如果你没有使用管道或者文件重定向而直接尝试直接将文件输出到终端的话,tar会报错。也就是说你使用下面这个命令也可以达到和上面相同的效果。
tar c a.txt b.txt > test.tar
另外,请你自己想一想,如果你一定想要tar在它归档的时候将归档文件的内容打印到终端上应该怎么做?并且我推荐你亲自试一试,你会得到很有趣的结果。

解归档

tar另一个最主要的用法就是解归档,也就是将归档文件中的文件还原。解归档的命令行参数是-x/x/--extract。例如,将刚才得到的test.tar解归档可以使用下面三种形式中的一种。

tar xf test.tar
tar -xf test.tar
tar --extract --file test.tar
另外,在你解归档的时候,你可以使用--directory=<target>来指定解归档文件时的目标文件夹(请将<target>替换成目标路径,不带<>)。请不要问我为什么这个参数没有缩写,我也不知道,就像我也不知道为什么要将--extract缩写成-x而不是-e一样。你还可以使用命令最后的位置参数来指定要解归档的文件,也就是你不一定每次都要将归档文件中的全部文件都解归档。

列举归档文件内容

列举归档文件的内容也是tar非常使用的功能,也就是你可以在不解归档的情况下查看一个归档文件中有哪些文件。列举归档文件内容的命令行参数就是-t/t/--list(这个缩写也很奇怪,为什么不是-l呢?)。例如,如果要列举出刚才的test.tar文件中的内容可以使用下面三种形式中的一种。

tar tf test.tar
tar -tf test.tar
tar --list --file test.tar

向归档文件中追加文件

向归档文件中追加文件将会是我介绍的最后一个归档文件的常用功能,这个功能允许你向一个现有的归档文件中添加新的文件。向归档文件中追加文件的命令行参数是-r/r/--append(这个缩写更是没法解释orz)。例如,如果要向刚才的test.tar文件中添加一个c.txt可以使用下面三种形式中的一种。这个命令的位置参数的含义和-c一样

tar rf test.tar c.txt
tar -rf test.tar c.txt
tar --append --file test.tar c.txt
注意,如果你追加的文件和归档文件中的某个文件同名,使用-c选项追加之后你再列举归档文件的内容,你会发现其中有两个同名的文件,这是因为这两个文件都被被包含在了归档文件中。但是如果你尝试解归档这个文件,你会发现最终只有一个文件,这是因为在解归档的时候,先被添加的文件会先被解归档然后被后添加的同名文件覆盖。如果你想要在追加文件的时候就直接更新归档文件中原本就存在的同名文件,请使用-u/u/--update参数。

其他常用参数

另外,tar还有其他几个也比较常用的参数。我在下面简单列举一下。 1. -v/v/--verbose: 给出详细信息。(在不同的操作中,列出的详细信息也不同) 2. -z/z/--gzip: 在归档或者解归档的同时使用gzip程序进行压缩或解压缩。虽然我们说tar只是归档工具,但是它同时附带了gzip, bzip2, xz等压缩工具,所以也提供了在归档的同时压缩的功能。上述三种工具最常用,经过它们的压缩处理之后的程序后缀一般使用.tar.gz/.tar.bz2/.tar.xz,你可能也见过。 3. -j/j/--bzip2: 类似上一个,但是使用bzip2作为压缩工具。 4. -J/J/--xz: 类似上一个,但是使用xz作为压缩工具。 5. -a/a/--auto-compress: 类似上面,但是使用输入文件的后缀名来自动推测要使用的压缩工具。

info

我建议你在任何涉及tar的操作中都加上-v选项,这样你可以时刻查看你的操作细节,来确保你没有操作错误。

上面我们已经看到了,tar的种种选项的缩写都让人感到迷惑,因此tar命令也总是给人很难用的印象。以至于我们有下面这张十分有名的梗图。 tar梗图

最常用的压缩工具——zip(还有unzip)

前面介绍了主要作为归档工具的tar,那么接下来我自然也要介绍一个主要作为压缩工具的zip。虽然你可能会觉得,这个工具的名字和前面提到过的gzip很像,但是实际上zipgzip用到的压缩算法之间截然不同。不过,我们这里也不会详细介绍zip的压缩算法,因为这个内容比较复杂并且也和我们的主题关系不大。那么下面我就主要介绍一下zip工具的常见用法。在使用zip之前,你需要先安装,因为这个软件通常不是Linux发行版自带的。你可以使用下面的命令或者使用其他你的发行版的默认包管理器进行安装。

apt install zip

压缩

压缩工具要能压缩(✍✍✍)。所以我们来介绍一下zip的压缩命令。zip命令的基础用法就是直接就是直接将一些文件归档并压缩。命令如下,

zip test.zip a.txt b.txt
其中zip命令末尾的位置参数中,第一个是压缩文件的路径,后面的若干个都是被压缩的文件的路径。在压缩过程中-r选项也十分常用。如果你要压缩的文件中包含文件夹,需要使用-r选项表示递归地压缩文件夹里的所有内容。这和之前遇到的大部分其他命令的-r选项含义类似。

解压缩

tar不太一样的地方是,如果你想要解压缩zip文件,你需要另一个命令unzip。你不需要额外安装unzip,因为通常它会随着zip一起被安装。不过你也可以单独安装unzip而不用安装zipunzip的使用方法也很简单,直接在后面加上你要解压的文件路径即可。例如,

unzip test.zip

列举压缩文件内容

使用unzip你也可以很轻松地列举压缩文件的内容。只需要使用使用-l选项即可,例如,

unzip -l test.zip

修改压缩文件的内容

zip当然也支持修改压缩文件的内容,例如添加新的文件,删除已有的文件,更新其中的文件等。但是用到的命令行选项比较复杂,所以请大家自己查看文档或者询问AI即可。

其他有用的参数

下面列举几个其他我认为有用的zip的参数。 1. -@:这是一个很特别的参数。它表示让zip从标准输入流中读取要压缩的文件的文件名列表。也就是你可以使用其他命令得到你要压缩的文件的文件名有哪些然后使用管道直接传给zip。(当然,其实也可以使用xargs来实现这个功能,后面我们会介绍)

例如,

find . -name test?.txt | zip -@ test.zip
这个命令表示查找当前文件夹下符合模式test?.txt文件并添加到压缩文件test.zip中。

  1. -:和其他一些命令一样,你可以使用-来表示从标准输入中读取要压缩文件或者将压缩文件输出到标准输出中。注意,和上面不一样的是zip test.zip -表示是从标准输入读取内容并压缩到test.zip中,而不是从标准输出中读取文件名然后将对应的文件添加到压缩文件中。实际上下面两个命令作用相同
    find . -name test?.txt | zip -@ test.zip
    find . -name test?.txt | xargs cat | zip test.zip -
    
    另外,zip - -可以被简写成zip,这个命令的作用相当于一个过滤器,将标准输入压缩后输出到标准输出。

使用tar复制文件

在这一章的最后,我来介绍一个有关tar命令的神奇小技巧。

第六章中,我们曾经介绍过,可以使用cp命令来复制文件。这里我将给大家介绍一种全新的复制文件的方式,简单来说就是利用tar命令将文件归档之后,使用管道传给另一个tar命令来解归档。也就是下面两个命令的作用相同,他们都可以将./test文件夹完整复制到./test1文件夹中。

cp -r ./test ./test1/test
tar cf - ./test | ( cd ./test1 && tar xf - )

那么,肯定有人要问,既然我有cp了,为什么还要使用tar来进行复制呢?这是因为这种复制的方式对于文件数量较大的情况速度会比cp更快。根据我的测试,在固态硬盘(SSD)上,复制100,000个4KB大小随机数据的文件时,使用上面的tar命令会比cp(GNU coreutils 8.32)用时少4%~6%。

小结

这一章介绍了归档和压缩文件的命令。同时,我相信大家应该也学会了区分归档和压缩的不同。最后,我还介绍了一个很有趣的使用tar命令来复制文件的用法。这个用法很有趣并且在大量小文件存在的时候还可能有更高的性能。