IBM的LPI复习资料之LPI101-Topic103 :GNU和Unix命令(3)文件和目录管理

引言:你可能已经听说过在Linux中一切皆是文件,所以一定要打好基础,把文件和目录的管理如查找、列出、移动、复制、打包等学扎实。本文针对LPI 101考试,当然读者也可以为了兴趣来学习。

摘要:本文介绍几本的文件和目录管理命令,具体有

  • 列举目录中文件
  • 复制、移动或者删除文件和目录
  • 迭代操作多个文件和目录
  • 使用通配符
  • 使用find命令,根据文件类型、大小或者时间来查找定位文件
  • 使用gzip和bizp2来压缩和解压文件
  • 使用tar,cpio,dd来打包文件
本文帮助你为LPI-1的103.2复习,本部分权重是4。

列举目录中的文件

所有Linux和Unix中的文件都是从一个单根树状文件系统中获得,这个文件系统的为一个的根就是/。可以使用mount挂载更多的文件到这个树上,也可以使用unmount卸载树上的已有文件。

列举目录包含的项

本文中,我们将使用前一篇文章中创建的文件来做实验。

文件和目录的路径可以是绝对路径(以/开头),也可以是相对路径(相对于当前工作目录)。绝对路径以/开头,后面是目录的名称,目录之间使用/分隔。

给定一个文件或目录的相对路径,则当前工作目录的绝对路径/相对路径 就是文件或目录的绝对路径了。例如当前工作目录的绝对路径是 /home/ian,已知目录的相对路径是lpi103-2,则其绝对路径就是 /home/ian/lpi103-2。

使用pwd命令可以打印出当前的工作目录。有时候环境变量PWD也代表当前工作目录。下图展示了使用pwd命令,以及三种不同的方式来使用ls来列举目录中的文件。

[root@localhost lpi103-2]# pwd
/root/lpi103-2
[root@localhost lpi103-2]# ls
msg  sedtab  text1  text2  text3  text5  text6  xaa  xab  yaa  yab
[root@localhost lpi103-2]# ls $PWD
msg  sedtab  text1  text2  text3  text5  text6  xaa  xab  yaa  yab
[root@localhost lpi103-2]# ls /root/lpi103-2/
msg  sedtab  text1  text2  text3  text5  text6  xaa  xab  yaa  yab

可以看出,ls的参数可以是绝对路径,也可以是相对路径。

列举详细信息

在一个存储设备中,一个文件或者目录是被存放到被称为block的多个存储单元中的。一个文件的元信息则存放到inode中,它记录了文件的属主、修改时间、大小、是否是目录、读写权限等。inode号也被叫做文件序列号,在一个特定的文件系统中它是唯一的。我们可以使用-l选项(或者--format=long)来显示这些元信息。

默认情况下,ls不会显示以文件名.开头的文件。除了根目录,其他每个目录中至少有两个这样的文件:一个是目录本身(.),另一个是父目录(..)。根目录没有父目录。

下图展示了使用-l 和 -a选项来显示元信息以及以.开头的特殊文件。

[root@localhost lpi103-2]# ls -al
total 92
drwxr-xr-x   2 root root  4096 May  7 17:29 .
dr-xr-x---. 10 root root  4096 May  7 15:47 ..
-rw-r--r--   1 root root 43851 May  7 15:38 msg
-rw-r--r--   1 root root     8 May  7 17:14 sedtab
-rw-r--r--   1 root root    24 May  7 14:29 text1
-rw-r--r--   1 root root    25 May  7 14:48 text2
-rw-r--r--   1 root root    63 May  7 16:07 text3
-rw-r--r--   1 root root    24 May  7 16:41 text5
-rw-r--r--   1 root root    98 May  7 17:29 text6
-rw-r--r--   1 root root    15 May  7 15:15 xaa
-rw-r--r--   1 root root     9 May  7 15:15 xab
-rw-r--r--   1 root root    17 May  7 15:16 yaa
-rw-r--r--   1 root root     8 May  7 15:16 yab

上图第一行显示了列出的所有文件所占用的block数量。接下来的行报告了每个文件的情况。
  • 第一列报告了文件的类型以及权限。第一个字符表示文件的类型,其中d表示目录,-表示一般文件,-l表示符号链接,还有很多其他特殊的文件类型。接下来的9个字符被分成三组,每组三个字符。三个分组分别表示文件属主、同组用户、其他用户对文件的读、写、执行权限。
  • 第二列表示文件的硬链接数。我们说过,inode包含了文件的元信息。目录中的每一个项都包含了一个指向inode的指针,所以每一个文件至少有一个硬链接。对于目录来说,其自身又包含了表示自己的.,再加上父目录中对它的硬链接,所以至少有2个硬链接,又因为每个子目录中还有一个..来链接父目录,所以每增加一个子目录,父目录的硬链接数也就加1。如上图中/root共有10个硬链接。
  • 第三列第四列分别表示文件属主和属主的主分组,在一些如RedHat的系统中,每个用户默认有一个独立的分组,但是其他系统中可能不是这样。
  • 第五列是文件的长度,以字节为单位。
  • 倒数第二列,表示文件最后修改时间。
  • 最后一列是文件名。
ls -i 会显示文件的inode号。

[root@localhost lpi103-2]# ls -i
1839215 msg     1839209 text1  1839189 text3  1839219 text6  1839212 xab  1839214 yab
1839218 sedtab  1839210 text2  1839216 text5  1839211 xaa    1839213 yaa

(译者注:硬链接就是目录中存放的inode号,一个inode号在多少个目录中出现,就是有多少个硬链接。没有被硬链接了的inode,也就无法访问了,对应的文件也就相当于被删除了,上一个不严格的图帮助理解一下)

同时列举多个目录或文件

ls 可以同时接受多个文件或目录作为参数。对于目录名,ls默认会读取目录的内容然后列出每个项的元信息,而不是列出目录本身的元信息。可以使用-d选项来改变这种默认方式。如下:

[root@localhost lpi103-2]# ls -ld ../lpi103-2 sedtab xaa
drwxr-xr-x 2 root root 4096 May  7 17:29 ../lpi103-2
-rw-r--r-- 1 root root    8 May  7 17:14 sedtab
-rw-r--r-- 1 root root   15 May  7 15:15 xaa

排序输出结果

默认情况下,ls按照文件名排序输出。ls提供了很多选项来控制输出的排序,例如-t 是按照修改时间(最新修改在前)排序,-lS 则按照大小排序, -r则倒转排序先后。例如 -lrt会按照修改时间排序,并且最新修改的在最后输出。更多地选项参考man手册页。


复制、移动、删除文件

