现在我们已经准备好进行一些真正的工作了!本章将介绍以下命令:
cp
—— 复制文件和目录mv
—— 移动/重命名文件和目录mkdir
—— 创建目录rm
—— 删除文件和目录ln
—— 创建硬和符号链接这五个命令是最常用的Linux命令之一。它们用于操纵文件和目录。
现在,坦率地说,使用图形文件管理器可以更容易地完成这些命令执行的一些任务。使用文件管理器,我们可以将文件从一个目录拖放到另一个目录,剪切和粘贴文件,删除文件等等。那么为什么要使用这些旧的命令行程序呢?
答案是力量(power)和灵活性(flexibility)。虽然使用图形文件管理器很容易执行简单的文件操作,但使用命令行程序可以更容易地执行复杂的任务。例如,我们如何将所有HTML文件从一个目录复制到另一个目录,但只复制目标目录中不存在或比目标目录中的版本更新的文件?使用文件管理器很难,但使用命令行很容易:
xxxxxxxxxx
cp -u *.html destination
第四章:操作文件和目录通配符字符范围点文件通配符也可以在GUI中使用mkdir
——创建目录cp
——复制文件和目录有用的选项和示例mv
——移动和重命名文件有用的选项和示例rm
——删除文件和目录有用的选项和示例谨慎使用 rm
!ln
——创建链接硬链接符号链接创建游乐场创建目录复制文件移动和重命名文件创建硬链接创建符号链接删除文件和目录使用GUI创建符号链接总结
在开始使用命令之前,我们需要讨论一下使这些命令如此强大的shell功能。由于shell大量使用文件名,它提供了特殊字符来帮助我们快速指定文件名组。这些特殊字符称为通配符(wildcards)。使用通配符(也称为 globbing)允许我们根据字符模式选择文件名。
下表列出了通配符及其选择:
通配符 | 含义 |
---|---|
* | 匹配任何字符 |
? | 匹配任意单个字符 |
[characters] | 匹配属于 characters 集合的任何字符 |
[!characters] [^characters] | 匹配不属于 characters 集合的任何字符 |
[[:class:]] | 匹配属于指定 class (类)的任何字符 |
下表列出了最常用的字符类:
字符类 | 含义 |
---|---|
[:alnum:] | 匹配任何字母数字字符 |
[:alpha:] | 匹配任意字符字符 |
[:digit:] | 匹配任意数字 |
[:lower:] | 匹配任意小写字母 |
[:upper:] | 匹配任意大写字母 |
使用通配符可以为文件名构建复杂的选择标准。下表提供了一些模式及其匹配的示例:
模式 | 匹配 |
---|---|
* | 所有文件 |
g* | 所有以 g 开头的文件 |
b*.txt | 任何以 b 开头、后跟任何字符、以 .txt 结尾的文件 |
Data??? | 任何以 Data 开头,后跟三个字符的文件 |
[abc]* | 任何以 a 、b 或 c 开头的文件 |
BACKUP.[0-9][0-9][0-9] | 任何以 BACKUP. 开头,后跟三个数字的文件 |
[[:upper:]]* | 任何以一个大写字母开头的文件 |
[![:digit:]]* | 任何以非数字开头的文件 |
*[[:lower:]123] | 任何以小写字母或数字 1 、2 或 3 结尾的文件 |
通配符可以与任何接受文件名作为参数的命令一起使用,但我们将在 【第7章.Shell所见的世界】中对此进行更多讨论。
如果你来自另一个类Unix环境,或者一直在阅读关于这个主题的其他书籍,你可能会遇到[A-Z]和[a-z]字符范围符号。这些是传统的Unix符号,也适用于旧版本的Linux。它们仍然可以工作,但你必须小心,因为除非配置得当,否则它们不会产生预期的结果。目前,您应该避免使用它们,而是使用字符类。
如果我们使用 -a
选项查看带有 ls
的主目录,我们会注意到有许多文件和目录的名称以点开头。正如我们所讨论的,这些文件是隐藏的。这不是文件的特殊属性;这只意味着除非包含 -a
或 -A
选项,否则该文件不会出现在 ls
的输出中。这种隐藏特性也适用于通配符。除非我们使用通配符模式,否则隐藏文件不会出现,例如 .*.
。然而,当我们这样做时,我们也会看到两者 .
(当前目录)和 ..
(当前目录的父目录)。为了排除它们,我们可以使用以下模式 .[!.]*
或者 .??*
。
通配符特别有价值,不仅因为它们在命令行上使用频繁,而且因为它们也受到一些图形文件管理器的支持。
u
开头的所有文件,请在位置栏中输入 /usr/bin/u*
,它将显示结果。许多最初在命令行界面中发现的想法也进入了图形界面。这是使Linux桌面如此强大的众多因素之一。
mkdir
——创建目录mkdir
命令用来创建目录。它以如下方式工作:
mkdir directory ...
关于符号的注释:当命令描述中的参数后面有三个句点时(如上所述),这意味着参数可以重复,因此以下命令可以创建单个目录:
xxxxxxxxxx
mkdir dir1
而下面的目录可以创建三个目录,dir1 、dir2 、dir3 :
xxxxxxxxxx
mkdir dir1 dir2 dir3
cp
——复制文件和目录cp命令复制文件或目录。它可以用两种不同的方式。
以下内容将单个文件或目录 item1 复制到文件或目录 item2 :
cp item1 item2
以下内容将多个项目(文件或目录)复制到一个目录中:
cp item ... directory
下表列出了 cp
的一些常用选项:
选项 | 长选项 | 含义 |
---|---|---|
-a | --archive | 复制文件和目录及其所有属性,包括所有权和权限。 通常,副本具有执行副本的用户的默认属性。 我们将在 【第9章.权限】中查看文件权限。 |
-i | --interactive | 在覆盖现有文件之前,请提示用户进行确认。 如果未指定此选项, cp 将以静默方式(没有警告)覆盖文件。 |
-r | --recursive | 递归复制目录及其内容。 复制目录时需要此选项(或 -a 选项)。 |
-u | --update | 将文件从一个目录复制到另一个目录时,只复制目标目录中不存在或比现有相应文件更新的文件。 这在复制大量文件时非常有用,因为它会跳过不需要复制的文件。 |
-v | --verbose | 执行复制时显示信息性消息。 |
下表是 cp
的示例:
命令 | 结果 |
---|---|
cp file1 file2 | 将 file1 复制到 file2 。 如果 file2 存在,它将被 file1 的内容覆盖。 如果file2 不存在,则创建它。 |
cp -i file1 file2 | 与前面的命令相似,如果 file2 存在,在覆盖之前会询问用户。 |
cp file1 file2 dir1 | 将 file1 和 file2 复制到目录 dir1 中。目录 dir1 必须已经存在。 |
cp dir1/* dir2 | 使用通配符,将 dir1 中的所有文件复制到 dir2 中。 目录 dir2 必须已经存在。 |
cp -r dir1 dir2 | 将目录 dir1 的内容复制到目录 dir2 。 如果目录 dir2 不存在,则会创建它。 如果目录 dir2 存在,那么目录 dir1 中的内容将被复制到 dir2 中。 |
mv
——移动和重命名文件mv
命令执行文件移动和文件重命名,具体取决于它的使用方式。无论哪种情况,操作后原始文件名都不再存在。 mv
的使用方式与 cp
非常相似,如下命令将文件或目录 item1 重命名为 item2:
mv item1 item2
以下命令将一个或多个项目从一个目录中移动到另一个目录中:
mv item... directory
mv
与 cp
共享许多相同的选项,例如 -i
、 -u
、-v
。
下表是 mv
的示例:
命令 | 结果 |
---|---|
mv file1 file2 | 将 file1 移动到 file2 。 如果 file2 存在,它将被 file1 的内容覆盖。 如果 file2 不存在,则创建它。 无论哪种情况,命令完成后 file1 都将不存在。 |
mv -i file1 file2 | 与上面例子相似,但在覆盖之前会提示用户。 |
mv file1 file2 dir1 | 将 file1 和 file2 移动到 dir1 。 dir1 必须存在。 |
mv dir1 dir2 | 如果目录dir2不存在,则创建目录dir2,将目录dir1的内容移动到dir2中,并删除目录dir1。 如果目录dir2确实存在,请将目录dir1(及其内容)移动到目录dir2中。 |
rm
——删除文件和目录rm命令用于删除文件和目录,如下所示:
rm item ...
其中 item 是一个或多个文件或目录。
下表是 rm
常用的选项:
选项 | 长选项 | 含义 |
---|---|---|
-i | --interactive | 在删除现有文件之前,请提示用户进行确认。 如果未指定此选项, rm 将自动删除文件。 |
-r | --recursive | 递归删除目录。 这意味着,如果要删除的目录有子目录,也要删除它们。 要删除目录,必须指定此选项。 |
-f | --force | 忽略不存在的文件,不进行提示。 这将覆盖 --interactive 选项。 |
-v | --verbose | 执行删除时显示信息性消息。 |
rm
!类Unix操作系统,如Linux,没有取消删除命令。一旦你用 rm
删除了一些东西,它就消失了。Linux假设你很聪明,知道自己在做什么。
请特别小心通配符。考虑一下这个经典的例子。假设您只想删除目录中的HTML文件。为此,请键入以下内容:
xxxxxxxxxx
rm *.html
这是正确的,但如果你不小心在 *
和 .html
之间放置了一个空格,如下所示:
xxxxxxxxxx
rm * .html
rm命令将删除目录中的所有文件,然后抱怨没有名为 .html 的文件。
这里有一个有用的提示:每当您在 rm
中使用通配符时(除了仔细检查您的键入!),请先用 ls
测试通配符。这将让您看到将被删除的文件。然后按向上箭头键调用命令,并将 ls
替换为 rm
。
ln
——创建链接ln命令用于创建硬链接或符号链接。它以两种方式之一使用。以下内容创建了一个硬链接:
ln file link
以下示例创建一个符号链接:
ln -s item link
其中,item 可以是文件或目录。
硬链接是Unix创建链接的原始方式,与更现代的符号链接相比。默认情况下,每个文件都有一个硬链接,为文件命名。当我们创建硬链接时,我们会为文件创建一个额外的目录条目。硬链接有两个重要限制:
硬链接不能引用其自身文件系统之外的文件。
这意味着链接不能引用与链接本身不在同一磁盘分区上的文件。
硬链接可能不会引用目录。
硬链接与文件本身无法区分。与符号链接不同,当我们列出包含硬链接的目录时,我们不会看到链接的特殊指示。删除硬链接后,该链接将被删除,但文件本身的内容将继续存在(即其空间不会被释放),直到删除指向该文件的所有链接。
了解硬链接很重要,因为你可能会不时遇到它们,但现代实践更喜欢符号链接,我们将在下面介绍。
Symbolic links——符号链接。
创建符号链接是为了克服硬链接的局限性。符号链接通过创建一种特殊类型的文件来工作,该文件包含指向引用文件或目录的文本指针。在这方面,它们的操作方式与Windows快捷方式大致相同,尽管它们当然比Windows功能早很多年。
符号链接指向的文件和符号链接本身在很大程度上是无法区分的。例如,如果我们向符号链接写入内容,则会向引用的文件写入内容。但是,当我们删除符号链接时,只会删除链接,而不会删除文件本身。如果在符号链接之前删除文件,则链接将继续存在,但不会指向任何内容。在这种情况下,链接被称为已断开。在许多实现中, ls
命令将以一种区分颜色(如红色)显示断开的链接,以显示它们的存在。
链接的概念可能看起来很混乱,但请坚持下去。我们将尝试所有这些东西,希望它会变得清晰。
既然我们要做一些真正的文件操作,让我们建立一个安全的地方来“玩”我们的文件操作命令。首先,我们需要一个目录来工作。我们将在主目录中创建一个目录,并将其称为 playground 。
mkdir
命令用于创建目录。要创建游乐场目录,我们将首先确保我们在主目录中,然后创建新目录。
xxxxxxxxxx
[me@linuxbox ~]$ cd
[me@linuxbox ~]$ mkdir playground
为了使我们的游乐场更有趣,让我们在其中创建几个名为 dir1 和 dir2 的目录。为此,我们将把当前的工作目录更改为 playground ,并执行另一个 mkdir
。
xxxxxxxxxx
[me@linuxbox ~]$ cd playground
[me@linuxbox playground]$ mkdir dir1 dir2
请注意, mkdir
命令可以接受多个参数,允许我们使用单个命令创建两个目录。
接下来,让我们把一些数据放到游乐场里。我们将通过复制文件来实现这一点。使用 cp
命令,我们将把 passwd 文件从 /etc 目录复制到当前工作目录:
xxxxxxxxxx
[me@linuxbox playground]$ cp /etc/passwd .
请注意我们如何使用当前工作目录的简写,即单个尾随句点。所以现在,如果我们执行 ls
,我们将看到我们的文件:
xxxxxxxxxx
[me@linuxbox playground]$ ls -l
total 12
drwxrwxr-x 2 me me 4096 2025-01-10 16:40 dir1
drwxrwxr-x 2 me me 4096 2025-01-10 16:40 dir2
-rw-r--r-- 1 me me 1650 2025-01-10 16:07 passwd
现在,为了好玩,让我们使用 -v
选项(verbose,冗长的)重复复制,看看它能做什么。
xxxxxxxxxx
[me@linuxbox playground]$ cp -v /etc/passwd .
`/etc/passwd' -> `./passwd'
cp
命令再次执行了复制,但这次显示了一条简洁的消息,指示它正在执行什么操作。请注意, cp
在没有任何警告的情况下重写了第一个副本。同样,这是一个假设我们知道自己在做什么的 cp
案例。为了获得警告,我们将包含 -i
(interactive,交互式)选项。
xxxxxxxxxx
[me@linuxbox playground]$ cp -i /etc/passwd .
cp: overwrite `./passwd'?
通过输入 y 来响应提示将导致文件被覆盖,任何其他字符(例如 n )都将导致 cp
不处理文件。
现在, passwd 这个名字看起来不太有趣,这是一个游乐场,所以让我们把它改成别的名字:
xxxxxxxxxx
[me@linuxbox playground]$ mv passwd fun
让我们通过将重命名的文件移动到每个目录并再次返回来传递一些乐趣。以下操作首先将其移动到目录 dir1 :
xxxxxxxxxx
[me@linuxbox playground]$ mv fun dir1
然后将其从 dir1 移动到 dir2 :
xxxxxxxxxx
[me@linuxbox playground]$ mv dir1/fun dir2
最后,下面将其带回当前工作目录:
xxxxxxxxxx
[me@linuxbox playground]$ mv dir2/fun .
接下来,让我们看看 mv
对目录的影响。首先,我们将再次将数据文件移动到 dir1 中,如下所示:
xxxxxxxxxx
[me@linuxbox playground]$ mv fun dir1
然后我们将 dir1 移动到 dir2 ,并用 ls
进行确认:
xxxxxxxxxx
[me@linuxbox playground]$ mv dir1 dir2
[me@linuxbox playground]$ ls -l dir2
total 4
drwxrwxr-x 2 me me 4096 2025-01-11 06:06 dir1
[me@linuxbox playground]$ ls -l dir2/dir1
total 4
-rw-r--r-- 1 me me 1650 2025-01-10 16:33 fun
请注意,由于 dir2 已经存在, mv
将 dir1 移动到 dir2 中。如果 dir2 不存在,mv
会将 dir1 重命名为 dir2 。最后,让我们把一切都放回去:
xxxxxxxxxx
[me@linuxbox playground]$ mv dir2/dir1 .
[me@linuxbox playground]$ mv dir1/fun .
现在我们将尝试一些链接。我们将首先创建一些指向数据文件的硬链接,如下所示:
xxxxxxxxxx
[me@linuxbox playground]$ ln fun fun-hard
[me@linuxbox playground]$ ln fun dir1/fun-hard
[me@linuxbox playground]$ ln fun dir2/fun-hard
现在我们有四个文件乐趣的实例。让我们看看我们的游乐场目录。
xxxxxxxxxx
[me@linuxbox playground]$ ls -l
total 16
drwxrwxr-x 2 me me 4096 2025-01-14 16:17 dir1
drwxrwxr-x 2 me me 4096 2025-01-14 16:17 dir2
-rw-r--r-- 4 me me 1650 2025-01-10 16:33 fun
-rw-r--r-- 4 me me 1650 2025-01-10 16:33 fun-hard
我们注意到的一件事是,列表中的第二个字段 fun 和 fun-hard 都包含一个4,这是文件现在存在的硬链接数量。请记住,文件总是至少有一个链接,因为文件名是由链接创建的。那么,我们怎么知道 fun 和 fun-hard 实际上是同一个文件呢?在这种情况下, ls
不是很有帮助。虽然我们可以看到 fun 和 fun-hard 都是一样的大小(字段5),但我们的列表无法确定。为了解决这个问题,我们必须再深入一点。
当考虑硬链接时,想象文件由两部分组成是有帮助的。
当我们创建硬链接时,我们实际上是在创建其他名称部分,这些部分都引用了相同的数据部分。系统为所谓的 inode 分配一个磁盘块链,然后将其与名称部分相关联。因此,每个硬链接都指向一个包含文件内容的特定索引节点。
ls
命令有一种方法可以显示此信息。它通过 -i
选项调用:
xxxxxxxxxx
[me@linuxbox playground]$ ls -li
total 16
12353539 drwxrwxr-x 2 me me 4096 2025-01-14 16:17 dir1
12353540 drwxrwxr-x 2 me me 4096 2025-01-14 16:17 dir2
12353538 -rw-r--r-- 4 me me 1650 2025-01-10 16:33 fun
12353538 -rw-r--r-- 4 me me 1650 2025-01-10 16:33 fun-hard
在这个版本的列表中,第一个字段是索引节点(inode)号,正如我们所看到的, fun 和 fun-hard 共享相同的索引节点编号,这证实了它们是同一个文件。
创建符号链接是为了克服硬链接的两个缺点。
符号链接是一种特殊类型的文件,其中包含指向目标文件或目录的文本指针。
创建符号链接类似于创建硬链接。
xxxxxxxxxx
[me@linuxbox playground]$ ln -s fun fun-sym
[me@linuxbox playground]$ ln -s ../fun dir1/fun-sym
[me@linuxbox playground]$ ln -s ../fun dir2/fun-sym
第一个例子很简单;我们只需添加 -s
选项即可创建符号链接,而不是硬链接。但接下来的两个呢?记住,当我们创建符号链接时,我们是在创建目标文件相对于符号链接的位置的文本描述。如果我们看一下这里显示的 ls
输出,会更容易看到:
xxxxxxxxxx
[me@linuxbox playground]$ ls -l dir1
total 4
-rw-r--r-- 4 me me 1650 2025-01-10 16:33 fun-hard
lrwxrwxrwx 1 me me 6 2025-01-15 15:17 fun-sym -> ../fun
dir1 中 fun-sym 的列表显示,它是第一个字段中前导l的符号链接,并且指向 ../fun ,这是正确的。相对于 fun-sym 的位置, fun 位于其上方的目录中。请注意,符号链接文件的长度为6,即字符串 ../fun 中的字符数,而不是它指向的文件的长度。
在创建符号链接时,我们可以使用绝对路径名,如下所示:
xxxxxxxxxx
[me@linuxbox playground]$ ln -s /home/me/playground/fun dir1/fun-sym
或者相对路径名,正如我们在前面的例子中所做的那样。在大多数情况下,使用相对路径名更可取,因为它允许在不破坏链接的情况下重命名和/或移动包含符号链接及其引用文件的目录树。
除了常规文件,符号链接还可以引用目录。
xxxxxxxxxx
[me@linuxbox playground]$ ln -s dir1 dir1-sym
[me@linuxbox playground]$ ls -l
total 16
drwxrwxr-x 2 me me 4096 2025-01-15 15:17 dir1
lrwxrwxrwx 1 me me 4 2025-01-16 14:45 dir1-sym -> dir1
drwxrwxr-x 2 me me 4096 2025-01-15 15:17 dir2
-rw-r--r-- 4 me me 1650 2025-01-10 16:33 fun
-rw-r--r-- 4 me me 1650 2025-01-10 16:33 fun-hard
lrwxrwxrwx 1 me me 3 2025-01-15 15:15 fun-sym -> fun
如前所述, rm
命令用于删除文件和目录。我们将用它来清理我们的游乐场。首先,让我们删除一个硬链接。
xxxxxxxxxx
[me@linuxbox playground]$ rm fun-hard
[me@linuxbox playground]$ ls -l
total 12
drwxrwxr-x 2 me me 4096 2025-01-15 15:17 dir1
lrwxrwxrwx 1 me me 4 2025-01-16 14:45 dir1-sym -> dir1
drwxrwxr-x 2 me me 4096 2025-01-15 15:17 dir2
-rw-r--r-- 3 me me 1650 2025-01-10 16:33 fun
lrwxrwxrwx 1 me me 3 2025-01-15 15:15 fun-sym -> fun
这正如预期的那样。如目录列表的第二个字段所示,文件 fun-hard 已经消失,为好玩而显示的链接数量从四个减少到三个。接下来,我们将删除文件 *fun) ,为了好玩,我们将包含 -i
选项来显示它的作用:
xxxxxxxxxx
[me@linuxbox playground]$ rm -i fun
rm: remove regular file `fun'?
在提示下输入 y ,文件将被删除。现在让我们看看 ls
的输出。注意到 fun-sym 发生了什么事吗?由于这是一个指向现在不存在的文件的符号链接,因此链接已断开(broken)。
xxxxxxxxxx
[me@linuxbox playground]$ ls -l
total 8
drwxrwxr-x 2 me me 4096 2025-01-15 15:17 dir1
lrwxrwxrwx 1 me me 4 2025-01-16 14:45 dir1-sym -> dir1
drwxrwxr-x 2 me me 4096 2025-01-15 15:17 dir2
lrwxrwxrwx 1 me me 3 2025-01-15 15:15 fun-sym -> fun
【最后一行的 fun-sym 和 fun 实际以黑底红字显示】
大多数Linux发行版将 ls
配置为显示断开的链接。断开的链接本身并不危险,但相当混乱。如果我们尝试使用断开的链接,我们将看到以下内容:
xxxxxxxxxx
[me@linuxbox playground]$ less fun-sym
fun-sym: No such file or directory
让我们稍微打扫一下。我们将删除此处的符号链接:
xxxxxxxxxx
[me@linuxbox playground]$ rm fun-sym dir1-sym
[me@linuxbox playground]$ ls -l
total 8
drwxrwxr-x 2 me me 4096 2025-01-15 15:17 dir1
drwxrwxr-x 2 me me 4096 2025-01-15 15:17 dir2
关于符号链接,需要记住的一件事是,大多数文件操作都是在链接的目标上执行的,而不是链接本身。 rm
是个例外。当我们删除链接时,删除的是链接,而不是目标。
最后,我们将拆除我们的游乐场。为此,我们将返回到主目录,并使用带有递归选项( -r
)的 rm
删除游乐场及其所有内容,包括其子目录:
xxxxxxxxxx
[me@linuxbox playground]$ cd
[me@linuxbox ~]$ rm -r playground
GNOME和KDE中的文件管理器都提供了一种简单而自动的创建符号链接的方法。在GNOME中,拖动文件时按住 Ctrl + Shift 键将创建链接,而不是复制(或移动)文件。在KDE中,每当文件被删除时,都会出现一个小菜单,提供复制、移动或链接文件的选择。
我们在这里覆盖了很多地方,需要一段时间才能完全理解。一遍又一遍地进行游乐场练习,直到有意义为止。深入了解基本的文件操作命令和通配符非常重要。您可以通过添加更多文件和目录、使用通配符指定各种操作的文件来扩展游乐场练习。一开始,链接的概念有点令人困惑,但花点时间了解它们是如何工作的。它们可以成为真正的救星。