从命令行管理文件

欢迎阅览我的文章,本章节将介绍什么是Linux,演示环境为RedHat-9

描述Linux文件系统层次结构概念

​ Linux系统中的所有文件存储在文件系统中,他们被组织到一颗上下颠倒的树中,称为文件系统层次结构。这个层次结构是上下颠倒的树,因为树根在顶部,树根下方延伸处目录和子目录的分支。

image-20250303143405965

​ / 目录是根目录,位于文件系统层次结构的顶部。/ 字符还用做文件名中的目录分隔符。例如:如果etc是/ 根目录的子目录,则可将该目录指代为 /etc。类似的,如果/etc目录包含一个名为issue的文件,可以将该文件指代为/etc/issue。

​ / 的子目录用于标准化用途,以便根据类型和用途整理文件,从而更加轻松的找到文件,例如:在根目录中,子目录/boot用于存储启动系统所需的文件。

  • 位置 用途
    /boot 操作系统启动过程所需文件
    /dev 供操作系统访问硬件的特殊设备文件
    /etc 供系统及软件的配置文件
    /home 供普通用户存储其个人数据及配置文件的主目录
    /root 供超级用户root存储其个人数据及配置文件的主目录
    /run 自上一次系统启动以来启动的进程的运行时数据。这些数据包括进程ID文件和锁定文件。此目录中的内容在重启时重新创建。所以该目录的数据在重启后,存放在该目录下的数据就会丢失。
    /tmp 供临时文件使用的全局可写空间,天内未曾访问、更改或者修改的文件将自动从该目录中删除。/var/tmp目录也是一个临时目录,其中的文件如果在30天内为曾访问、更改或者修改过,将被自动删除
    /usr 安装的软件、共享的库(包括文件)和只读程序数据。重要的子目录有: - /usr/bin:用户命令 - /usr/sbin:系统管理命令 - /usr/local:本地自定义软件
    /var 特定于系统的可变数据应在系统启动之间保持永久性。动态变化的文件(如数据库、缓存目录、日志文件、打印机后台处理文档和网页内容)可在/var下找到

通过名称指定文件

绝对路径和相对路径

​ 文件或目录的路径指定其唯一的文件系统位置。跟随文件路径会遍历出一个或多个指定的子目录,用正斜杠 (/) 分隔,直到达到目标位置。目录也称之为文件夹,可以包含其文件和其他子目录。目录的引用方式可以与文件相同

注意:Linux文件名中可以接收空格字符。但是shell也使用空格来分割命令行上的选项和参数。如果命令中包含了名称带有空格的文件,则shell可能会误解释该参数,并认为该文件名是多个参数。为避免这样的情况,请将此类文件名括在引号中,以便shell激昂名称解释为单个参数。当然最好避免在文件中名中使用空格是最好的。

绝对路径

​ 绝对路径是一个完全限定名称,用于指定文件在文件系统层次结构中的确切位置。绝对路径从根 (/) 目录开始寻找目标文件或目录,并包括到达特定文件所必须遍历的每个子目录。文件系统中的每个文件都有一个唯一绝对路径名,可通过一个简单的规则识别:第一个字符是正斜杠 (/) 的路径名是绝对路径名。

​ 例如,系统消息日志文件的绝对路径名是 /var/log/messages。绝对路径名输入起来可能会太长,所以也可以通过相对于shell提示符当前工作目录的位置来查找文件

1
2
3
[root@workstation ~]# ls /var/log/messages
/var/log/messages
[root@workstation ~]#

当前工作目录和相对路径

​ 当用户登录并打开shell命令提示符时,初始位置通常是该用户的主目录。系统进程也有一个初始目录。用户和进程根据需要更改到其他目录。属于工作目录和当前目录指它们的当前位置

​ 与绝对路径类似,相对路径也是标识唯一文件,但仅指定从工作目录到达文件所需的路径。相对路径遵循一个简单原则:第一字符是正斜杠之外的其他字符的路径名就是相对路径名。例如:我当前工作目录为/var,我要找到消息日志文件则是:log/messages

1
2
3
[root@workstation var]# ls log/messages
log/messages
[root@workstation var]#

​ Linux文件系统(包括ext4、XFS、GFS2和GlusterFS)是区分大小写的。在同一目录中创建FileCase.txt和filecase.txt文件将会生成两个不同的文件。

​ 非Linux文件系统的工作方式可能会有所不同。例如:VFAT、Microsoft的NTFS和Apple的HFS+具有大小写保留行为。虽然这些文件系统不区分大小写,它们确实使用文件的原始大小写形式显示的文件名。如果在VFAT文件系统上创建上述示例中的文件,这两个名称指向同一文件,而部署指向两个不同的文件。

浏览文件系统中的路径

​ pwd命令显示改shell的当前工作目录的完整路径名。此命令可帮助您却独使用当前相对路径来访问文件的语法。ls命令列出指定目录的目录内容。如果未指定目录,则列出当前工作目录的内容

1
2
3
4
5
6
[root@workstation var]# pwd
/var
[root@workstation var]# ls
account cache db ftp kerberos local log nis preserve spool yp
adm crash empty games lib lock mail opt run tmp
[root@workstation var]#

​ 使用cd命令可更改shell当前工作目录。如果没有未该命令指定任何参数,它将切换到您用户的主目录。