我们已经学会了一些创建文件的方法,那么如何复制、重命名、移动、或者删除文件呢?这要用到三个很短的命令:

  • cp 用于复制一个或多个文件或者目录。必须提供源和目的参数,源或目的参数可以包含路径。如果目标是一个存在的目录,那么所有的源都将复制到这个目录下。如果目标是一个不存在的目录, 那么源也必须是目录,然后一个源目录的拷贝就会产生,名称为目标名称。(译者注:在CentOS6中实验,结果不是这样)如果目标是文件,那么源也必须是文件,然后源文件的一份拷贝就会产生,并且以目标名为新名称,如果目标文件存在,则覆盖之。与DOS和Windows不同,这里的目标参数必须提供,不存在默认的目标参数。
  • mv 用于重命名或者移动一个或多个文件及目录。其规则与cp类似。因为文件名字只是其所在目录的一个项的属性,所以改名并不会影响inode编号。但是跨文件系统移动时,inode将会改变,因为这要靠复制然后删除原来的文件来实现。
  • rm 用于删除一个或者多个文件。后面我们会讨论删除目录的问题。

下面的实验使用了cp和mv来备份我们的文件,也使用了ls -i来显示文件的节点信息。

[root@localhost lpi103-2]# cp text1 text1.bkp
[root@localhost lpi103-2]# mkdir backup
[root@localhost lpi103-2]# cp text1 backup/text1.bkp.2
[root@localhost lpi103-2]# ls -i text1 text1.bkp backup/
1839209 text1  1839220 text1.bkp

backup/:
1839222 text1.bkp.2
[root@localhost lpi103-2]# mv text1.bkp backup
[root@localhost lpi103-2]# mv backup/text1.bkp backup/text1.bkp.1
[root@localhost lpi103-2]# ls -i text1 text1.bkp backup
ls: cannot access text1.bkp: No such file or directory
1839209 text1

backup:
1839220 text1.bkp.1  1839222 text1.bkp.2

  1. 复制text1,得到副本text1.bkp
  2. 使用mkdir创建了一个用于备份的子目录
  3. 复制了text1的另外一个副本到backup目录中,然后显示了这三份同样的文件其对应的inode编号各不相同
  4. 然后移动text1.bkp到了backup目录中,并且重新命名为text1.bkp.1
  5. 然后核实了inode编号为1839220的text1.bkp文件已经不再存在lpi103-2中,inode编号不变,名称改变了的text1.bkp.1存到了backup目录中。
正常情况下,如果目标文件存在,那么cp将会覆盖之。而mv却不会。 可以通过选项来控制cp 和 mv的覆盖行为。

  • -f 或者 --force 导致cp会尝试覆盖掉目标文件,即使目标文件不可写。
  • -i 或者 --interactive 在覆盖目标之前,提示用户确认。
  • -b或者 --backup 会在覆盖目标之前,把目标先备份。
还是那句话,详细的选项参数请参考man手册页。

[root@localhost lpi103-2]# cp text2 backup
[root@localhost lpi103-2]# cp --backup=t text2 backup
cp: overwrite `backup/text2'? y
[root@localhost lpi103-2]# ls backup/
text1.bkp.1  text1.bkp.2  text2  text2.~1~

注意rm命令也支持-i和-f选项。当你使用rm删除了一个文件,那么文件系统将不能再访问它。有些系统默认为root用户设置了 alias rm = 'rm -i' ,来防止误删除操作。

结束本节之前,我们强调一下:cp会为目标文件创建一个新的时间戳。目标文件的属主和组也被设置为运行cp命令的用户以及组。可以使用-p选项来保持源的某些元信息。但是只有root用户才能保留文件的属主信息(译者注:这也是为了安全,否则就可以伪造文件作者了)。

创建和删除目录

我们已经使用mkdir创建目录了。本节我们深入学习mkdir和rmdir。

mkdir

假设我们在lpi103-2目录下,想要创建两个子目录dir1和dir2。和其他命令一样,mkdir也可以同时创建多个目录。如下:

[root@localhost lpi103-2]# mkdir dir1 dir2
[root@localhost lpi103-2]# ls
backup  dir1  dir2  msg  sedtab  text1  text2  text3  text5  text6  xaa  xab  yaa  yab

注意mkdir的成功执行并不会有任何的输出。当然你可以通过echo $?来确认退出码确实是0。

如果我们想要创建一个层级嵌套的子目录,例如 d1/d2/d3,这将会失败,因为d1和d2目录并不存在。幸运的是mkdir有一个-p选项来自动创建所需的父目录,如下:

[root@localhost lpi103-2]# mkdir d1/d2/d3
mkdir: cannot create directory `d1/d2/d3': No such file or directory
[root@localhost lpi103-2]# echo $?
1
[root@localhost lpi103-2]# mkdir -p d1/d2/d3
[root@localhost lpi103-2]# echo $?
0

rmdir

与创建目录相反,rmdir用来删除目录。同样也存在一个-p选项来删除父目录。rmdir只能用来删除空目录。

为了演示目录删除,我们复制text1文件到d1/d2目录下。然后我们使用rmdir来删除前面使用mkdir创建的所有目录。我们看到d1和d2没有被删除,因为d2不是空目录。其他的目录被删除了。当我们从d2中删除了text1后,就可以使用rmdir -p 来删除d1和d2。

[root@localhost lpi103-2]# cp text1 d1/d2/
[root@localhost lpi103-2]# rmdir -p d1/d2/d3 dir1 dir2
rmdir: failed to remove directory `d1/d2': Directory not empty
[root@localhost lpi103-2]# ls ./d1/d2
text1
[root@localhost lpi103-2]# rm d1/d2/text1 
rm: remove regular file `d1/d2/text1'? y
[root@localhost lpi103-2]# rmdir -p d1/d2
[root@localhost lpi103-2]# 

处理多个文件和目录

到目前为止,我们操作的都是一个文件或者是一组单个文件。本文接下来将会讨论处理多个文件的操作。包括递归操作目录树,保存或者恢复多个文件及目录。

递归操作

  • 递归列举
 
 
ls 使用-R选项来列出一个目录及其子目录。递归选项只作用于目录名。例如他不会找到所有的叫做text1的文件(译者注:没弄懂什么意思)。如下所示:
[root@localhost lpi103-2]# ls -iR
.:
1839221 backup  1839218 sedtab  1839210 text2  1839216 text5  1839211 xaa  1839213 yaa
1839215 msg     1839209 text1   1839189 text3  1839219 text6  1839212 xab  1839214 yab

./backup:
1839220 text1.bkp.1  1839222 text1.bkp.2  1839224 text2  1839223 text2.~1~


  • 递归复制
