Linux文件与目录管理

清单 13. 通配符模式异常
[ian@echidna lpi103-2]$ echo text*
text1 text10 text2 text3 text4 text5 text6
[ian@echidna lpi103-2]$ echo "text*"
text*
[ian@echidna lpi103-2]$ echo text[[\!?]z??
text[[!?]z??

有关 globbing 的更多信息,请查阅 man 7 glob。您将需要章节号,因为第 3 节中也介绍了 glob 信息。理解所有不同 shell 交互的最佳方式是进行实践,因此您需要多多尝试这些通配符。注意,在使用 cpmvrm 出现异常行为之前,使用 ls 检查您的通配符模式。

对文件执行 Touch 命令

我们现在来看看 touch 命令,它将更新文件访问和修改时间或创建空文件。在下一部分中,我们将探讨如何使用这些信息查找文件和目录。我们将继续在示例中使用 lpi103-2 目录。我们还将查看各种指定时间戳的方法。

touch

不包含任何选项的 touch 命令使用一个或多个文件名作为参数,并将更新文件的修改时间。这个时间戳通常会和一个长目录列表一同显示。在清单 14 中,我们使用 echo 创建了一个小文件 f1,然后使用一个长目录列表来显示修改时间(即 mtime)。在本例中,修改时间正好是文件的创建时间。我们随后使用 sleep 命令来等待 60 秒,并在此运行 ls。注意,该文件的时间戳已经修改了一段时间。

清单 14. 使用 touch 更新修改时间
[ian@echidna lpi103-2]$ echo xxx>f1; ls -l f1; sleep 60; touch f1; ls -l f1
-rw-rw-r--. 1 ian ian 4 2009-08-14 18:24 f1
-rw-rw-r--. 1 ian ian 4 2009-08-14 18:25 f1

如果为一个并不存在的文件指定文件名,那么 touch 通常会为您创建一个空文件,除非您指定了 -c--no-create 选项。清单 15 展示了这两个命令。注意,只有 f2 被创建。

清单 15. 使用 touch 创建空文件
[ian@echidna lpi103-2]$ touch f2; touch -c f3; ls -l f*
-rw-rw-r--. 1 ian ian 4 2009-08-14 18:25 f1
-rw-rw-r--. 1 ian ian 0 2009-08-14 18:27 f2

touch 命令还可以将文件的修改时间(也称为 mtime)设置为一个特定日期和时间,可以使用 -d-t 选项。-d 可以非常灵活地处理它将接受的日期和时间格式,而 -t 选项需要至少一个 MMDDhhmm 时间,年份和秒数是可选的。清单 16 展示了一些例子。

清单 16. 使用 touch 设置 mtime
[ian@echidna lpi103-2]$ touch -t 200908121510.59 f3
[ian@echidna lpi103-2]$ touch -d 11am f4
[ian@echidna lpi103-2]$ touch -d "last fortnight" f5
[ian@echidna lpi103-2]$ touch -d "yesterday 6am" f6
[ian@echidna lpi103-2]$ touch -d "2 days ago 12:00" f7
[ian@echidna lpi103-2]$ touch -d "tomorrow 02:00" f8
[ian@echidna lpi103-2]$ touch -d "5 Nov" f9
[ian@echidna lpi103-2]$ ls -lrt f*
-rw-rw-r--. 1 ian ian 0 2009-07-31 18:31 f5
-rw-rw-r--. 1 ian ian 0 2009-08-12 12:00 f7
-rw-rw-r--. 1 ian ian 0 2009-08-12 15:10 f3
-rw-rw-r--. 1 ian ian 0 2009-08-13 06:00 f6
-rw-rw-r--. 1 ian ian 0 2009-08-14 11:00 f4
-rw-rw-r--. 1 ian ian 4 2009-08-14 18:25 f1
-rw-rw-r--. 1 ian ian 0 2009-08-14 18:27 f2
-rw-rw-r--. 1 ian ian 0 2009-08-15 02:00 f8
-rw-rw-r--. 1 ian ian 0 2009-11-05 00:00 f9

如果您不确定某个日期表达式所表示的日期,那么可以使用 date 命令确定日期。它还接受 -d 选项并解析与 touch 相同的日历格式。

可以使用 -r(或 --reference)选项以及一个引用文件名 来表示 touch(或 date)应当使用现有文件的时间戳。清单 17 给出了一些示例。

清单 17. 引用文件的时间戳
[ian@echidna lpi103-2]$ date
Fri Aug 14 18:33:48 EDT 2009
[ian@echidna lpi103-2]$ date -r f1
Fri Aug 14 18:25:50 EDT 2009
[ian@echidna lpi103-2]$ touch -r f1 f1a
[ian@echidna lpi103-2]$ ls -l f1*
-rw-rw-r--. 1 ian ian 4 2009-08-14 18:25 f1
-rw-rw-r--. 1 ian ian 0 2009-08-14 18:25 f1a

Linux 系统同时记录文件修改 时间和文件访问 时间。这两个时间也分别被称为 mtimeatime。当文件被创建时,这两个时间戳均被设置为相同的值,在文件被修改时,两个值同时被重置。如果文件被访问过,那么访问时间将被更新,即使文件未被修改。对于我们的最后一个 touch例子,我们将查看文件访问 时间。-a(或 --time=atime--time=access--time=use)选项表示访问时间应该被更新。清单 18 使用 cat命令访问 f1 文件并显示其内容。我们随后使用 ls -lls -lu 分别显示 f1 和 f1a 的修改和访问时间,f1a 是使用 f1 作为引用文件创建的。我们随后使用 touch -a 将 f1 的访问时间重置为 f1a 的访问时间,然后检验它是否被重置。

清单 18. 访问时间和修改时间
[ian@echidna lpi103-2]$ ls -lu f1*
-rw-rw-r--. 1 ian ian 4 2009-08-14 18:39 f1
-rw-rw-r--. 1 ian ian 0 2009-08-14 18:25 f1a
[ian@echidna lpi103-2]$ ls -l f1*
-rw-rw-r--. 1 ian ian 4 2009-08-14 18:25 f1
-rw-rw-r--. 1 ian ian 0 2009-08-14 18:25 f1a
[ian@echidna lpi103-2]$ touch -a -r f1a f1
[ian@echidna lpi103-2]$ ls -lu f1*
-rw-rw-r--. 1 ian ian 4 2009-08-14 18:25 f1
-rw-rw-r--. 1 ian ian 0 2009-08-14 18:25 f1a

有关大量可用日期和时间规范的更多完整信息,请参考手册或信息页中有关 touchdate 命令的内容。

查找文件

现在我们已经介绍了文件和目录主题中的递归和 globbing 内容,递归涉及文件的所有方面,而 globbing 更具有针对性,让我们看看 find 命令,该命令更像是外科医生的手术刀。find 命令用于根据名称、时间戳或大小等条件查找一个或多个目录树中的文件。我们再一次使用 lpi103-2 目录。

find

find 命令将使用全名或部分名称搜索文件或目录,或者按照其他搜索条件搜索,例如大小、类型、文件所有者、创建日期或最近一次的访问时间。最基本的查找是按全名或部分名称查找。清单 19 展示了 lpi103-2 目录中的一个例子,我们将查找文件名中包含 '1' 或 'k' 的所有文件,然后执行一些路径搜索,下面的说明部分将加以解释。

清单 19. 按名称查找文件
[ian@echidna lpi103-2]$ find . -name "*[1k]*"
./f1a
./f1
./text10
./backup
./backup/text1.bkp.1
./backup/text1.bkp.2
./text1
[ian@echidna lpi103-2]$ find . -ipath "*ACK*1"
./backup/text1.bkp.1
[ian@echidna lpi103-2]$ find . -ipath "*ACK*/*1"
[

说明:

  1. 您可以使用 shell 通配符模式,比如前面 通配符和 globbing 小节中的模式。

  2. 可以使用 -path 代替 -name 来匹配完全路径而不是基本文件名。在本例中,模式可能跨越路径组件,这与普通通配符匹配不同,后者只匹配路径的某个部分。

  3. 如果希望进行不区分大小写的搜索,如前面的 ipath 所示,那么在搜索字符串或模式的 find 选项前面加一个 'i'。

  4. 如果希望搜索名称以点开头的文件或目录名,比如 .bashrc 或当前目录 (.),那么您必须将一个前导圆点指定为模式的一部分。否则,名称搜索将忽略这些文件或目录。

在上面的第一个例子中,我们查找所有文件和一个目录(./backup)。使用 -type 参数以及一个单字母类型来限制搜索。使用 'f' 表示普通文件,使用 'd' 查找目录,使用 'l' 查找符号链接。参考手册页,获得 find 的其他可能类型。清单 20 展示了只搜索目录的结果(-type d)和文件名(*,在本例中可为任何内容)搜索结果。

清单 20. 按类型搜索文件
[ian@echidna lpi103-2]$ find . -type d
.
./backup
[ian@echidna lpi103-2]$ find . -type d -name "*"
.
./backup

注意,-type d 不包含任何形式的名称指定,将显示在其名称中具有一个前导圆点的目录(在本例中只包括当前目录),和通配符 “*” 的作用相同。

我们还可以按照文件大小进行搜索,可以搜索具有指定大小的文件 (n),或者搜索文件大小大于 (+n) 或小于 (-n) 某个给定值的文件。通过使用上限和下限大小,我们可以查找大小在某个给定范围内的文件。默认情况下,find-size 选项假设包含 512 字节的块为一个单位,用 'b' 表示。此外,指定 'c' 表示字节,或指定 'k' 表示千字节。在清单 21 中,我们首先查找大小为 0 的所有文件,然后查找大小为 24 或 25 字节的所有文件。注意,指定 -empty 而不是 -size 0 也将查找空文件。

清单 21. 按大小查找文件
[ian@echidna lpi103-2]$ find . -size 0
./f1a
./f6
./f8
./f2
./f3
./f7
./f4
./f9
./f5
[ian@echidna lpi103-2]$ find . -size -26c -size +23c -print
./text2
./text5
./backup/text1.bkp.1
./backup/text1.bkp.2
./text1

清单 21 中的第二个例子引入了 -print 选项,它演示了一个可能会对搜索返回的结果执行的操作。在 bash shell 中,如果没有指定任何操作的话,那么这将是默认操作。在某些系统和 shell 中,需要指定一个操作;否则,不会生成输出。

其他操作包括 -ls(输出文件信息,与 ls -lids 命令的输出差不多)和 -exec(为每个文件执行一个命令)。-exec 必须以分号终止,必须对分号进行转义,以避免 shell 首先解释分号。如果希望在命令中使用返回的文件,还必须指定 {}。记住,花括号对于 shell 也是有意义的,因此必须进行转义(或引用)。清单 22 展示了如何使用 -ls-exec 选项列出文件信息。注意第二个表单没有列出 inode 信息。

清单 22. 查找和处理文件
[ian@echidna lpi103-2]$ find . -size -26c -size +23c -ls
933893    4 -rw-rw-r--   1 ian      ian            25 Aug 11 14:27 ./text2
933900    4 -rw-rw-r--   1 ian      ian            24 Aug 11 18:47 ./text5
934193    4 -rw-rw-r--   1 ian      ian            24 Aug 12 15:36 ./backup/text1.bkp.1
934195    4 -rw-rw-r--   1 ian      ian            24 Aug 12 15:36 ./backup/text1.bkp.2
933892    4 -rw-rw-r--   1 ian      ian            24 Aug 11 14:02 ./text1
[ian@echidna lpi103-2]$ find . -size -26c -size +23c -exec ls -l '{}' \;
-rw-rw-r--. 1 ian ian 25 2009-08-11 14:27 ./text2
-rw-rw-r--. 1 ian ian 24 2009-08-11 18:47 ./text5
-rw-rw-r--. 1 ian ian 24 2009-08-12 15:36 ./backup/text1.bkp.1
-rw-rw-r--. 1 ian ian 24 2009-08-12 15:36 ./backup/text1.bkp.2
-rw-rw-r--. 1 ian ian 24 2009-08-11 14:02 ./text1

-exec 选项可用于您能够想象到的所有用途。例如:

find . -empty -exec rm '{}' \;

删除目录树中的所有空文件

find . -name "*.htm" -exec mv '{}' '{}l' \;

将所有 .htm 文件重命名为 .html 文件。

在最后一个 find 例子中,我们使用由 touch 命令描述的时间戳来查找具有特定时间戳的文件。清单 23 给出了三个例子:

  1. 当用于 -mtime -2 时,find 命令将查找在最近两天以内修改的所有文件。在本例中,一天即指与当前日期和时间相关的 24 个小时。注意,如果您希望根据访问时间而不是修改时间查找文件,那么将使用 -atime

  2. 添加 -daystart 选项意味着我们希望使用日历计算天数,从午夜开始。现在,f3 已被排除在列表以外。

  3. 最后,我们将展示如何使用以分钟计算的时间范围而不是天数来查找在过去的 1 个小时(60 分钟)至 10 个小时(600 分钟)之间发生修改的文件。

清单 23. 按时间戳查找文件
[ian@echidna lpi103-2]$ date
Sat Aug 15 00:27:36 EDT 2009
[ian@echidna lpi103-2]$ find . -mtime -2 -type f -exec ls -l '{}' \;
-rw-rw-r--. 1 ian ian 0 2009-08-14 18:25 ./f1a
-rw-rw-r--. 1 ian ian 4 2009-08-14 18:25 ./f1
-rw-rw-r--. 1 ian ian 0 2009-08-13 06:00 ./f6
-rw-rw-r--. 1 ian ian 0 2009-08-15 02:00 ./f8
-rw-rw-r--. 1 ian ian 0 2009-08-14 18:27 ./f2
-rw-rw-r--. 1 ian ian 58 2009-08-14 17:30 ./text10
-rw-rw-r--. 1 ian ian 0 2009-08-14 11:00 ./f4
-rw-rw-r--. 1 ian ian 0 2009-11-05 00:00 ./f9
[ian@echidna lpi103-2]$ find . -daystart -mtime -2 -type f -exec ls -l '{}' \;
-rw-rw-r--. 1 ian ian 0 2009-08-14 18:25 ./f1a
-rw-rw-r--. 1 ian ian 4 2009-08-14 18:25 ./f1
-rw-rw-r--. 1 ian ian 0 2009-08-15 02:00 ./f8
-rw-rw-r--. 1 ian ian 0 2009-08-14 18:27 ./f2
-rw-rw-r--. 1 ian ian 58 2009-08-14 17:30 ./text10
-rw-rw-r--. 1 ian ian 0 2009-08-14 11:00 ./f4
-rw-rw-r--. 1 ian ian 0 2009-11-05 00:00 ./f9
[ian@echidna lpi103-2]$ find . -mmin -600 -mmin +60 -type f -exec ls -l '{}' \;
-rw-rw-r--. 1 ian ian 0 2009-08-14 18:25 ./f1a
-rw-rw-r--. 1 ian ian 4 2009-08-14 18:25 ./f1
-rw-rw-r--. 1 ian ian 0 2009-08-14 18:27 ./f2
-rw-rw-r--. 1 ian ian 58 2009-08-14 17:30 ./text10

find 命令的手册页可以帮助您了解各种选项,我们无法在这篇简短的介绍中一一介绍它们。

识别文件

文件名通常具有一个后缀,比如 gif、jpeg 或 html,它将告诉您文件中可能包含的内容。Linux 不需要这种后缀,因此通常不会使用它们来识别文件类型。了解正在处理的文件的类型将使您知道程序将使用什么工具显示或操作文件。file 命令将使您了解到一个或多个文件中的数据的类型。清单 24 展示了使用 file 命令的一些例子。

清单 24. 识别文件内容
[ian@echidna lpi103-2]$ file backup text1 f2 ../p-ishields.jpg /bin/echo
backup:            directory
text1:             ASCII text
f2:                empty
../p-ishields.jpg: JPEG image data, JFIF standard 1.02
/bin/echo:         ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically 
linked (uses shared libs), for GNU/Linux 2.6.18, stripped

file 命令尝试使用三种测试来对每个文件进行分类。比如,文件系统测试使用 stat 命令的结果来判断某个文件或目录是否为空。名为 magic的测试将检查文件中的特定内容,这些内容可以识别文件。这些签名也被称为魔术数字(magic number)。最后,语言测试将查看文本文件中的内容,尝试确定某个文件是 XML 文件、C 或 C++ 语言源文件、troff 文件,或是其他被认为是某些语言处理器的源文件。找到的第一种类型将被生成报告,除非 -k--keep-going 选项被指定。

file 命令具有许多选项,您可以通过手册页获得详细介绍。清单 25 展示了如何使用 -i(或 --mime)选项来将文件类型显示为 MIME 字符串,而不是普通的人类可读输出。

清单 25. 将文件内容识别为 MIME
[ian@echidna lpi103-2]$ file -i backup text1 f2 ../p-ishields.jpg /bin/echo
backup:            application/x-directory; charset=binary
text1:             text/plain; charset=us-ascii
f2:                application/x-empty; charset=binary
../p-ishields.jpg: image/jpeg; charset=binary
/bin/echo:         application/x-executable; charset=binary

魔术数字文件也由 file 命令管理。请在此查看手册页获得更多信息。

注意:作为 ImageMagick 包的一部分,identify 命令可以用作额外一种工具,为识别图像文件类型提供更多细节。

压缩文件

当您备份、归档或传输文件时,通常会对文件进行压缩。在 Linux 环境中,两个流行的压缩程序为 gzipbzip2gzip 命令使用 Lempel-Ziv 算法,而 bzip2 使用 Burrows-Wheeler 块分类算法。

使用 gzip 和 gunzip

压缩通常对文本文件比较有效。许多图像格式的文件已经进行了数据压缩,因此对这些或其他二进制文件进行压缩效果不大。为了演示对较大文本文件执行的压缩,让我们将 /etc/services 复制到我们一直使用的目录中,并使用 gzip 对它执行压缩,如清单 26 所示。我们使用 cp-p选项保留 /etc/services 的时间戳。注意,压缩后的文件具有相同的时间戳,并且具有一个 .gz 后缀。

清单 26. 使用 gzip 进行压缩
[ian@echidna lpi103-2]$ cp -p /etc/services
[ian@echidna lpi103-2]$ ls -l serv*
-rw-r--r--. 1 ian ian 630983 2009-04-10 04:42 services
[ian@echidna lpi103-2]$ gzip services
[ian@echidna lpi103-2]$ ls -l serv*
-rw-r--r--. 1 ian ian 124460 2009-04-10 04:42 services.gz

您使用 gzip-d 选项解压缩使用 gzip 压缩过的文件,更常见的是使用 gunzip 命令。清单 27 展示了第一种方法。注意,未压缩的文件现在具有原始名和时间戳。

清单 27. 使用 gzip 解压缩
[ian@echidna lpi103-2]$ gzip -d services.gz
[ian@echidna lpi103-2]$ ls -l serv*
-rw-r--r--. 1 ian ian 630983 2009-04-10 04:42 services

使用 bzip2 和 bunzip2

bzip2 命令以与 gzip 类似的方式运行,如清单 28 所示。

清单 28. 使用 bzip2 进行压缩
[ian@echidna lpi103-2]$ ls -l serv*
-rw-r--r--. 1 ian ian 630983 2009-04-10 04:42 services
[ian@echidna lpi103-2]$ bzip2 services
[ian@echidna lpi103-2]$ ls -l serv*
-rw-r--r--. 1 ian ian 113444 2009-04-10 04:42 services.bz2
[ian@echidna lpi103-2]$ bunzip2 services.bz2
[ian@echidna lpi103-2]$ ls -l serv*
-rw-r--r--. 1 ian ian 630983 2009-04-10 04:42 services

gzip 和 bzip2 之间的区别

根据设计,bzip2 的许多选项与 gzip 的选项是相似的,但是这两个命令不包含完全相同的选项。您可能已经注意到,在我们的两个例子中,未压缩的文件具有与原始文件相同的文件名和时间戳。然而,重命名或 touch 已压缩文件会改变这一行为。gzip 命令的 -N--name 选项会强制保留名称和时间戳,但是 bzip2 不会。gzip 命令还有一个 -l 选项,用于显示与已压缩文件有关的信息,包括将在解压缩时使用的名称。清单 29 解释了这两个命令之间的一些区别。

清单 29. gzip 和 bzip2 之间的区别
[ian@echidna ~]$ ls -l serv*
-rw-r--r--. 1 ian ian 630983 2009-04-10 04:42 services
[ian@echidna ~]$ gzip -N services
[ian@echidna ~]$ touch services.gz
[ian@echidna ~]$ mv services.gz services-x.gz
[ian@echidna ~]$ ls -l serv*
-rw-r--r--. 1 ian ian 124460 2009-09-23 14:08 services-x.gz
[ian@echidna ~]$ gzip -l services-x.gz
         compressed        uncompressed  ratio uncompressed_name
             124460              630983  80.3% services-x
[ian@echidna ~]$ gzip -lN services-x.gz
         compressed        uncompressed  ratio uncompressed_name
             124460              630983  80.3% services
[ian@echidna ~]$ gunzip -N services-x.gz
[ian@echidna ~]$ ls -l serv*
-rw-r--r--. 1 ian ian 630983 2009-04-10 04:42 services
[ian@echidna ~]$
[ian@echidna ~]$ bzip2 services
[ian@echidna ~]$ mv services.bz2 services-x.bz2
[ian@echidna ~]$ touch services-x.bz2
[ian@echidna ~]$ ls -l serv*
-rw-r--r--. 1 ian ian 113444 2009-09-23 14:10 services-x.bz2
[ian@echidna ~]$ bunzip2 services-x.bz2
[ian@echidna ~]$ ls -l serv*
-rw-rw-r--. 1 ian ian 630983 2009-09-23 14:10 services-x
[ian@echidna ~]$ rm services-x # Don't need this any more

gzipbzip2 都接受来自 stdin 的输入。两者都支持用 -c 选项将输出导出到 stdout。

bzip2 还有另外两个相关的命令。

  1. bzcat 命令将文件解压缩到 stdout,其作用等同于 bzip2 -dc

  2. bzip2recover 命令尝试从受损害的 bzip2 文件中恢复数据。

手册页将帮助您了解 gzipbzip2 的其他选项。

其他压缩工具

另外两个更旧一点的程序是 compressuncompress,它们仍然频繁出现在 Linux 和 UNIX 系统中。

此外,来自 Info-ZIP 项目的 zipunzip 命令也在 Linux 中得到了实现。它们提供了跨平台的压缩功能,可以广泛应用于各种硬件和操作系统。注意,并不是所有操作系统都支持相同的文件属性或文件系统功能。如果您下载用 zip 压缩过的产品文件并在 Windows 系统上解压缩它,然后将结果文件传输到 CD 或 DVD 中以用于 Linux 安装,您可能会遇到安装问题,原因在于,例如,Windows 系统不支持原始的未压缩文件集所含的符号链接。

有关这些或其他压缩程序的更多信息,请参考相关的手册页。

归档文件

tarcpiodd 命令被常用于备份文件组甚至是整个分区,目的是归档文件或传输到另外一个用户或站点。LPIC-2 认证中的考试 201 关注更加详细的备份事项。

有三种常用的备份方法:

  1. 差异累积 备份是指对自上一次完全备份之后发生更改的所有内容进行备份。要执行恢复,需要最近一次的完全备份和最新的差异备份。

  2. 增量 备份是指只对自上一次增量备份后发生变化的内容执行备份。要执行恢复,需要最近一次的完全备份以及这次完全备份之后的所有增量备份(按顺序)。

  3. 完全 备份是指一次完整的备份,通常为整个文件系统、目录或相关文件组。这种备份所需的时间是三种备份中最长的,因此通常与其他两种方法的其中一种结合使用。

这些命令以及本文中学习的其他命令为您提供了执行任何这些备份任务的工具。

使用 tar

tar(最初来自 Tape ARchive)从一组输入文件或目录中创建一个归档文件,即 tarfiletarball;它还从此类归档中恢复文件。如果某个目录被作为输入提供给 tar,所有文件和子目录都被自动包括,这使得 tar 可以非常方便地归档您的目录结构的子树。

输出可以被导入到文件、磁带或软盘之类的设备或是 stdout 中。输出位置使用 -f 选项指定。其他常见选项为:-c 用于创建归档,-x 用于提取归档,-v 用于详细输出,它将列出被处理的文件,-z 用于使用 gzip 压缩,而 -j 用于使用 bzip2 压缩。大部分 tar 选项包含使用一个连字符的简单格式和使用一对连字符的详细格式。这里解释了简单格式。参考手册页,获得有关详细格式和额外选项的内容。

清单 30 展示了如何使用 tar 创建 lpi103-2 目录的备份。

清单 30. 使用 tar 备份 lpi103-2 目录
[ian@echidna lpi103-2]$ tar -cvf ../lpitar1.tar .
./
./text3
./yab
...
./f5

您通常希望压缩归档文件来节省空间或减少传输时间。tar 命令的 GNU 版本允许您使用一个单个选项实现此目的 ―-z 表示使用 gzip 压缩,而 -b 表示使用 bzip2 压缩。清单 31 演示了 -z 选项的使用,以及两种归档文件在大小方面的差异。

清单 31. 使用 gzip 压缩 tar 归档
[ian@echidna lpi103-2]$ tar -zcvf ../lpitar2.tar ~/lpi103-2/
tar: Removing leading `/' from member names
/home/ian/lpi103-2/
/home/ian/lpi103-2/text3
/home/ian/lpi103-2/yab
...
/home/ian/lpi103-2/f5
[ian@echidna lpi103-2]$ ls -l ../lpitar*
-rw-rw-r--. 1 ian ian 30720 2009-09-24 15:38 ../lpitar1.tar
-rw-rw-r--. 1 ian ian   881 2009-09-24 15:39 ../lpitar2.tar

清单 31 还显示了 tar 的另外一个重要特性。我们使用了一个绝对目录路径,而输出的第一行告诉我们 tar 正在从成员名称中删除前导斜线 (/)。这允许将文件恢复到其他位置以进行检验,如果您尝试恢复系统文件的话,这一点尤其重要。如果您确实需要存储绝对名称,那么使用 -p选项。在创建归档时,避免将绝对路径名和相对路径名混在一起始终是一种好的想法,因为在从归档恢复时,所有名称都将为相对名称。

tar 命令可以使用 -r--append 选项将额外的文件附加到归档中。这会造成归档中出现文件的多个副本。在这种情况下,最后 一个文件将在恢复操作期间被恢复。您可以使用 --occurrence 选项从多个文件中选择一个特定文件。如果归档位于常规文件系统而非磁带中,那么可以使用 -u--update 选项来更新一个归档。这种工作方式类似于附加到一个归档,区别在于,归档中的文件的时间戳将与文件系统中的时间戳进行比较,并且只有在归档版本之后发生修改的文件被附加。如前所述,这不适用于磁带归档。

tar 命令也可以将归档与当前文件系统加以比较,并恢复来自归档的文件。使用 -d--compare--diff 选项执行比较。输出将显示内容有差异的文件,以及时间戳不同的文件。一般情况下,将只列出不同的文件(如果有的话)。使用前面讨论的 -v 选项获得详细输出。-C-- directory 选项将告诉 tar 从指定的目录开始执行操作,而不是从当前目录开始。

清单 32 展示了一些例子。我们使用 touch 来修改 f1 文件的时间戳,然后演示了 tar 的比较操作,之后从其中一个归档中恢复 f1。我们将使用各种操作来进行说明。

清单 32. 使用 tar 执行比较和恢复
[ian@echidna lpi103-2]$ touch f1
[ian@echidna lpi103-2]$ tar --diff --file ../lpitar1.tar .
./f1: Mod time differs
[ian@echidna lpi103-2]$ tar -df ../lpitar2.tar -C /
home/ian/lpi103-2/f1: Mod time differs
[ian@echidna lpi103-2]$ tar -xvf ../lpitar1.tar ./f1 # See below
./f1
[ian@echidna lpi103-2]$ tar --compare -f ../lpitar2.tar --directory /

您为恢复指定的文件或目录必须匹配归档中的名称。在本例中,如果尝试只恢复 f1 而不是 ./f1,那么将是无效的。您可以使用 globbing,但是需要注意不要恢复过多或过少的内容。如果您不确定归档内容的话,您可以使用 --list-t 选项来列出归档内容。清单 33 展示了一个通配符说明示例,它将恢复更多的文件,而不仅仅是 ./f1。

清单 33. 使用 tar 列出归档内容
[ian@echidna lpi103-2]$ tar -tf ../lpitar1.tar "*f1*"
./f1a
./f1

可以使用 find 命令选择要归档的文件,然后将结果传递给 tar。我们将在讨论 cpio 时探讨这种方法,但是同样的方法也可以用于 tar

和本文介绍的其他命令一样,这篇简要的介绍无法涵盖所有的选项。请参考手册页或信息页了解更多内容。

使用 cpio

cpio 命令在 copy-out 模式下创建归档,在 copy-in 模式下恢复归档,或在 copy-pass 模式下将一组文件从一个位置复制到另一个位置。您将对 copy-out 模式使用 -o--create 选项,对 copy-in 模式使用 -i--extract 选项,而对 copy-pass 模式使用 -p--pass-through 选项。输入是在 stdin 中提供的一组文件。输出被指向 stdout,或者是由 -f--file 选项指定的设备或文件。

清单 34 展示了如何使用 find 命令生成一组文件,并将列表传递给 cpio。注意,对 find 使用了 -print0 选项来为文件名生成 null-terminate 字符串,而 cpio 上的对应的 --null 选项将读取这个格式。这将正确地处理包含内嵌空格或换行符的文件名。-depth 选项告诉 find 在目录名的前面列出目录条目。在本例中,我们仅仅创建了 lpi103-2 目录的两个归档,一个使用相对名称,一个使用绝对名称。我们没有使用 find 的众多功能对所选文件进行限制,比如只查找在本周修改过的文件。

清单 34. 使用 cpio 备份目录
[ian@echidna lpi103-2]$ find . -depth -print0 | cpio --null -o > ../lpicpio.1
3 blocks
[ian@echidna lpi103-2]$ find ~/lpi103-2/ -depth -print0 | cpio --null -o > ../lpicpio.2
4 blocks

如果您希望按照归档顺序列出文件,那么对 cpio 添加 -v 选项。

copy-in 模式下的 cpio 命令(选项 -i--extract)可以列出归档的内容或恢复所选文件。当您列出文件时,指定 --absolute-filenames选项将减少无关消息的数量,较旧版本的 cpio 在从包含前导 / 字符的每个路径中分离该字符时会发出这些消息。该选项在许多最新实现中都被忽略。选择性列出前面的归档的输出如清单 35 所示。

清单 35. 使用 cpio 列出和恢复所选文件
[ian@echidna lpi103-2]$ cpio  -i --list  "*backup*" < ../lpicpio.1
backup
backup/text1.bkp.1
backup/text1.bkp.2
3 blocks
[ian@echidna lpi103-2]$ cpio  -i --list absolute-filenames "*text1*" < ../lpicpio.2/home/ian/lpi103-2/text10
/home/ian/lpi103-2/backup/text1.bkp.1
/home/ian/lpi103-2/backup/text1.bkp.2
/home/ian/lpi103-2/text1
4 blocks

清单 36 展示了如何将路径中含有 “text1” 的所有文件恢复到一个临时子目录中。其中一些文件位于子目录中。与 tar 不同,如果目录树不存在的话,您将需要明确地指定 -d--make-directories 选项。此外,cpio 不会使用归档副本替换文件系统中任何较新的文件,除非您指定了-u--unconditional 选项。

清单 36. 使用 cpio 恢复所选文件
[ian@echidna lpi103-2]$ mkdir temp
[ian@echidna lpi103-2]$ cd temp
[ian@echidna temp]$ cpio  -idv "*f1*" "*.bkp.1" < ../../lpicpio.1
f1a
f1
backup/text1.bkp.1
3 blocks
[ian@echidna temp]$ cpio  -idv "*.bkp.1" < ../../lpicpio.1
cpio: backup/text1.bkp.1 not created: newer or same age version exists
backup/text1.bkp.1
3 blocks
[ian@echidna temp]$ cpio  -id --no-absolute-filenames "*text1*" < ../../lpicpio.2cpio: Removing leading `/' from member names
4 blocks
./home/ian/lpi103-2/backup/text1.bkp.1
./home/ian/lpi103-2/backup/text1.bkp.2
./home/ian/lpi103-2/text1
./backup/text1.bkp.1
[ian@echidna temp]$ cd ..
[ian@echidna lpi103-2]$ rm -rf temp # You may remove these after you have finished

有关其他选项的更多细节,请参考手册页。

dd 命令

就其最简单形式而言,dd 命令将一个输入文件复制到一个输出文件。您已经了解过 cp 命令,因此您可能希望知道为什么还要用另外一个命令复制文件。dd 命令可以完成很多常规 cp 命令无法办到的事情。特别是,它可以对文件执行转换,比如将小写转换为大写,或将 ASCII 转换为 EBCDIC。它还可以重新阻塞(reblock)一个文件,当将文件传输给磁带时可能需要这样做。它还可以跳过或只包括所选的文件块。最后,它可以读取和写入原始设备,比如 /dev/sda,这允许您创建和恢复作为完整分区映像的文件。写入到设备通常需要根权限。

我们将首先来看一个使用 conv 将文件转换为大写的简单例子,如清单 37 所示。我们使用 if 选项指定输入文件,而不是使用默认的 stdin。类似的 of 选项可用于覆盖 stdout 默认输出。为了演示的目的,我们使用 ibsobs 选项指定了不同的输入和输出块大小。对于较大的文件,在进行磁盘之间的传输时,使用较大的块大小加速操作会比较方便。另外,块大小最常用于磁带。注意,清单末尾的三行状态代码表示有多少完整的和局部的块被读取和写入,以及被传输的数据的总量。

清单 37. 使用 dd 将文本转换为大写
[ian@echidna lpi103-2]$ cat text6
1 apple
2 pear
3 banana
9       plum
3       banana
10      apple
1 apple
2 pear
3 banana
9       plum
3       banana
10      apple
[ian@echidna lpi103-2]$ dd if=text6 conv=ucase ibs=20 obs=30
1 APPLE
2 PEAR
3 BANANA
9       PLUM
3       BANANA
10      APPLE
1 APPLE
2 PEAR
3 BANANA
9       PLUM
3       BANANA
10      APPLE
4+1 records in
3+1 records out
98 bytes (98 B) copied, 0.00210768 s, 46.5 kB/s

任何文件都可能是一个原始设备。这种情况通常出现在磁带中,但是一个完整的磁盘分区,比如 /dev/hda1 或 /dev/sda2,可以被备份到一个文件或磁带中。理想情况下,设备上的文件系统应当被解除挂载,或至少为只读挂载,从而确保数据在备份期间不会发生修改。清单 39 展示了一个示例,其中输入文件是一个原始设备 dev/sda3,而输出文件是位于根用户的主目录中的文件 backup-1。要将文件转储到磁带或软盘中,将进行 of=/dev/fd0of=/dev/st0 等指定。

清单 38. 使用 dd 备份分区
[root@echidna ~]# dd if=/dev/sda2 of=backup-1
1558305+0 records in
1558305+0 records out
797852160 bytes (798 MB) copied, 24.471 s, 32.6 MB/s

注意,797,852,160 字节的数据被复制,而输出文件也包含这么多的数据,即使实际上只会使用 3% 的分区。除非您使用硬件压缩将文件复制到磁盘,否则您将希望对数据进行压缩。清单 39 展示了实现此目的的一种方法,以及 lsdf 命令的输出,向您展示了文件的大小和 /dev/sda3 上的文件系统的使用百分比。

清单 39. 使用 dd 实现压缩备份
[root@echidna ~]# dd if=/dev/sda2 |gzip >backup-2
1558305+0 records in
1558305+0 records out
797852160 bytes (798 MB) copied, 23.4617 s, 34.0 MB/s
[root@echidna ~]# ls -l backup-[12]
-rw-r--r--. 1 root root 797852160 2009-09-25 17:13 backup-1
-rw-r--r--. 1 root root    995223 2009-09-25 17:14 backup-2
[root@echidna ~]# df -h /dev/sda2
Filesystem            Size  Used Avail Use% Mounted on
/dev/sda2             755M   18M  700M   3% /grubfile

gzip 压缩将文件大小减小到未压缩大小的 20%。然而,未使用的块可能包含任何数据,因此即使压缩过的备份也可能要比分区的总数据大。

如果按照处理的记录的数量对总字节进行划分,您将看到 dd 将写入多个包含 512 字节的数据块。当复制到磁带之类的原始输出设备中时,这将导致产生非常低效的操作。如前所述,指定 obs 选项来改变输出的大小,或用 ibs 选项来指定输入块大小。您还可以仅指定 bs 来将输入和输出块大小同时指定为一个常用值。在使用磁带时,记住使用相同的块大小来读取和写入磁带。

如果需要多个磁带或其他可移动存储来保存备份,那么需要使用 split 之类的工具将它们分为更小的部分。如果需要跳过磁盘或磁带标签之类的块,可以使用 dd 完成。参见手册页中的示例。

dd 命令无法被文件系统感知,因此需要恢复一个分区的转储才能知道分区的内容。清单 40 展示了如何将清单 39 中转储的文件恢复到分区 /dev/sdc,该分区创建在可移动 USB 驱动上,专门用于这个用途。

清单 40. 使用 dd 恢复分区
[root@echidna ~]# gunzip backup-2 -c | dd  of=/dev/sdc7
1558305+0 records in
1558305+0 records out
797852160 bytes (798 MB) copied, 30.624 s, 26.1 MB/s

您可能对一些使用 dd 命令在幕后执行实际的设备写入工作的 CD 和 DVD 刻录应用程序感兴趣。如果您使用的工具提供了大量实际使用的命令,并且您现在对 dd 有了更多的了解,那么您会发现查看日志会大有裨益。实际上,如果您将一个 ISO 映像刻录到一张 CD 或 DVD 磁盘,一种确定没有错误的方法就是使用 dd 回读磁盘并通过 cmp 工具传递结果。清单 41 使用我们在本文中创建的备份文件解释了这一常见技巧,而不是使用 ISO 映像。注意,我们使用映像的文件大小计算读取的块的数量。

清单 41. 比较映像和文件系统
[root@echidna ~]# ls -l backup-1
-rw-r--r--. 1 root root 797852160 2009-09-25 17:13 backup-1
[root@echidna ~]# echo $(( 797852160 / 512 )) # calculate number of 512 byte blocks
1558305
[root@echidna ~]# dd if=/dev/sdc7 bs=512 count=1558305 | cmp - backup-1
1558305+0 records in
1558305+0 records out
797852160 bytes (798 MB) copied, 26.7942 s, 29.8 MB/s


你可能感兴趣的:(linux,文件与目录管理)