​ 以下示例中,cd命令混用绝对路径和相对路径,以更改shell当前工作目录。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# pwd查看当前工作目录
[student@workstation ~]$ pwd
/home/student
# 通过相对路径进去主目录的test1
[student@workstation ~]$ cd test1/
[student@workstation test1]$ pwd
/home/student/test1
[student@workstation test1]$ cd
[student@workstation ~]$ pwd
/home/student
# 通过绝对路径到主目录下的test3
[student@workstation ~]$ cd /home/student/test3
[student@workstation test2]$ pwd
/home/student/test3
# 通过相对路径进去主目录的test2
[student@workstation test1]$ cd
[student@workstation ~]$ cd test2/
[student@workstation test2]$ pwd
/home/student/test2
# 通过cd不加参数,返回主目录
[student@workstation test2]$ cd
[student@workstation ~]$ pwd
/home/student
[student@workstation ~]$

​ 在上述示例中,默认shell提示符还显示当前工作目录绝对路径的最后一个目录。例如,对于/home/student/test1目录,仅显示test1。当您的当前目录是主目录时,提示符显示波浪号字符 (~)。

​ touch 命令可将文件的时间戳更新为当前日期和时间,而不进行其他修改。此命令同时也可以用于创建空的文件,因为使用touch命令加上不存在的文件名参数就会导致创建该文件。在以下示例中,touch命令在Videos子目录中创建文件,以及修改文件更新时间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# touch 接上一个不存在的文件名参数,则创建文件
[kiosk@foundation0 Videos]$ touch test1.txt
[kiosk@foundation0 Videos]$ ls -l
total 0
-rw-rw-r--. 1 kiosk kiosk 0 Mar 4 17:35 test1.txt
# 向该文件添加内容
[kiosk@foundation0 Videos]$ echo hahaah > test1.txt
[kiosk@foundation0 Videos]$ cat test1.txt
hahaah
# 修改时间为17:36
[kiosk@foundation0 Videos]$ ls -l
total 4
-rw-rw-r--. 1 kiosk kiosk 7 Mar 4 17:36 test1.txt
# 当touch 接上已存在的文件名参数,则最新修改时间更新
[kiosk@foundation0 Videos]$ touch test1.txt
# 修改时间为:17:38
[kiosk@foundation0 Videos]$ ls -l
total 4
-rw-rw-r--. 1 kiosk kiosk 7 Mar 4 17:38 test1.txt
# 切文件的内容未作更改
[kiosk@foundation0 Videos]$ cat test1.txt
hahaah
[kiosk@foundation0 Videos]$

​ ls 命令具有多个选项,用于显示文件的属性。最常的选项是 -l (长列表格式)、-a(包含隐藏文件在内的所有文件),以及 -R (递归方式,包含所有子目录的内容)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# 长格式显示目录或指定目录下的内容
[kiosk@foundation0 Videos]$ ls -l
total 4
drwxrwxr-x. 2 kiosk kiosk 6 Mar 4 17:45 dir1
-rw-rw-r--. 1 kiosk kiosk 0 Mar 4 17:45 dir-1.txt
drwxrwxr-x. 2 kiosk kiosk 6 Mar 4 17:45 dir2
-rw-rw-r--. 1 kiosk kiosk 0 Mar 4 17:45 dir-2.txt
-rw-rw-r--. 1 kiosk kiosk 7 Mar 4 17:38 test1.txt
# 长格式显示,并且显示包含隐藏文件(.haha.txt)
[kiosk@foundation0 Videos]$ ls -la
total 8
drwxr-xr-x. 4 kiosk kiosk 98 Mar 4 17:45 .
drwx------. 18 kiosk kiosk 4096 Feb 27 15:08 ..
drwxrwxr-x. 2 kiosk kiosk 6 Mar 4 17:45 dir1
-rw-rw-r--. 1 kiosk kiosk 0 Mar 4 17:45 dir-1.txt
drwxrwxr-x. 2 kiosk kiosk 6 Mar 4 17:45 dir2
-rw-rw-r--. 1 kiosk kiosk 0 Mar 4 17:45 dir-2.txt
-rw-rw-r--. 1 kiosk kiosk 0 Mar 4 17:45 .haha.txt
-rw-rw-r--. 1 kiosk kiosk 7 Mar 4 17:38 test1.txt
# 长格式及递归显示dir1目录下的内容
[kiosk@foundation0 Videos]$ ls -lR dir1/
# dir1下具有test-dir、test-dir-2目录
dir1/:
total 0
drwxrwxr-x. 2 kiosk kiosk 23 Mar 4 17:50 test-dir
drwxrwxr-x. 2 kiosk kiosk 23 Mar 4 17:50 test-dir-2
# test-dir目录下具有test1.txt文件
dir1/test-dir:
total 0
-rw-rw-r--. 1 kiosk kiosk 0 Mar 4 17:50 test1.txt
# test-dir-2目录下具有test2.txt文件
dir1/test-dir-2:
total 0
-rw-rw-r--. 1 kiosk kiosk 0 Mar 4 17:50 test2.txt
[kiosk@foundation0 Videos]$

​ ls -la中的显示了所有的目录,包括隐藏目录,其中顶部具有两个特殊的目录。一个圆点(.)代表当前目录,两个原点(..)则代表父级目录,也就是当前目录的上一级目录。这些特殊目录存在于系统中的每一个目录中,在使用文件管理命令时非常有用。

重要:开头为圆点(.)的文件名表示为隐藏文件;在使用ls和其他命令时,无法在普通视图中看到这些文件。此行为并非一种安全功能。因为ls -a加上选项还是可以很轻松的看到该文件。隐藏文件主要还是用于必要的用户配置文件让主目录凌乱不堪,同时也可以避免重要的配置文件被误操作,复制到其他目录或被修改、删除掉。