[root@localhost lpi103-2]# cp -pR . copy1
cp: cannot copy a directory, `.', into itself, `copy1'
[root@localhost lpi103-2]# ls -R
.:
backup  copy1  msg  sedtab  text1  text2  text3  text5  text6  xaa  xab  yaa  yab

./backup:
text1.bkp.1  text1.bkp.2  text2  text2.~1~

./copy1:
backup  msg  sedtab  text1  text2  text3  text5  text6  xaa  xab  yaa  yab

./copy1/backup:
text1.bkp.1  text1.bkp.2  text2  text2.~1~

  • 递归删除
前面我们说过rmdir只能删除空目录。我们可以使用rm -r来递归删除文件和目录。下面展示了删除刚才创建的copy1目录及其所有子目录和文件。

[root@localhost lpi103-2]# rm -rf copy1
[root@localhost lpi103-2]# ls -R
.:
backup  msg  sedtab  text1  text2  text3  text5  text6  xaa  xab  yaa  yab

./backup:
text1.bkp.1  text1.bkp.2  text2  text2.~1~
[root@localhost lpi103-2]# 

如果有些文件你没有写权限,你可能需要使用-f来强制删除。

通配符和文件名替代


有时候,我们需要操作多个文件系统对象,但不是一个目录树下。例如,我们要找到所有的文本文件的修改时间,但不包括分片文件。这对于我们的lpi103-2是非常容易的,但是对于大的文件系统来说就困难多了。

要解决这个问题,就要使用bash内建的通配符支持。这种支持也叫做“globbing",因为最初的实现就是一个叫做glob的程序。让我们通过通配符指定多个文件吧!

任何包括'?',‘*‘,’[‘的字符串都叫做通配模式。替代过程就是shell或者其他的程序扩展这下跌通配模式为匹配这些模式的路径名列表。匹配过程是这样的:

  • ? 匹配任何单个字符
  • * 匹配任何字符串,包括空字符串
  • [ 引入一个字符类,一个字符类是一个非空字符串,以']'结尾。匹配[]中的任何一个字符都可以。这里有一些特殊情况:
(1)*和?匹配他们自身。如果文件名使用了这些字符,注意引号和转义。
(2)因为字符串必须非空,并且以]结尾,你必须首先放置]。
(3)-可以用来表示范围,如[0-9a-fA-F]表示任何大写或者小写的十六进制数字。如果想使用-自身,则把他放到最开始或者最后。
(4)!放到第一位时,表示范围的取反,不在第一位则表示其自身。注意shell本身也使用!表示历史命令,所以使用的时候要注意转义。

注意:通配符模式和正则表达式模式有些共同点,但是不完全相同,一定要小心!!!(译者注:其中一个区别是,通配符模式自动含有开始和结尾标志)

文件名替代针对每一个路径名独立进行。你不能匹配/也不能在范围中包含。

[root@localhost lpi103-2]# echo odd1>'text[*?!1]'
[root@localhost lpi103-2]# echo odd2>'text[2*?!]'
[root@localhost lpi103-2]# ls
backup  msg  sedtab  text1  text[*?!1]  text2  text[2*?!]  text3  text5  text6  xaa  xab  yaa  yab
[root@localhost lpi103-2]# ls text[2-4]
text2  text3
[root@localhost lpi103-2]# ls text[!2-4]
text1  text5  text6
[root@localhost lpi103-2]# ls text*[2-4]*
text2  text[2*?!]  text3
[root@localhost lpi103-2]# ls text*[!2-4]*
text1  text[*?!1]  text[2*?!]  text5  text6
[root@localhost lpi103-2]# ls text*[!2-4]
text1  text[*?!1]  text[2*?!]  text5  text6
[root@localhost lpi103-2]# echo text*>text10
[root@localhost lpi103-2]# ls *\!*
text[*?!1]  text[2*?!]
[root@localhost lpi103-2]# ls tex?[[]*
text[*?!1]  text[2*?!]
[root@localhost lpi103-2]# rm tex?[[]*
rm: remove regular file `text[*?!1]'? y
rm: remove regular file `text[2*?!]'? y
[root@localhost lpi103-2]# ls *b*
sedtab  xab  yab

backup:
text1.bkp.1  text1.bkp.2  text2  text2.~1~
[root@localhost lpi103-2]# ls backup/*2
backup/text1.bkp.2  backup/text2
[root@localhost lpi103-2]# ls -d .*

注意:
1 取反和*在一起的时候对导致一些奇怪的现象。模式*[!2-4]匹配一个文件名没有2,3,4跟随的最长部分。
2 与前面ls的例子一样,如果模式扩展结果是一个目录名,并且没有使用-d选项,那么这个目录的内容将会被列举。
3 如果文件名以.开始,那么必须显式的匹配。

记住命令行上的任何通配符都会被shell扩展,这将会导致不希望的结果。更糟糕的是,如果你指定的模式不匹配任务文件系统对象,POSIX标准要求原始的模式字符串作为参数传递给命令。有些早期的实现版本会传递一个空列表给命令,所以你可能一些老脚本可能会导致非预期的结果。如下:

