Package Management and Processing
Linux的软件包管理系统
Linux发行版本质量最重要的决定因素是软件包管理系统和其支持社区的持久性。其中,软件包管理系统即Linux的打包系统,它负责从其支持的社区,即资源库(类似于手机上的软件商店)中搜索用户想要的软件包,并替用户完成从软件包到软件的安装。软件包管理系统通常由两种工具类型组成:
- 安装和删除软件包文件的底层工具;
- 在资源库中完成元数据、软件包搜索和依赖解析(软件很少是独立运行的,其运行过程中需要用到的其他软件就是它的依赖程序,某一软件包安装的同时也要确保依赖程序也被正确安装)的上层工具,其作用类似于Python的
pip
和conda
。
不同的Linux发行版本使用的软件包管理系统不尽相同,但是主流的基本都属于Debian的.deb
或Red Hat的.rpm
阵营:
包管理系统 | 底层工具 | 上层工具 | 发行版本 |
---|---|---|---|
Debian Style(.deb) | dpkg | apt, apt-get, apt-cache, aptitude | Ubuntu, Debian, Xandros, Linspire |
Red Hat Style (.rpm) | rpm | yum | CentOS, Fedora, Red Hat Enterprise Linux, OpenSUSE, Mandriva, PCLinuxOS |
Debian Style
当前的主流Linux发行版本,如Ubuntu、Debian,使用的都是Debian Style的包管理系统。相比于Red Hat Style的包管理系统,Debian Style的上层工具要更加多样,但也相应更加复杂。apt-get
和apt-cache
是最早的支持Debian包管理系统的上层工具;apt
包含了apt-get
和apt-cache
中最常用命令选项的集合,但是apt
本身要更加简洁;aptitude
功能更加全面,且在搜索上的表现优于apt
。一些常用的指令有:
1 | # 查找资源库软件包 |
事实上,在查找
search
、安装install
和更新upgrade
软件包时,上层工具都会去搜索软件包列表,软件包列表里包含了各类软件包的信息。但是,软件包列表会随时间变化,如添加新的包、删除旧的包等都会导致列表发生变化,而上层工具搜索的往往是软件包列表的缓存,因此,在进行前面的3项操作前,应先用apt-get update
或apt update
刷新软件包列表缓存。
search
所用到的[search_string]
可以是软件包的名字,也可以是软件包的说明信息。
aptitude
的指令名字与使用方式和其他3个基本一致。
通常,以指令调用上层工具后,上层工具会自动调用下层工具帮助我们完成后续的安装任务,不过有时我们可能会直接得到软件包.deb
文件,这时我们就可以直接使用底层工具来处理它们:
1 | # 通过软件包安装软件 |
需要注意的是,直接通过软件包安装文件时,底层工具不会帮助我们完成依赖解析,因此若其发现缺少了某个依赖程序,它会直接报错并退出。一旦发生这种情况,我们就需要手动地安装依赖程序。
apt
的全称是Advanced Packaging Tool,而dpkg
的全称是Debian Packager。
Red Hat Style
Red Hat Style的上层工具只有yum
:
1 | # 查找资源库软件包 |
同样地,Red Hat Style也支持用底层工具直接安装.rpm
文件:
1 | # 通过软件包安装软件 |
使用
rpm
直接安装软件包同样需要我们自己处理依赖程序。
yum
的全称是Yellow dog Updater, Modified,rpm
的全称是Red Hat Package Manager。
压缩,归档,备份
压缩包、文件包是另外两种常见的“包文件”。不像软件包是用于装载某个可执行程序的,它们是用于更好地存储、管理、归档和备份文件以保护重要数据的。
压缩文件
压缩(Zip、Compress),顾名思义就是通过压缩算法,使得计算机能以尽可能小的空间来存储未压缩文件。压缩算法分两大类:
- 无损压缩:无损压缩保留了原文件的所有数据。当还原一个被压缩文件时,还原文件将与原文件一模一样;
- 有损压缩:有损压缩允许压缩操作时删除一些数据,使得文件得到更大的压缩率。当一个有损压缩文件被还原时,它与原文件将存在差异。有损压缩一般用于少量的损失不影响原文件效果的文件,如图片、视频等。JPEG和MP3就是常见的有损压缩文件。
gzip
:强大的无损压缩程序
gzip
,全称GNUzip,是GNU计划实现的一款Linux系统常用的无损压缩程序。gunzip
则是其对应的解压程序。
1 | gzip [OPTION]... [FILE]... |
gzip
在执行压缩操作时,原文件会被压缩文件[FILE].gz
替代;解压时,[FILE].gz
又会被还原为原文件:
1 | [meme@localhost Playground]$ ls -l /etc | cat > foo.txt |
不难看出,压缩后的[FILE].gz
文件大小约为原文件的1/5。解压后的文件与原文件一模一样,包括权限、修改时间等。gzip
和gunzip
的[OPTION]
选项有很多,常用的有:
-c
:把程序输出写入到标准输出,并且保留原始文件。用在gzip
上会使得此次gzip
操作将压缩后的文件内容(一堆乱码)直接输出在标准输出上,而原文件不发生变化:用在1
2
3
4
5
6
7[meme@localhost Playground]$ ls
dir foo.txt
[meme@localhost Playground]$ sudo gzip -c foo.txt
�f�d
...
[meme@localhost Playground]$ ls
dir foo.txtgunzip
上会使得gunzip
直接输出解压后文件的内容,而并不解压文件:1
2
3
4
5
6
7
8[meme@localhost Playground]$ sudo gzip foo.txt
[meme@localhost Playground]$ ls
dir foo.txt.gz
[meme@localhost Playground]$ sudo gunzip -c foo.txt.gz
total 1424
...
[meme@localhost Playground]$ ls
dir foo.txt.gzzcat
(zip & cat)命令相当于使用了-c
的gunzip
。-d
:意为decompress,只用于gzip
,带-d
选项的gzip
作用相当于gunzip
。-f
:意为force,指强制压缩原文件,即便原始文件已经被压缩。-r
:意为recursive,若命令行中有一个或多个参数为目录,则递归地压缩目录中文件。
bzip2
:慢但更彻底的gzip
bzip2
与gzip
相似,但是使用了不同的压缩算法,使得bzip2
可以做到更高的压缩级别,但速度就稍微慢了一点。除了bzip2
的压缩文件名字后缀为.bz2
,bzip2
与gzip
的功能几乎一模一样,包括压缩文件替代原文件、除-r
以外的选项以及bunzip2
和bzcat
完成解压缩。
归档文件
相比于压缩文件包,我们更常见的是普通的文件包,即归档文件包,Windows上的.zip
文件包就是一种常见的归档文件包。所谓归档(Archive),即把一群文件捆绑成一个大的文件的过程。归档通常只是将目标文件群集中地放在一个归档文件包中,但有些归档程序,如zip
,还包含着压缩的功能。
tar
:经典Linux归档工具
tar
,全称Tape Archive,是Linux系统中最常用的归档工具。一个tar
包可以由一组独立的文件、一个或者多个目录或前两者的混合体组成。
1 | tar MODE[OPTION...] [PATH]... |
上边的MODE
指tar
的不同操作模式,常用的有:
c
:为文件、目录、目录列表创建归档文件;x
:抽取归档文件;r
:追加具体的路径到归档文件末尾;t
:列出归档文件的内容。
而常用的[OPTION]
有:
-f
:意为file,指定归档文件包的名字;-v
:意为verbose,显示命令的整个执行过程;-z
:意为gzip,对归档文件包使用gzip
压缩;-j
:意为bip2,对归档文件包使用bzip2
压缩。
一般来说,模式只能选择一个,而选项可以选择多个。确定了模式后,选项可以直接跟在模式后面,而无需用空格或
-
分割。
tar
包的后缀名为.tar
,经过gzip
压缩的tar
包后缀名为.tgz
,经过bzip2
压缩的tar
包后缀名为.tbz
。
在进一步了解tar
之前,我们先在当前目录下创建playground
目录,并在其下创建100个子目录,在每个子目录下创建24个普通文件:
1 | [meme@localhost Playground]$ mkdir -p ./playground/dir-{00{1..9},0{10..99},100} |
tar
一个很重要的特性是它在归档时保留了原文档的目录结构。如,若我们在当前目录下归档playground
文件夹:
1 | [meme@localhost Playground]$ ls |
使用tar tf
可以列出归档文件的内容,tar tvf
可以列出归档文件的详细内容:
1 | [meme@localhost Playground]$ tar tf playground.tar playground |
若我们使用同样的命令,但是将待归档文件夹的路径更改为其绝对路径,则其归档文件的结构也将是绝对路径的结构:
1 | [meme@localhost Playground]$ pwd |
我们不妨将playground.tar
和playground2.tar
用tar xf
同时提取在新建文件夹foo
中:
1 | [meme@localhost Playground]$ mkdir foo |
可见,playground.tar
和playground2.tar
内部的内容分别按相对路径和绝对路径的目录结构存储。对playground.tar
,是playground/
;对playground2.tar
则是home/meme/Playground/playground/
。这样的设计可以保证我们归档目录结构与原目录结构的完全统一,使得我们可以在任何地方抽取归档文件。比如,playground2.tar
就可以完全在另一台主机的根目录下抽取,使得其在新主机的路径仍为home/meme/Playground/playground
。
需要注意的是,tar xf
默认抽取所有文件,但是若其后面有指定的文件路径,则其只会抽取指定文件,如,此处我们先删除home
,再只从playground2.tar
中抽取一个目录dir-001
:
1 | [meme@localhost foo]$ ls |
在有些版本的Linux发行版中,在命令的
.tar
文件名后加入--wildcards
可以使得我们的路径能支持通配符,但是路径最好用引号引起。已抽出文件不会继承打包文件的权限,其只拥有将其抽出的用户的权限,也就是说,抽出文件的拥有者是抽取人,除非打包文件的是根用户。
与find
的结合
由于find
搜索指定文件夹中的文件时给出的搜索结果是相对于该文件夹的相对路径,因此tar
常常可以与find
结合使用,使得find
的搜索结果可以作为tar
的待归档文件,并用tar rf
直接在原归档文件的基础上增加新内容,如:
1 | [meme@localhost Playground]$ find playground -name 'file-A' |
将直接将所有的file-A
文件归档、增加至playground.tar
中。
与标准输入和输出结合
通常地,tar cf [FILE.tar] [PATH]
不会产生输出,而是直接生成FILE.tar
文件,但是,若我们将[FILE.tar]
替换为-
,则上述指令会将归档文件包以标准输出的形式输出;同样地,tar xf [FILE.tar]
不会接受输入,只会生成提取文件,而我们若将[FILE.tar]
替换为-
,则tar xf
会接受标准输入的输入:
1 | [meme@localhost foo]$ ls |
上述命令将tar cf
对../playground
的归档输出到-
标准输出中,该标准输出又被管道至tar xf
的-
标准输入,tar xf
将-
提取,于是我们就在当前文件夹得到父文件夹的playground
文件夹。
-
代替标准输入、输出的惯例被很多程序使用。
由此,前面find
与tar
的结合也可以通过管道|
进行:
1 | [meme@localhost Playground]$ ls |
-T
全称--file-from
,它将导致tar
从一个文件(此处为标准输出文件)而不是命令行中读入路径名,-T
后面的-
示意该文件为管道过来的标准输入文件。最终整个命令达到的效果就是将playground
中所有的file-A
文件归档。
-T-
可以用--file-from=-
代替。
.tgz
和.tbz
tar czf [FILE.tgz] [PATH]
和tar cjf [FILE.tbz] [PATH]
将分别把得到的.tar
文件一步压缩为.tgz
或.tbz
文件,此处不再赘述。
zip
:打包与压缩
zip
更常用于Windows系统中。相比于tar
,zip
兼具打包和压缩的功能。
1 | zip [OPTION] [ZIPFILE] [FILE] |
zip
的使用很简单,基本格式为包文件名+待打包文件路径,对于目录文件则要加上-r
选项,否则只有目录被存储:
1 | [meme@localhost Playground]$ ls |
上述指令将playground
中的dir-001
文件夹打包压缩为dir-001.zip
。值得注意的是,zip
有压缩功能,stored
后的百分比即表示压缩量。因为各个file-[A..Z]
文件均为空文件,所以没有压缩。
zip
的打包是更新式的打包而不是替代式的打包,也就是说,若已经存在了文件包xx.zip
,再以相同的名字xx.zip
打包某群文件不会再生成一个.zip
文件,而是在原xx.zip
文件包的基础上进行更新,如:
1 | [meme@localhost Playground]$ zip -r dir-001.zip playground/dir-002 |
dir-002
直接被加进了dir-001.zip
中,类似的操作在tar
中要指定r
模式。
上面用到的unzip
是与zip
对应的解压程序。unzip -l [FILE.zip] [PATH]
将只列出文件包内某文件的信息,[PATH]
缺省则列出所有。而去掉-l
则将从包中抽取所有或指定文件。
zip
也能结合标准输入输出,此处不再赘述。
同步与备份文件
同步与备份,即保持一个或多个目录与另一个本地或远程目录保持同步。常见的git
仓库就是一个这样的远程托管同步系统。在Linux中,更常被使用的同步备份工具是rsync
,全称Remote Synchronize。
1 | rsync [OPTION] SOURCE DESTINATION |
其中SOURCE
是待备份文件(可多个),而DESTINATION
是即将存储SOURCE
全部文件内容的文件夹,两者必须是下列3个选项之一且至少一个是本地文件/目录:
- 一个本地文件/目录;
- 一个远程文件/目录,以
[user@]host:path
的形式存在; - 一个远程rsync服务器,由
rsync://[user@]host[:port]/path
指定。
其中带
[]
的表示可选项,因此对于远程文件/目录,我们只要写上远程主机名host
以及存放目录path
;对于远程rsync服务器,我们只要写上远程服务器的主机名(url的形式)host
及其存放目录path
。
实际使用时,我们一般会用rsync -ac -delete
,其中-a
表示递归地备份并保护文件属性,-v
表示输出备份信息,-delete
表示删除备份设备中已经存在但是不存在于源设备中的文件。若SOURCE
和DESTINATION
中有一个为远程ssh主机,还要增加选项--rsh==ssh
。