​ 您也可以讲波浪号(~)特殊字符于其他命令组合使用,以促进于主目录的交互。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 从当前工作目录/var,通过波浪号查看主目录内容
[kiosk@foundation0 var]$ ls -l ~
total 152588
-rw-rw-r--. 1 kiosk kiosk 127 Oct 9 2023 '\'
-rw-rw-r--. 2 kiosk kiosk 33577 Sep 16 2022 ClassPrep.txt
-rw-rw-r--. 2 kiosk kiosk 10853 Nov 16 2021 ClassRHAPrep.txt
-rw-rw-r--. 2 kiosk kiosk 18852 Jul 7 2022 ClassroomReset.txt
****忽略****
-rw-rw-r--. 2 kiosk kiosk 7900 Nov 22 2022 History.txt
drwxr-xr-x. 2 kiosk kiosk 6 Feb 1 2023 Music
drwxr-xr-x. 2 kiosk kiosk 6 Feb 1 2023 Pictures
drwxr-xr-x. 2 kiosk kiosk 6 Feb 1 2023 Public
-rwxrwxrwx. 1 kiosk kiosk 12 Feb 27 11:35 ssh.sh
drwxrwxr-x. 2 kiosk kiosk 72 Jan 31 2023 survey
drwxr-xr-x. 2 kiosk kiosk 6 Feb 1 2023 Templates
drwxr-xr-x. 4 kiosk kiosk 98 Mar 4 17:45 Videos
[kiosk@foundation0 var]$

​ cd 命令同样有着许多选项。其中一些实用的应该尽早熟悉使用,要形成一种肌肉记忆。cd - 命令可更改到用户在进入当前目录之前所处的目录。

1
2
3
4
5
6
# 通过cd - 命令,迅速返回到之前所处的目录
[kiosk@foundation0 var]$ cd -
/home/kiosk
[kiosk@foundation0 ~]$ pwd
/home/kiosk
[kiosk@foundation0 ~]$

cd .. 命令使用(..)隐藏目录上移一个级别,进入当前目录的父目录,而不必知道确切的父目录名称。其他隐藏目录(.)可为当前位置是来源或者目标参数的命令指定当前目录,以此免除输入目录绝对路径名的必要。

1
2
3
4
5
6
7
8
9
10
11
# 返回上级目录
[kiosk@foundation0 ~]$ cd ..
[kiosk@foundation0 home]$ pwd
/home
# cd -返回上次所在目录
[kiosk@foundation0 home]$ cd -
/home/kiosk
# 执行当前目录下的test.sh脚本文件
[kiosk@foundation0 ~]$ bash ./test.sh
Hello World
[kiosk@foundation0 ~]$

使用命令行工具管理文件

命令行文件管理

​ 创建、删除、复制和移动文件和目录,是系统管理员的常用操作。不带选项时,一些命令讲用于文件交互,或者可以通过相应的选项集来操作目录。

​ 请注意运行命令时使用的选项。某些选项的含义可能因命令而异。

创建目录

​ mkdir 命令可创建一个或多个目录或子目录。他取您要创建的目录的路径列表作为参数。

​ 以下实例,将在/home/kiosk/Documents目录下。使用mkdir命令和空格分割的目录名称列表来一次性创建多个目录。

1
2
3
4
5
6
[kiosk@foundation0 Documents]$ pwd
/home/kiosk/Documents
[kiosk@foundation0 Documents]$ mkdir ProjectX ProjectY ProjectZ
[kiosk@foundation0 Documents]$ ls
ProjectX ProjectY ProjectZ
[kiosk@foundation0 Documents]$

​ 如果创建的目录参数已存在,或者您尝试创建的目录的父目录不存在,则mkdir命令将失败显示错误。

​ mkdir 命令 -p(父级)选项将为请求的目标位置创建缺失的父目录。在以下示例中,mkdir命令可以在缺少父级目录的情况下,用一个命令创建三个ChapterN子目录。 -p 选项可创建缺失的父目录Thesis。

1
2
3
4
5
6
7
8
9
10
11
kiosk@foundation0 Documents]$ mkdir -p Thesis/Chapter1 Thesis/Chapter2 Thesis/Chapter3
[kiosk@foundation0 Documents]$ ls -R Thesis/
Thesis/:
Chapter1 Chapter2 Chapter3

Thesis/Chapter1:

Thesis/Chapter2:

Thesis/Chapter3:
[kiosk@foundation0 Documents]$

​ 请谨慎使用mkdir 命令的 -p 选项,因为在错误的拼写中可能会创建非预期的目录,不会因为对于您是非预期的目录,而生成错误消息。在以下示例中,假设您试图在Videos中创建一个Watched子目录,但在mkdir命令中不小心遗漏了Videos中的字母 “s”。

1
2
3
4
5
6
7
8
9
10
[kiosk@foundation0 ~]$ mkdir Video/Watched
mkdir: cannot create directory ‘Video/Watched’: No such file or directory
# 加入-p选项,Watched目录将会创建在错误父目录中
[kiosk@foundation0 ~]$ mkdir -p Video/Watched
[kiosk@foundation0 ~]$ ls -R Video
Video:
Watched

Video/Watched:
[kiosk@foundation0 ~]$