[root@localhost lpi103-2]# echo text*
text1 text10 text2 text3 text5 text6
[root@localhost lpi103-2]# echo "text*"
text*
[root@localhost lpi103-2]# echo text[[\!?]z??
text[[!?]z??

更深入的学习路径名替代,使用man 7 glob。需要使用分节号,因为在section 3中也有 glob库的内容。理解各种shell的通配符工作方式的最好方法就是动手实验。在cp,mv,特别是rm命令上使用通配符之前,要先使用ls来测试通配符的工作情况。

触摸文件

现在我们来学习touch命令,它被用来更新文件的获取和修改时间,也用来创建空文件。在后面我们将学习如何利用这些信息查找文件和目录。学习使用指定时间戳的各种方法。

touch

不带任何选项的touch命令,接受一个或多个文件名作为参数,然后更新这些文件的的修改时间。下面例子中,我们使用echo创建了一个小文件f1,然后使用ls -l显示文件的修改时间。然后人使用sleep命令等待60秒,再运行ls -l,注意文件的时间戳改变了1分钟。

[root@localhost lpi103-2]# echo xxx>f1; ls -l f1; sleep 60; touch f1; ls -l f1
-rw-r--r-- 1 root root 4 May  8 16:50 f1
-rw-r--r-- 1 root root 4 May  8 16:51 f1

如果为touch 指定的文件名对应的文件不存在,那么touch将会创建这个文件,除非使用-c或者--nocreate选项。如下:

[root@localhost lpi103-2]# touch f2; touch -c f3; ls -l f*
-rw-r--r-- 1 root root 4 May  8 16:51 f1
-rw-r--r-- 1 root root 0 May  8 16:53 f2

touch也可应把文件的修改时间设置为特定的时间。这通过 -d 或者 -t 来指定。-d 是个非常灵活的选项,能接受各种格式的参数,-t 则需要至少 MMDDhhmm的时间和可选的年和秒。如下:

[root@localhost lpi103-2]# touch -t 198111261212.59 f3
[root@localhost lpi103-2]# touch -d 11am f4
[root@localhost lpi103-2]# touch -d "last fortnight" f5
[root@localhost lpi103-2]# touch -d "yesterday 6am" f6
[root@localhost lpi103-2]# touch -d "2 days ago 12:00" f7
[root@localhost lpi103-2]# touch -d "tomorrow 02:00" f8
[root@localhost lpi103-2]# touch -d "5 Nov" f9
[root@localhost lpi103-2]# ls -lrt f*
-rw-r--r-- 1 root root 0 Nov 26  1981 f3
-rw-r--r-- 1 root root 0 Apr 24 16:57 f5
-rw-r--r-- 1 root root 0 May  6 12:00 f7
-rw-r--r-- 1 root root 0 May  7 06:00 f6
-rw-r--r-- 1 root root 0 May  8 11:00 f4
-rw-r--r-- 1 root root 4 May  8 16:51 f1
-rw-r--r-- 1 root root 0 May  8 16:53 f2
-rw-r--r-- 1 root root 0 May  9  2013 f8
-rw-r--r-- 1 root root 0 Nov  5  2013 f9

如果你不确定一个日期表达式到底表示的是什么时间,你可以使用date命令来查看。date 也接受-d选项,解释方式与touch相同。

你还可以使用-r(或者--reference)选项来引用其他文件的修改时间。如下:

[root@localhost lpi103-2]# date 
Wed May  8 17:02:57 CST 2013
[root@localhost lpi103-2]# date -r f1
Wed May  8 16:51:50 CST 2013
[root@localhost lpi103-2]# touch -r f1 f1a
[root@localhost lpi103-2]# ls -l f1*
-rw-r--r-- 1 root root 4 May  8 16:51 f1
-rw-r--r-- 1 root root 0 May  8 16:51 f1a

Linux系统会同时记录文件的访问时间和修改时间。通常使用atime和mtime这两个术语表示。当文件刚被创建时,这两个时间戳被设置为同一个值,当文件被修改时,这两个值同时被更新。当一个文件仅仅被访问时,atime被更新,mtime则不变。在最后一个touch的例子中,我们将会看看atime。

[root@localhost lpi103-2]# cat f1
xxx
[root@localhost lpi103-2]# ls -lu f1*
-rw-r--r-- 1 root root 4 May  9 09:34 f1
-rw-r--r-- 1 root root 0 May  8 16:51 f1a
[root@localhost lpi103-2]# touch -a -r f1a f1
[root@localhost lpi103-2]# ls -lu f1*
-rw-r--r-- 1 root root 4 May  8 16:51 f1
-rw-r--r-- 1 root root 0 May  8 16:51 f1a

首先使用cat来访问f1文件,这样f1的atime就被更新了,然后使用touch的-a选项来设置f1的atime与f1a的atime一致,最后查看修改的结果。

关于其他的日期时间的格式,请参考touch 和 date的man手册页。

查找文件

前面我们介绍了文件和目录操作的两大重量级工具:递归像一个大锤子来选择所有文件和目录,通配符这个大锤子则带来更加灵活的选择。现在我们来学习find这个命令,它更像是一个外科手术刀。find被用与在一个或多个目录中根据像文件名、时间戳、大小等来查找文件。

find

find命令在指定的目录中根据全部或部分文件名或者其他的属性如大小、类型、属主、创建时间、访问时间等来搜索文件。最基本的搜索时根据文件名或者部分文件名。下面例子中,我们首先在lpi103-2文件夹中搜索文件名中含有1或者k的文及,然后执行一些路径搜索,后面会有解释。

[root@localhost lpi103-2]# find . -name "*[1k]*"
./f1
./text10
./backup
./backup/text2.~1~
./backup/text1.bkp.1
./backup/text1.bkp.2
./f1a
./text1
[root@localhost lpi103-2]# find . -ipath "*ACK*1"
./backup/text1.bkp.1
[root@localhost lpi103-2]# find . -ipath "*ACK*/*1"
./backup/text1.bkp.1

说明:

  1. 这里使用的模式与shell的通配符模式完全相同;
  2. -path用于指定用于匹配的不是文件名本身,而是整个路径名;
  3. -i则是忽略大小写
  4. 如果想搜索以.开头的文件或目录,如.bashrc或者当前目录.,那么模式的开头必须是一个.,否则这些文件会被忽略。
在上面的第一个例子中,我们既找到了文件,也找到了目录。使用-type用来限制查找的类型。 f表示常规文件,d表示目录文件,l表示符号链接,还有其他的类型请参考find的man手册页。下面的例子中,使用了-type d 来搜索目录。

[root@localhost lpi103-2]# find . -type d
.
./backup
[root@localhost lpi103-2]# find . -type d -name "*"
.
./backup

注意,-type d不带任何参数时,会显示以.开头的文件,与通配符"*"一样。

我们还可以根据文件大小查找,可以是等于、大于、或者小于指定的大小。通过使用大小的上下边界,我们可以查找其大小在某一范围的文件。默认情况下-size使用的大小单位是512个字节的block。可以指定c(字节),k(千字节)。下面例子中,我们首先查找大小为0的所有的文件,然后查找大小为24或25字节的文件。注意-empty 和 -size 0的作用相同。

[root@localhost lpi103-2]# find . -size 0
./f8
./f6
./f9
./f2
./f5
./f1a
./f4
./f7
./f3
[root@localhost lpi103-2]# find . -size +23c -size -26c -print
./backup/text2.~1~
./backup/text1.bkp.1
./backup/text1.bkp.2
./backup/text2
./text2
./text1
./text5

在第二个命令中,我们使用了-print选项,这是对搜索的结果进行的操作。在bash中,如果没有指定操作,则print就是默认的操作。在其他的系统或shell中,操作是必须的,否则不会有任何输出。

其他的操作包括-ls,其输出信息格式与ls -lids相同, -exec会对查找到的每一个文件执行指定的命令。-exec必须以;结尾,因为shell也使用;这个字符,所以请先转义它。使用{}来引用find的查找结果,{}也是shell的特殊字符,所以也需要转义或者用引号包围起来。看例子吧:

root@localhost lpi103-2]# find . -size -26c -size +23c -ls
1839223    4 -rw-r--r--   1 root     root           25 May  8 14:58 ./backup/text2.~1~
1839220    4 -rw-r--r--   1 root     root           24 May  8 14:40 ./backup/text1.bkp.1
1839222    4 -rw-r--r--   1 root     root           24 May  8 14:41 ./backup/text1.bkp.2
1839224    4 -rw-r--r--   1 root     root           25 May  8 14:58 ./backup/text2
1839210    4 -rw-r--r--   1 root     root           25 May  7 14:48 ./text2
1839209    4 -rw-r--r--   1 root     root           24 May  7 14:29 ./text1
1839216    4 -rw-r--r--   1 root     root           24 May  7 16:41 ./text5
[root@localhost lpi103-2]# find . -size -26c -size +23c -exec ls -l '{}' \;
-rw-r--r-- 1 root root 25 May  8 14:58 ./backup/text2.~1~
-rw-r--r-- 1 root root 24 May  8 14:40 ./backup/text1.bkp.1
-rw-r--r-- 1 root root 24 May  8 14:41 ./backup/text1.bkp.2
-rw-r--r-- 1 root root 25 May  8 14:58 ./backup/text2
-rw-r--r-- 1 root root 25 May  7 14:48 ./text2
-rw-r--r-- 1 root root 24 May  7 14:29 ./text1
-rw-r--r-- 1 root root 24 May  7 16:41 ./text5

-exec选项的能力超出你的想象,例如:

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

删除所有当前目录下的空文件。

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

把所有.htm文件修改为.html文件。

最后一个关于find的例子中,我们将会利用文件的时间戳来定位文件。

[root@localhost lpi103-2]# find . -mtime -2 -type f -exec ls -l '{}' \;
-rw-r--r-- 1 root root 0 May  9 02:00 ./f8
-rw-r--r-- 1 root root 8 May  7 15:16 ./yab
-rw-r--r-- 1 root root 0 Nov  5  2013 ./f9
-rw-r--r-- 1 root root 9 May  7 15:15 ./xab
-rw-r--r-- 1 root root 43851 May  7 15:38 ./msg
-rw-r--r-- 1 root root 0 May  8 16:53 ./f2
-rw-r--r-- 1 root root 4 May  8 16:51 ./f1
-rw-r--r-- 1 root root 17 May  7 15:16 ./yaa
-rw-r--r-- 1 root root 52 May  8 16:10 ./text10
-rw-r--r-- 1 root root 25 May  8 14:58 ./backup/text2.~1~
-rw-r--r-- 1 root root 24 May  8 14:40 ./backup/text1.bkp.1
-rw-r--r-- 1 root root 24 May  8 14:41 ./backup/text1.bkp.2
-rw-r--r-- 1 root root 25 May  8 14:58 ./backup/text2
-rw-r--r-- 1 root root 98 May  7 17:29 ./text6
-rw-r--r-- 1 root root 0 May  8 16:51 ./f1a
-rw-r--r-- 1 root root 25 May  7 14:48 ./text2
-rw-r--r-- 1 root root 0 May  8 11:00 ./f4
-rw-r--r-- 1 root root 24 May  7 14:29 ./text1
-rw-r--r-- 1 root root 24 May  7 16:41 ./text5
-rw-r--r-- 1 root root 8 May  7 17:14 ./sedtab
-rw-r--r-- 1 root root 63 May  7 16:07 ./text3
-rw-r--r-- 1 root root 15 May  7 15:15 ./xaa
[root@localhost lpi103-2]# find . -daystart -mtime -2 -type f -exec ls -l '{}' \;
-rw-r--r-- 1 root root 0 May  9 02:00 ./f8
-rw-r--r-- 1 root root 0 Nov  5  2013 ./f9
-rw-r--r-- 1 root root 0 May  8 16:53 ./f2
-rw-r--r-- 1 root root 4 May  8 16:51 ./f1
-rw-r--r-- 1 root root 52 May  8 16:10 ./text10
-rw-r--r-- 1 root root 25 May  8 14:58 ./backup/text2.~1~
-rw-r--r-- 1 root root 24 May  8 14:40 ./backup/text1.bkp.1
-rw-r--r-- 1 root root 24 May  8 14:41 ./backup/text1.bkp.2
-rw-r--r-- 1 root root 25 May  8 14:58 ./backup/text2
-rw-r--r-- 1 root root 0 May  8 16:51 ./f1a
-rw-r--r-- 1 root root 0 May  8 11:00 ./f4
[root@localhost lpi103-2]# find . -mmin -600 -mmin +60  -type f -exec ls -l '{}' \;
-rw-r--r-- 1 root root 0 May  9 02:00 ./f8

  1. 当使用-mtime -2时,find命令会查找最近2天(48小时内)修改的文件。一天就是相对于当前时间的24小时。如果想根据访问时间而不是修改时间,那么使用-atime代替-mtime。
  2. 当使用-daystart时,则表示是按照日历的天来算的,而不是相对当前时间的24小时。
  3. 最后例子中,我们查找的时在过去60分钟-600分钟之内修改过的文件。

识别文件

文件名通常由一个后缀,如.gif,.jpeg,.html等,这用来暗示文件的类型。Linux不需要这样的后缀,并且通常也不使用它们来是被文件类型。文件的类型决定了查看或操作它的程序。file命令用来识别一个或者多个文件的类型。看例子:

[root@localhost lpi103-2]# file backup/ text1 f2 ../music/wee-willie-winkie.mp3 /bin/echo
backup/:                        directory
text1:                          ASCII text
f2:                             empty
../music/wee-willie-winkie.mp3: Audio file with ID3 version 2.3.0, contains: 
/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命令来确认文件是否为空或者是目录;然后根据文件中的“魔数”来识别文件类型;最后的语言测试用来确定文本文件是否是一个xml,C或者C++源程序、troff文件、或者其他程序设计语言的源文件。这三个步骤依次执行,一旦有一个步骤识别成功了,就会停止并报告结果,除非指定了-k或者--keep-going选项。

file有许多的选项,请参考man手册页。下面例子使用了-i或者--mime选项来把文件的类型显示为MIME字符串,而不是一般的供人类阅读的文本。

[root@localhost lpi103-2]# file -i backup/ text1 f2 ../music/wee-willie-winkie.mp3 /bin/echo
backup/:                        application/x-directory; charset=binary
text1:                          text/plain; charset=us-ascii
f2:                             application/x-empty; charset=binary
../music/wee-willie-winkie.mp3: application/octet-stream; charset=binary
/bin/echo:                      application/x-executable; charset=binary