​ mkdir 命令失败,因为Video目录不存在。如果您使用带有-p 选项的mkdir 命令,则会无意中创建Video目录。Watched子目录将会在不正确的目录中创建。

复制文件和目录

​ cp 命令可以复制文件,并在当前目录或者其他指定目录中创建一个文件。

1
2
3
4
5
6
7
[kiosk@foundation0 ~]$ cd Videos/
[kiosk@foundation0 Videos]$ ls
test1.txt
[kiosk@foundation0 Videos]$ cp test1.txt test2.txt
[kiosk@foundation0 Videos]$ ls
test1.txt test2.txt
[kiosk@foundation0 Videos]$

​ 也可以使用cp命令将多个文件复制到某一目录中。这种情况下,最后一个参数必须是目录。复制的文件在新目录中保留其原有名称。如果目标目录中存在同名的文件,则会覆盖原有文件。默认情况下,cp 命令不复制目录,而是会忽略它。

​ 以下示例中列出两个目录作为参数,即Thesis和ProjecrX目录。最后一个参数(ProjecrX目录)是目标,可用作目的地。cp命令忽略了Thesis参数,因为它是要复制的对象是一个目录。

1
2
3
4
5
6
7
8
9
10
11
[kiosk@foundation0 Documents]$ ls 
ProjecrX text1.txt text2.txt Thesis
[kiosk@foundation0 Documents]$ cp text1.txt text2.txt Thesis ProjecrX
cp: -r not specified; omitting directory 'Thesis'
[kiosk@foundation0 Documents]$ ls Thesis ProjecrX
ProjecrX:
text1.txt text2.txt

Thesis:
Chapter1 Chapter2 Chapter3
[kiosk@foundation0 Documents]$

​ Thesis目录复制失败,但test1.txt和test2.txt文件复制成功。

​ 您可以使用cp 命令 -r 选项复制目录及其内容,请记住,您可以在命令组合中使用.和..特殊目录。在以下示例中,Thesis目录及其内容复制到ProjecrX目录。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[kiosk@foundation0 Documents]$ cd ProjecrX/
# cp 复制, ../上级目录的Thesis目录, .目的地当前所在工作目录
[kiosk@foundation0 ProjecrX]$ cp -r ../Thesis/ .
[kiosk@foundation0 ProjecrX]$ ls
text1.txt text2.txt Thesis
[kiosk@foundation0 ProjecrX]$ ls -R Thesis/
Thesis/:
Chapter1 Chapter2 Chapter3

Thesis/Chapter1:

Thesis/Chapter2:

Thesis/Chapter3:
[kiosk@foundation0 ProjecrX]$

移动文件和目录

​ mv 命令可将文件从一个位置移动到另一个位置。如果您将文件的绝对路径视为它的全名,那么移动文件实际上和重命名文件名一样。文件内容正在移动后保持不变。

​ 使用mv命令来重命名文件。以下示例中,mv text1.txt命令将目录中的text1.txt 文件重命名为 text2.txt

1
2
3
4
5
6
[kiosk@foundation0 ProjecrX]$ ls
text1.txt Thesis
[kiosk@foundation0 ProjecrX]$ mv text1.txt text2.txt
[kiosk@foundation0 ProjecrX]$ ls
text2.txt Thesis
[kiosk@foundation0 ProjecrX]$

​ 使用mv 命令将文件移动到另一个目录。再以下示例中,text2.txt 文件从/Documents/ProjecrX目录移动到/Documents/Thesis/Chapter1目录中。您可以使用mv命令 -v选项来显示命令操作的详细输出

1
2
3
4
5
6
[kiosk@foundation0 ProjecrX]$ ls ../Thesis/Chapter1/
[kiosk@foundation0 ProjecrX]$ mv -v text2.txt ../Thesis/Chapter1/
renamed 'text2.txt' -> '../Thesis/Chapter1/text2.txt'
[kiosk@foundation0 ProjecrX]$ ls ../Thesis/Chapter1/
text2.txt
[kiosk@foundation0 ProjecrX]$

删除文件和目录

​ rm 命令可删除文件。默认情况下,rm不会删除目录。您可以使用rm命令的 -r或 –recursive选项,使rm命令删除目录及其内容(文件)。rm -r命令首先遍历每个子目录,并在删除每个目录之前逐一删除其中的文件。

​ 在以下示例中,不带选项时rm 命令会删除test1.txt文件,但若要删除Thesis/Chhapter1目录,您必须添加-r 选项。

1
2
3
4
5
6
7
8
9
10
11
12
[kiosk@foundation0 ~]$ ls Documents/Thesis/Chapter1/
test1.txt
[kiosk@foundation0 ~]$ rm Documents/Thesis/Chapter1/test1.txt
[kiosk@foundation0 ~]$ ls Documents/Thesis/Chapter1/
[kiosk@foundation0 ~]$ rm Documents/Thesis/Chapter1/
rm: cannot remove 'Documents/Thesis/Chapter1/': Is a directory
[kiosk@foundation0 ~]$ rm -r Documents/Thesis/Chapter1/
[kiosk@foundation0 ~]$ ls Documents/Thesis/Chapter1/
ls: cannot access 'Documents/Thesis/Chapter1/': No such file or directory
[kiosk@foundation0 ~]$ ls Documents/Thesis
Chapter2 Chapter3
[kiosk@foundation0 ~]$

重要:红帽Linux不提供命令行取消删除功能,也没有可从中恢复报关被删除文件的“垃圾桶”。垃圾桶是桌面环境(如:GNOME)的一个组件,但是不供从shell运行的命令使用。所有在使用相对路径删除文件或目录之前,最好先使用pwd命令验证您当前的工作目录。

​ 您可以使用rm命令 -i 选项以交互式提示确认后再删除。这基本上与使用rm命令-f选项相反,-f选项强制删除并且不提示用户进行确认。

1
2
3
4
5
6
7
[kiosk@foundation0 Documents]$ rm -ri Thesis/
rm: descend into directory 'Thesis/'? y
rm: remove directory 'Thesis/Chapter2'? y
rm: remove directory 'Thesis/Chapter3'? y
rm: remove directory 'Thesis/'? y
[kiosk@foundation0 Documents]$ rm -rf ProjecrX/
[kiosk@foundation0 Documents]$

注意:如果同时使用-i和-f选项,-f选项将具有优先权,所以再rm删除文件之前,不会提示您进行确认。

​ 您也可以使用rmdir命令来删除空目录。使用rm命令-r选项可删除非空目录

1
2
3
4
5
6
7
8
9
10
# dir1目录非空,dir2空目录,rmdir命令无法删除非空目录,rm -r可删除非空目录
[kiosk@foundation0 Documents]$ ls dir1/
text1.txt
[kiosk@foundation0 Documents]$ ls dir2
[kiosk@foundation0 Documents]$ rmdir dir1/
rmdir: failed to remove 'dir1/': Directory not empty
[kiosk@foundation0 Documents]$ rmdir dir2/
[kiosk@foundation0 Documents]$ ls
dir1
[kiosk@foundation0 Documents]$

制作文件间的链接

管理文件间的链接

​ 您可以创建指向同一文件的多个文件名。这些文件名称为链接。

​ 您可以创建的两种类型的链接:硬链接或符号链接(同时也称为软链接)。每种方法各有利弊。

创建硬链接

​ 从初始名称到文件系统上的数据,每个文件都以一个硬链接开始。当创建指向文件的硬链接时,也会创建另一个指向同一数据的名称。新的硬链接与原始文件名的作用完全相同。创建之后,新的硬链接与文件的原始名称毫无二致。

​ 您可以使用ls -l命令来确认文件是否具有多个硬链接。他报告的项目之一就是每个文件的链接数,即文件所具有的硬链接数。再下面的示例中,newfile.txt的链接数位1。它恰好有一个绝对路径,即/home/kiosk/newfile.txt。

1
2
3
[kiosk@foundation0 ~]$ ls -l newfile.txt 
-rw-rw-r--. 1 kiosk kiosk 6 Mar 5 16:47 newfile.txt
[kiosk@foundation0 ~]$

​ 您可以使用ln命令来创建一个指向现有文件的硬链接(也就是指向该文件的另一个名称)。该命令至少需要两个参数:现有文件的路径,以及要创建的硬链接的路径。

​ 以下示例将为现有文件newfile.txt,在/tmp目录中创建一个名为newfile-hlink2.txt的硬链接。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[kiosk@foundation0 ~]$ cat newfile.txt 
hahah
# 创建硬链接
[kiosk@foundation0 ~]$ ln newfile.txt /tmp/newfile-hlink2.txt
# 硬链接已生成
[kiosk@foundation0 ~]$ ls -l /tmp/newfile-hlink2.txt
-rw-rw-r--. 2 kiosk kiosk 6 Mar 5 16:47 /tmp/newfile-hlink2.txt
# 硬链接与原始文件具有相同的数据
[kiosk@foundation0 ~]$ cat /tmp/newfile-hlink2.txt
hahah
# 修改原始文件内容的同时,硬链接的内容也同时随原文件更新
[kiosk@foundation0 ~]$ echo xixixi > newfile.txt
[kiosk@foundation0 ~]$ cat /tmp/newfile-hlink2.txt
xixixi
[kiosk@foundation0 ~]$

​ 要确定两个文件是否被硬链接,请使用ls命令配合-i 选项列出每个文件索引节点编码。如果两个文件位于同一文件系统上,而且他们的索引节点编号相同,那么这两个文件就是指向同一数据的硬链接。

1
2
3
4
[kiosk@foundation0 ~]$ ls -li newfile.txt /tmp/newfile-hlink2.txt
269337410 -rw-rw-r--. 2 kiosk kiosk 7 Mar 5 16:55 newfile.txt
269337410 -rw-rw-r--. 2 kiosk kiosk 7 Mar 5 16:55 /tmp/newfile-hlink2.txt

重要:引用同一文件的硬链接具有相同的链接数、访问权限、用户和组所有权、时间戳,以及文件内容。当一个硬链接的内容发生更改,同一文件的其他硬链接也会显示更新后的新内容。这是因为每个硬链接都指向存储设备中的同一数据

​ 即使原始文件被删除,只要还存在至少一个硬链接,该文件的内容就依然可用。只有最后一个硬链接被删除时,数据才会从存储中删除,从而使任何硬链接都不会引用该文件内容。

1
2
3
4
5
6
[kiosk@foundation0 ~]$ rm -rf newfile.txt 
[kiosk@foundation0 ~]$ ls -li /tmp/newfile-hlink2.txt
269337410 -rw-rw-r--. 1 kiosk kiosk 7 Mar 5 16:55 /tmp/newfile-hlink2.txt
[kiosk@foundation0 ~]$ cat /tmp/newfile-hlink2.txt
xixixi
[kiosk@foundation0 ~]$

硬链接的局限性