file命令也会管理“魔数”,同样需要读者自行参考man手册页。

注意:ImageMagic包里还有一个identity命令,它用来识别图像文件,能够给出更多的图像文件信息。

压缩文件

当备份或者移动文件时,通常需要压缩。Linux中有两个常用的压缩命令,gzip和bzip2,其中gzip使用的是Lempel-Ziv压缩算法,而bzip2使用的是Burrows-Wheeler块排序算法。

使用gzip和gunzip


压缩通常在文本文件上工作的很好。很多图像文件已经是压缩过的了,所以再对其进行压缩的效果往往不好。为了演示压缩一个适当大小的文件,我们复制/etc/services到我们的目录中,并且使用gzip压缩。我们使用了cp -p来保持文件的时间戳。注意压缩后的文件与压缩前的文件使用相同的时间戳,并且以.gz为后缀。

[root@localhost lpi103-2]# cp -p /etc/services .
[root@localhost lpi103-2]# ls -l serv*
-rw-r--r-- 1 root root 641020 Oct 15  2012 services
[root@localhost lpi103-2]# gzip services 
[root@localhost lpi103-2]# ls -l serv*
-rw-r--r-- 1 root root 127223 Oct 15  2012 services.gz

使用gzip的-d选项来解压文件,更经常使用的是gunzip命令。如下:

[root@localhost lpi103-2]# gzip -d services.gz 
[root@localhost lpi103-2]# ls -l serv*
-rw-r--r-- 1 root root 641020 Oct 15  2012 services

注意,解压后的文件与原始的文件有相同的文件名和时间戳。

使用bzip2和bunzip2

bzip2的使用方式与gzip类似。如下:

[root@localhost lpi103-2]# ls -l serv*
-rw-r--r-- 1 root root 641020 Oct 15  2012 services
[root@localhost lpi103-2]# bzip2 services
[root@localhost lpi103-2]# ls -l serv*
-rw-r--r-- 1 root root 115774 Oct 15  2012 services.bz2
[root@localhost lpi103-2]# bunzip2 services.bz2 
[root@localhost lpi103-2]# ls -l serv*
-rw-r--r-- 1 root root 641020 Oct 15  2012 services

gzip和bzip2的差异

在设计时,bzip2的很多选项都与gzip相同,但是并不是完全相同。你可能已经注意到了,两个例子中解压后的文件都与原始的文件具有相同的文件名和时间戳。但是重命名或者touch压缩文件后将会改变这种结果。gzip命令由一个-N或者--name选项来强制保持文件名和时间戳,但是bzip2没有。gzip还有个-l选项用来显示压缩文件以及解压后对应的文件名。下面的例子显示了gzip和bzip2的不同。

[root@localhost lpi103-2]# ls -l serv*
-rw-r--r-- 1 root root 641020 Oct 15  2012 services
[root@localhost lpi103-2]# gzip -N services
[root@localhost lpi103-2]# touch services.gz 
[root@localhost lpi103-2]# mv services.gz services-x.gz
[root@localhost lpi103-2]# ls -l serv*
-rw-r--r-- 1 root root 127223 May  9 11:15 services-x.gz
[root@localhost lpi103-2]# gzip -l services-x.gz 
         compressed        uncompressed  ratio uncompressed_name
             127223              641020  80.2% services-x
[root@localhost lpi103-2]# gzip -lN services-x.gz 
         compressed        uncompressed  ratio uncompressed_name
             127223              641020  80.2% services
[root@localhost lpi103-2]# gunzip -N services-x.gz 
[root@localhost lpi103-2]# ls -l serv*
-rw-r--r-- 1 root root 641020 Oct 15  2012 services
[root@localhost lpi103-2]# bzip2 services 
[root@localhost lpi103-2]# mv services.bz2 services-x.bz2
[root@localhost lpi103-2]# touch services-x.bz2 
[root@localhost lpi103-2]# ls -l serv*
-rw-r--r-- 1 root root 115774 May  9 11:17 services-x.bz2
[root@localhost lpi103-2]# bunzip2 services-x.bz2 
[root@localhost lpi103-2]# ls -l serv*
-rw-r--r-- 1 root root 641020 May  9 11:17 services-x
[root@localhost lpi103-2]# rm services-x # Don't need this any more

gzip和bzip2都能出标准输入中接受输入,都支持-c选项来直接向stdout输出。
对于bizp2还有其他两个命令:
  1. bzcat 压缩文件到标准输出,与bzip2 -dc相同;
  2. bzip2recover 尝试从损坏的bzip2文件中恢复数据。
更多关于gzip和bzip2的信息请参看man手册页。

其他压缩工具

compress和uncompress这两个老的程序,仍然在Linux和Unix系统中被经常使用。

除此之外,来自Info-Zip项目的zip和unzip命令也有Linux平台上的实现。这就为跨平台使用压缩功能提供了方便。注意并不是所有的操作系统都支持相同的文件元信息或者文件系统能力。如果你下载了一个研所的程序然后在Windows系统上解压,然后通过CD或DVD把文件转移到Linux上,这样你可能会在安装这个程序是出现问题,因为Windows操作系统不支持符号链接,而这却在原始的程序文件集合中被使用了。

更多地压缩工具,参看man手册页。

打包多个文件

tar, cpio, dd命令经常被用来备份一组文件、甚至整个分区,用于存档或者转移文件到另一个用户或站点。LPIC-2的201考试专注于备份的细节。

有三种通用的备份方式:

  1. 微分或累积备份。备份自上次完全备份以来发生变化的部分。恢复的时候,至少需要最后一个完全备份和最新的累积备份。
  2. 增量备份。备份自上次增量备份以来发生的变化部分。恢复的时候,需要最后一个完全备份,还有所有的增量备份(按顺序)。
  3. 完全备份。通常是整个文件系统或一组文件或目录的完整备份。这种方式需要的时间最长,所以它通常配合上面两种方式的一种来工作。
使用这三个命令,再加上前面学习的那些命令,就可以完成任何的备份任务。

使用tar

tar,名字来自于 Tape ARchive,用来从一组输入的文件或目录中创建一个归档文件或者叫做tarfile,tarball,也能从归档文件中恢复出原始文件。如果tar的输入是个目录,所有的子目录和文件都会被自动包含进来,这使得使用tar来归档一个目录树时非常方便。

tar的输出可以使一个文件、一个设备(如磁带或硬盘)或者是标准输出。输出通过-f选项来定位。其他的常用选项有:-c 创建一个归档文件;-x 从归档文件中抽取;-v 冗长的输出被处理的各个文件;-z使用gzip压缩;-j 使用bzip2压缩。大多数的tar命令选项有两种等价的格式,使用一个-开头的短格式和使用--开头的长格式。我们这里使用的时短格式。关于长格式、以及其他的选项请参考man手册页。