​ 硬链接存在一些局限性。首先,您只能将硬链接用于常规文件。无法使用ln命令来创建指向目录或特殊文件的硬链接。

​ 其次,只有当两个文件位于同一文件系统上时,您才能使用硬链接。文件系统层次结构可以由多个存储设备组成。当切换到新目录时,该目录及其内容可能会存储在不同的文件系统中,具体取决于您的系统配置。

​ 您可用使用df命令来列出位于不同文件系统上的目录。例如,您可能会看到以下输出:

1
2
3
4
5
6
7
8
9
10
11
[kiosk@foundation0 ~]$ df 
Filesystem 1K-blocks Used Available Use% Mounted on
devtmpfs 8155384 0 8155384 0% /dev
tmpfs 8175032 0 8175032 0% /dev/shm
tmpfs 3270016 10264 3259752 1% /run
/dev/nvme0n1p3 191037300 70391952 120645348 37% /
/dev/loop2 7866562 7866562 0 100% /content/rhel9.0/x86_64/rhel8-additional
/dev/loop1 456 456 0 100% /content/rhel9.0/x86_64/rhcsa-practice
/dev/nvme0n1p1 2086912 971540 1115372 47% /boot
/dev/loop0 8377364 8377364 0 100% /content/rhel9.0/x86_64/dvd
tmpfs 1635004 104 1634900 1% /run/user/1000

​ 两个不同的目录及其子目录中的文件位于不同的文件系统上。因此,本示例中的系统而言,您可以在/tmp/newfile-hlink2.txt/home/kiosk/newfile.txt 文件之间创建一个硬链接,因为它们都说 / 目录的子目录,而不是列表中其他任何目录的子目录。但是您不能在/boot/home/kiosk/newfile.txt 之间建立硬链接,因为第一个文件位于/boot目录下的子目录并且在/dev/nvme0n1p1文件系统中,而第二个文件在/dev/nvme0n1p3文件系统中

创建符号链接

​ ln 命令 -s 选项可创建符号链接,也称为“软链接”。符号链接不是常规文件,而是指向现有文件或目录的特殊类型的文件。

​ 符号链接相比硬链接有着一定的优势:

  • 符号链接可以链接位于不同文件系统上的两个文件。
  • 符号链接可以指向目录或特殊文件,而不仅限于常规文件。

​ 在以下示例中,ln -s命令为/home/kiosk/newfile.txt文件创建符号链接。符号链接在名称是/tmp/newfile-symlink.txt

1
2
3
4
5
6
7
[kiosk@foundation0 ~]$ ln -s /home/kiosk/newfile.txt /tmp/newfile-symlink.txt
[kiosk@foundation0 ~]$ ls -l newfile.txt /tmp/newfile-symlink.txt
-rw-r--r--. 1 kiosk kiosk 6 Mar 5 17:46 newfile.txt
lrwxrwxrwx. 1 kiosk kiosk 23 Mar 5 17:48 /tmp/newfile-symlink.txt -> /home/kiosk/newfile.txt
[kiosk@foundation0 ~]$ cat /tmp/newfile-symlink.txt
hahah
[kiosk@foundation0 ~]$

​ 在上面示例中,/tmp/newfile-symlink.txt文件的长列表的第一个字符是l(字母 l)而不是 - 。这个字符表示该文件是符号链接而非常规文件。

​ 当原始常规文件被删除后,符号链接会指向原始文件,但目标已消失。指向缺少文件的符号链接称为“悬空符号链接”。

1
2
3
4
5
6
[kiosk@foundation0 ~]$ rm -f newfile.txt 
[kiosk@foundation0 ~]$ ls -l /tmp/newfile-symlink.txt
lrwxrwxrwx. 1 kiosk kiosk 23 Mar 5 17:48 /tmp/newfile-symlink.txt -> /home/kiosk/newfile.txt
[kiosk@foundation0 ~]$ cat /tmp/newfile-symlink.txt
cat: /tmp/newfile-symlink.txt: No such file or directory
[kiosk@foundation0 ~]$

重要:在上述示例中,悬空符号链接有个副作用,那就是:如果您稍后创建了一个与删除文件同名的新文件(/home/kiosk/newfile.txt),那么符号链接将不再“悬空”,而是指向这个新文件,硬链接的工作方式却不是这样的。如果您删除硬链接,然后使用常规工具(而不是ln)创建一个同名的文件,那么新文件将不会链接到旧文件,不妨通过以下方式比较硬链接和符号链接,以了解它们的工作原理:

  • 硬链接是将名称指向存储设备上的数据。
  • 符号链接是将名称指向另一个名称,原文件指向存储设备上的数据。

​ 符合链接可以指向目录,而且,符号链接发挥目录一样的作用。如果使用cd进入到符合链接的目录,则当前工作目录将变为被链接的目录。有些工具可以跟踪您如何通过软链接到达这个目录的。例如,默认情况下,cd将使用符号链接的名称(而非实际的名称)来更新当前工作目录。如果要使用实际目录的名称更新当前工作目录,则可以使用 -P 选项。

​ 以下示例将创建/home/kiosk/configfiles的不好链接,它将指向/etc目录。

1
2
3
4
5
6
7
8
[kiosk@foundation0 ~]$ ln -s /etc/ /home/kiosk/configfiles
[kiosk@foundation0 ~]$ cd /home/kiosk/configfiles
[kiosk@foundation0 configfiles]$ pwd
/home/kiosk/configfiles
[kiosk@foundation0 configfiles]$ cd -P /home/kiosk/configfiles
[kiosk@foundation0 etc]$ pwd
/etc
[kiosk@foundation0 etc]$