下面的例子展示了使用tar来备份我们的Lpi103-2目录。

[root@localhost lpi103-2]# tar -cvf ../lpitar1.tar .
./
./f8
./f6
./yab
./f9
./xab
./msg
./f2
./f5
./f1
./yaa
./text10
./backup/
./backup/text2.~1~
./backup/text1.bkp.1
./backup/text1.bkp.2
./backup/text2
./text6
./f1a
./text2
./f4
./text1
./text5
./sedtab
./f7
./text3
./xaa
./f3

通常我们想通过压缩归档文件来节省存储空间和传输时间。GUN版本的tar命令允许你通过-z来使用gzip来压缩,通过-b使用bzip2来压缩。下面例子展示了使用-z来压缩归档文件,以及压缩与不压缩版本的大小区别。

[root@localhost lpi103-2]# tar -zcvf ../lpitar3.tar ~/lpi103-2/
tar: Removing leading `/' from member names
/root/lpi103-2/
/root/lpi103-2/f8
/root/lpi103-2/f6
/root/lpi103-2/yab
/root/lpi103-2/f9
/root/lpi103-2/xab
/root/lpi103-2/msg
/root/lpi103-2/f2
/root/lpi103-2/f5
/root/lpi103-2/f1
/root/lpi103-2/yaa
/root/lpi103-2/text10
/root/lpi103-2/backup/
/root/lpi103-2/backup/text2.~1~
/root/lpi103-2/backup/text1.bkp.1
/root/lpi103-2/backup/text1.bkp.2
/root/lpi103-2/backup/text2
/root/lpi103-2/text6
/root/lpi103-2/f1a
/root/lpi103-2/text2
/root/lpi103-2/f4
/root/lpi103-2/text1
/root/lpi103-2/text5
/root/lpi103-2/sedtab
/root/lpi103-2/f7
/root/lpi103-2/text3
/root/lpi103-2/xaa
/root/lpi103-2/f3
[root@localhost lpi103-2]# ls -l ../lpitar*
-rw-r--r-- 1 root root 71680 May  9 13:26 ../lpitar1.tar
-rw-r--r-- 1 root root 13595 May  9 13:30 ../lpitar2.tar

本例还显示了tar的另一个重要特征。我们使用了目录的绝对路径,tar的输出的第一行告诉我们删除了开头的/。这就允许文件被恢复到其他的路径下,这对于恢复系统文件非常重要。入股哦你确实想要存储绝对路径,使用-p选项。在创建归档文件时一定要避免混淆绝对路径和相对路径,因为从归档文件恢复的时候都是采用相对路径。

tar命令的-r或--append选项可以向已有的归档文件中加入新的文件。这可能会导致一个文件的多份拷贝存在于归档文件中,在恢复的时候最后一个被恢复的拷贝将会覆盖前面的同名文件。你可以使用--occurrence选项来选择特定的文件来恢复。如果归档文件存放在一般的文件系统中而不是磁带上,你可以使用-u或者--update选项来更新归档文件。这与向归档文件中添加文件类似,只是归档文件中的文件时间戳会和文件系统中的文件时间戳进行比较,只有修改过的文件才会被添加到归档文件中。已经说过了,这对于磁带归档文件不起作用。

tar命令也用于比较归档文件和文件系统,以及从归档文件中恢复文件。使用-d或者--compare或者--diff选项来执行比较。输出会显示内容不同的文件,也会显示时间戳不同的文件。正常情况下,只有有差异的文件被列出来。使用-v选项来输出更相信的内容。 使用-C或者--directory选项来告诉tar在一个指定的目录中开始工作,否则默认是在当前目录下。

下例使用touch修改了f1的时间戳,然后在恢复之前比较归档文件。

[root@localhost lpi103-2]# touch f1
[root@localhost lpi103-2]# tar --diff --file ../lpitar1.tar .
./f1: Mod time differs
[root@localhost lpi103-2]# tar -df ../lpitar2.tar -C ./
./f1: Mod time differs
[root@localhost lpi103-2]# tar -xvf ../lpitar1.tar ./f1
./f1
[root@localhost lpi103-2]# tar --compare -f ../lpitar2.tar --directory ./

指定的要恢复的文件名必须匹配归档文件中德文件名。在本例中如果不是./f1而是f1的话,将不会工作。也可以使用通配符,但是要小心恢复的文件列表是否和你想要的完全一样。当不能确定归档文件里有什么文件时,你也可以使用-t或者--list选项来列出归档文件的内容。如下例:

[root@localhost lpi103-2]# tar -tf ../lpitar1.tar "*f1*"
./f1
./f1a

你可以使用find命令来选择要归档的文件,然后通过管道把结果传送给tar。我们将在讲解cpio命令的时候讨论这种技术,同样的方法也适用于tar。

使用cpio

cpio命令使用copy-out模式来创建归档文件,使用copy-in模式来恢复文件,使用copy-pass模式来复制一组文件到其他位置。使用-o或者--create选项表示copy-out模式,使用-i或者--extract选项来使用copy-in模式,使用-p或者--pass-through选项来使用copy-pass模式。输入是在标准输入中给出的文件列表,输出可以是标准输出或者是一个设备或者是通过-f或者--file选项指定的文件。

下面例子展示了使用find命令来产生文件列表,然后把结果通过管道传输给cpio。注意使用了find的-print0选项来产生0结尾的文件名字符串,同时使用cpio的--null选项来读取这种格式的字符串。这样一些包含空格或者换行符的文件名字也能正常工作。-depth选项告诉find先列出目录的内容,在列出目录自身。在本例中,我们简单地创建了lpi103-2目录的两个归档文件,一个使用了相对路径名,另一个采用了绝对路径名。我们没有使用find的更多能力来限制查找文件的结果,比如只选择本周修改的文件。

[root@localhost lpi103-2]# find . -depth -print0 | cpio --null -o > ../lpicpio.1
89 blocks
[root@localhost lpi103-2]# find ~/lpi103-2/ -depth -print0 | cpio --null -o > ../lpicpio.2
90 blocks

如果你想要查看归档文件的详细信息,使用cpio的-v选项。

cpio工作在copy-in模式时,可以列出归档文件中内容,以恶可以恢复选择的文件。

可以使用--absolute-filenames 选项来减少一些老版本cpio的输出消息,这些老版本的cpio会去掉开头的/。在许多现代版本的cpio中,这个选项将会被忽略。下面的例子有选择地列出归档文件中的文件列表。

[root@localhost lpi103-2]# cpio -i --list "*backup*"< ../lpicpio.1
backup/text2.~1~
backup/text1.bkp.1
backup/text1.bkp.2
backup/text2
backup
89 blocks
[root@localhost lpi103-2]# cpio -i --list absolute-filenames "*text1*" < ../lpicpio.2
/root/lpi103-2/text10
/root/lpi103-2/backup/text1.bkp.1
/root/lpi103-2/backup/text1.bkp.2
/root/lpi103-2/text1
90 blocks

下面例子中,展示了使用cpio来恢复"text1"到一个临时子目录中,与tar不同,你需要显式地指定一个-d或者--make-direcotories选项来创建这个子目录。另外,cpio不会使用归档文件中的文件覆盖文件系统中更新的同名文件,除非你使用了-u或者--unconditional选项。

[root@localhost lpi103-2]# mkdir temp
[root@localhost lpi103-2]# cd temp/
[root@localhost temp]# cpio -idv "*f1*" "*.bkp.1" <../../lpicpio.1
f1
backup/text1.bkp.1
f1a
89 blocks
[root@localhost temp]# cpio -idv "*.bkp.1" < ../../lpicpio.1
cpio: backup/text1.bkp.1 not created: newer or same age version exists
backup/text1.bkp.1
89 blocks
[root@localhost temp]# cpio -id --no-absolute-filenames "*text1*" < ../../lpicpio.2
cpio: Removing leading `/' from member names
90 blocks
[root@localhost temp]# cd ..
[root@localhost lpi103-2]# rm -rf temp