使用shell扩展匹配文件名

命令行扩展

​ 当您在Bash shell提示符中键入命令时,shell在运行该命令行之前通过多个扩展对其进行处理。您可以使用这些shell扩展来执行原本很难或不可能完成的复杂任务。

​ Bash执行的主要扩展有:

  • 大括号扩展,可以生成多个字符串。
  • 波浪号扩展,扩展至用户主目录路径。
  • 变量扩展,将文本替换为shell变量中存储的值。
  • 命令替换,加ing文本替换为命令的输出。
  • 路径名扩展,帮助按模式匹配选择一个或多个文件。

​ 路径名扩展也称为通配符,是Bash最有用的功能之一。使用此功能,可以更加轻松地管理多个文件。使用“扩展”的元字符来匹配要寻找的文件名和路径名,可以一次性针对集中的一组文件执行命令。

路径名扩展和模式匹配

​ 路径名扩展将表示为通配符或字符类别的特殊字符模式扩展为该模式匹配的文件名列表。在shell运行您的命令之前,它会将模式替换为匹配的文件名列表。如果该模式与任何内容都不匹配,则shell将尝试使用该模式作为其运行命令的字面参数。下表列出了用于模式匹配的常见元字符和模式类型。

模式 匹配项
* 由零个或跟多字符组成的任意字符串。
? 任何一个字符。
[abc…] 括起的类型(位于两个方括号之间)中的任何一个字符。
[!abc…] 不在括起的类型中的任意字符。
[^abc…] 不在括起的类型中的任意字符。
[[:alpha:]] 任何字母字符
[[:lower:]] 任何小写字符
[[:upper:]] 任何大写字符
[[:alnum:]] 任何字母字符或数字
[[:punct:]] 除空格和字母数字意外的任何可打印字符。
[[:digit:]] 从0到9的任何单个数字。
[[:space:]] 任何单个空格字符,可能包括制表符、换行符、回车符、换页符或空格。

​ 便于演示,以下命令创建一些示例文件:

1
2
3
4
5
[kiosk@foundation0 Videos]$ mkdir glob; cd glob
[kiosk@foundation0 glob]$ touch alpha bravo charlie dalta echo able baker cast dog easy Able Aplha Cast 123
[kiosk@foundation0 glob]$ ls
able alpha baker bravo cast charlie dalta dog easy echo
[kiosk@foundation0 glob]$

​ 以下示例中,前面两个命令通过星号(*)使用简单模式匹配,分别匹配以“a”开头的所有文件名和包含“a”的所有文件名。第三个命令使用星号和方括号匹配以“a”或“c”开头的所有文件名。

1
2
3
4
5
6
7
[kiosk@foundation0 glob]$ ls a*
able alpha
[kiosk@foundation0 glob]$ ls *a*
able alpha baker bravo cast charlie dalta easy
[kiosk@foundation0 glob]$ ls [ac]*
able alpha cast charlie
[kiosk@foundation0 glob]$

​ 第一、二个命令,开头不包括“a”或“c”的文件。

1
2
3
4
5
[kiosk@foundation0 glob]$ ls [!ac]*
baker bravo dalta dog easy echo
[kiosk@foundation0 glob]$ ls [^ac]*
baker bravo dalta dog easy echo
[kiosk@foundation0 glob]$

​ 过滤出文件内任何字母字符的内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
[kiosk@foundation0 glob]$ cat able 
daf
fasfa
154512

fadfa

fa
dggf
gf
fgd
eq
bnv

cz
rew
vbc`:

[kiosk@foundation0 glob]$ grep [[:alpha:]] able
daf
fasfa
fadfa
fa
dggf
gf
fgd
eq
bnv
cz
rew
vbc`:
[kiosk@foundation0 glob]$

​ 以下示例中也可以使用问号 “?”来匹配其中的一些文件名,这两个命令分别仅匹配长度为四个和五个字符的文件名。

1
2
3
4
5
[kiosk@foundation0 glob]$ ls ????
able cast easy echo
[kiosk@foundation0 glob]$ ls ?????
alpha baker bravo dalta
[kiosk@foundation0 glob]$

大括号扩展

​ 大括号扩展用于生成任意字符串。大括号包含字符串的都好分割列表或顺序表达式。结果包含大括号定义之前或之后的文本。大括号扩展可以相互嵌套。您也可以使用双点语法(..),它将扩展为一个顺序序列。例如,大括号内的{a..d}双点语法扩展为 b c d。

1
2
3
4
5
6
7
8
9
10
[kiosk@foundation0 glob]$ touch {tmp,nginx,docker,kubelet}.log
[kiosk@foundation0 glob]$ ls
docker.log kubelet.log nginx.log tmp.log
[kiosk@foundation0 glob]$ touch file{a..c}.txt
[kiosk@foundation0 glob]$ ls file*
filea.txt fileb.txt filec.txt
[kiosk@foundation0 glob]$ touch file{a..c}{1..3}.txt
[kiosk@foundation0 glob]$ ls
filea1.txt filea2.txt filea3.txt fileb1.txt fileb2.txt fileb3.txt filec1.txt filec2.txt filec3.txt
[kiosk@foundation0 glob]$

​ 可以通过大括号扩展的方式去快速创建多个文件或目录及查找等操作。

波形符扩展