dd 命令

dd的最简单方式就是复制一个输入文件到一个输出文件。我们已经知道了cp命令,所以可能会质疑为什么还需要另外一个复制文件的命令呢?dd命令可以比cp做更多的事情。尤其是dd能够在文件上执行转换,比如把小写字符转换为大写字符,或者把ASCII编码转换为EDCDIC编码。dd还能够重组一个文件,这文件在转移到磁带之前是必须的。它还可以忽略或者只复制文件的指定的部分。最后,dd能够读写原始设备,比如/dev/sda,这可以用来备份和恢复整个磁盘分区。想设备写入通常需要root权限。

我们从使用conv选项来把文件中字符大写的小例子开始。我们使用 if选项来指定输入文件而不采用标准输入。类似,of选项用来指定输出目的来代替标准输出。为了演示,我们输入输出时采用了不同的块大小,这通过ibs和obs选项来指定。当在磁盘和磁盘之间传送数据的时候,使用大块来加速操作是非常方便的。此外,块大小通常用于磁带设备。最后三行是运行状态,显示了读写了多少个整块以及部分块,以及传送的全部数据大小。

[root@localhost 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
[root@localhost 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, 3.9944e-05 s, 2.5 MB/s

每一个文件都可以示原始设备。这通常会是一个磁带设备,也可能是一个磁盘分区如/dev/hda1或者/devs/da2,可以备份到磁带中或者一个文件中。理想的情况下,备份时设备上的文件系统应该被卸载或者至少是只读挂载的,这样才能确保备份的过程中数据不会发生改变。

下面的例子中,我们把/dev/sda6这个裸设备备份成/root/backup-1这个文件。如果是备份到磁带或者软盘上,则需要指定of=/dev/fd0或者of=/dev/st0。

[root@localhost ~]# dd if=/dev/sda6 of=backup-1
31248384+0 records in
31248384+0 records out
15999172608 bytes (16 GB) copied, 855.25 s, 18.7 MB/s
[root@localhost ~]# ll 
total 15624432
-rw-------.  1 root root        1033 Mar 27 11:12 anaconda-ks.cfg
-rw-r--r--   1 root root 15999172608 May  9 15:17 backup-1
[root@localhost ~]# df -h
Filesystem            Size  Used Avail Use% Mounted on
/dev/sda1              56G   18G   35G  34% /
tmpfs                 947M     0  947M   0% /dev/shm
/dev/sda5              74G   15G   56G  21% /data
/dev/sda6              15G  870M   14G   7% /work

注意dd复制了16GB的数据,并且输出的文件确实是这么大,尽管/dev/sda6这个分区,实际使用了7%的容量。除非采用硬件压缩的方式备份到磁带上,一般都需要压缩文件。下面例子显示了实现方法。

[root@localhost ~]# dd if=/dev/sda6 | gzip >backup-2
31248384+0 records in
31248384+0 records out
15999172608 bytes (16 GB) copied, 1549.11 s, 10.3 MB/s
[root@localhost ~]# ll back*
-rw-r--r-- 1 root root 15999172608 May  9 15:17 backup-1
-rw-r--r-- 1 root root 13400290321 May  9 15:55 backup-2


gzip使得文件大小减少了很多,但是由于分区中尚未使用的块中也可能包含任意数据,所以即使是压缩了的文件,其大小仍然远远大于分区中的实际使用部分。

如果用总的字节数除以记录数,你会发现dd使用的块大小是512个字节。当复制目的是一个像磁带这样的设备时,这将导致非常低效。前面我们说过可以通过obs和ibs分别指定输入和输出块的大小,也可以通过bs来为输入和输出指定同样的块大小。当使用磁带时,记住读取和写入的块大小要一致才行。

如果你需要多个磁带或者其他的移动设备来存放你的备份时,你需要使用split这样的工具来分割大文件。如果你需要忽略如磁盘和磁带的标签时,你可以使用dd做到,请参考man手册页。

dd命令对于文件系统一无所知,所以你需要恢复镜像文件到一个分区来查看里面的内容。下面例子演示了使用刚才创建的镜像文件来恢复一个分区,这个分区存在于一个移动硬盘上。

译者注:本实验译者没做,没找到合适的移动硬盘。

也许你对这样一个事实会感兴趣,那就是有些CD和DVD烧录程序底层实际上就是使用了dd来进行实际的设备写入操作。如果你使用的烧录程序提供一个实际执行命令的日志,既然我们已经知道了dd这个命令的一些知识,那么查看这些日志将会非常有意思。实际上,当你烧录一个ISO镜像文件到CD或者DVD光盘上时,一种检测烧录是否成功的方式就是使用dd来读取光盘的内容然后通过管道交由cmp命令来和镜像文件进行比较。下例展示了这种通用的技术,只是使用的文件是我们刚刚创建的备份文件而不是ISO镜像。注意我们使用备份文件的大小来计算要读取的块数量。


译者注:本实验译者没做,没找到合适的移动硬盘。



你可能感兴趣的:(IBM的LPI复习资料之LPI101-Topic103 :GNU和Unix命令(3)文件和目录管理)