​ 波形符()可匹配当前用户的主目录。如果波形符后为斜杠(/)以外的字符串,shell就会将波形符之后的字符串解释为用户名。如果存在匹配项,则用该用户的主目录绝对路径来替换字符串。如果找不到匹配的用户名,shell将使用实际波形符加上该字符串完整输出。如果您以(/)开头,shell就会将该解释为当前用户的主目录,在它之后的字符串就是当前用户主目录下的子目录。

​ 一下示例中,echo命令用于显示波形字符最终输出的值。也可以使用echo命令来显示大括号和变量扩展字符等的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
# root的主目录绝对路径
[kiosk@foundation0 glob]$ echo ~root
/root
# kiosk的主目录绝对路径
[kiosk@foundation0 glob]$ echo ~kiosk/
/home/kiosk/
# ~/当前用户主目录,glob主目录下的子目录
[kiosk@foundation0 glob]$ echo ~/glob
/home/kiosk/glob
# 匹配不到则将参数完整输出
[kiosk@foundation0 glob]$ echo ~ahahha
~ahahha
[kiosk@foundation0 glob]$

变量扩展

​ 变量的作用类似于可以在内存中存储值的命名容器。通过变量,可以从命令行或shell脚本内轻松访问和修改存储的数据。

​ 您可以通过以下语法蒋数据作为值分配给变量:

1
[kiosk@foundation0 glob]$ VARIABLENAME=value

​ 可以使用变量扩展蒋变量名转换为命令行上的值。如果字符串以美元符号($)开头,那么shell就会尝试将该字符串的其余部分用作变量名称,并将它替换为变量中包含的任何值。也就是说美元符可以将它后面的字符串解释(标记)为这是一个变量,而非普通的字符串。

1
2
3
4
5
6
7
8
9
# 定义一个名为:USERNAME的变量,它的值为:Asimov
# 他们是一个键值对的关系
[kiosk@foundation0 glob]$ USERNAME=Asimov
# $打入开头关键字同样也可以TAB为您补全上来
[kiosk@foundation0 glob]$ echo $USER
$USER $USERNAME
[kiosk@foundation0 glob]$ echo $USERNAME
Asimov
[kiosk@foundation0 glob]$

​ 为了预防您取的变量名于其他shell扩展名其冲突而引起错误,您可以将变量的名称放在大括号中,如:${VARIABLENAME}

1
2
3
4
5
6
[kiosk@foundation0 glob]$ USERNAME=LiWeiHu
[kiosk@foundation0 glob]$ echo ${USER}
${USER} ${USERNAME}
[kiosk@foundation0 glob]$ echo ${USERNAME}
LiWeiHu
[kiosk@foundation0 glob]$

​ 变量名只能包含字母(大小写均可)、数字和下划线。变量名称区分大小写,不能以数字开头。

命令替换

​ 命令替换允许命令的输出替换命令行上的命令本身。当命令阔在括号中并且前面有美元符号($)时,会发生命令替换。$(command) 形式可以互相嵌套多个命令扩展。

​ 将date +%A这个原本的命令,用它输出的值去替换这个命令,去输出今天是星期几,于我们没带命令替换的普通字符串,形成一段完整的输出内容。

1
2
3
4
5
[kiosk@foundation0 glob]$ echo Today is $(date +%A)
Today is Thursday
[kiosk@foundation0 glob]$ echo Today time is $(date +%M) minutes past $(date +%l%p).
Today time is 18 minutes past 4PM.
[kiosk@foundation0 glob]$

防止参数被扩展

​ 在Bash shell中,许多字符有着特殊含义。为防止命令行的某些部分上执行shell扩展,您可以为字符和字符串加引号或执行转义。

​ 反斜杠(\)是bash shell中的转义字符。它可以防止其后的字符被扩展。

1
2
3
4
5
6
7
# 未被转义时,$HOME将作为变量去输出key值
[kiosk@foundation0 ~]$ echo $HOME
/home/kiosk
# 通过转义符,$HOME它就是一个普通的字符串输出
[kiosk@foundation0 ~]$ echo \$HOME
$HOME
[kiosk@foundation0 ~]$

​ 在上面的示例中,保护美元符免于扩展,bash将其视为常规字符,因此也就未在$HOME上执行变量扩展。

​ 如果要保护较长的字符串,则使用单引号 (’)或双引号(”)来括起字符串。它们的作用略有不同。单引号将阻止所有shell扩展。双引号则阻止大部分shell扩展。

​ 双引号可抑制美元符号( $ )、反斜杠( \ )、反引号( ` )和感叹号( ! )以外的特殊字符,在引用文本内发挥作用。这回阻止路径名扩展,但仍允许命令替换和变量扩展。

​ 以下示例中,演示了双引号无法抑制变量扩展,依然会输出变量具有的值。

1
2
3
4
5
6
[kiosk@foundation0 ~]$ echo ${HOSTNAME}
foundation0.ilt.example.com
[kiosk@foundation0 ~]$ echo "****** hostname is ${HOSTNAME} ********"
****** hostname is foundation0.ilt.example.com ********
[kiosk@foundation0 ~]$

​ 使用单引号则可以按字面解释抑制引号内所有的特殊字符,以文本输出。

1
2
3
4
5
[kiosk@foundation0 ~]$ echo ${HOSTNAME}
foundation0.ilt.example.com
[kiosk@foundation0 ~]$ echo '****** hostname is ${HOSTNAME} ********'
****** hostname is ${HOSTNAME} ********
[kiosk@foundation0 ~]$