关键词: Linux


Reference:TLCL (billie66.github.io)

引言

图形用户界面(Graphical User Interface,GUI)让简单的任务更容易完成,而命令行界面(Command Line Interface,CLI)使完成复杂的任务成为可能。

《快乐的Linux命令行》一书面向现代 Linux 命令行用户,传授如何与命令行界面友好相处,如何工作?能做什么?使用命令行最好的方法是什么?

前提条件:

  • 安装 Linux 系统

可使用 WSL,WSL安装记录

学习 shell

一、什么是shell

1.1 初次接触

shell 是一个程序,能够接受命令并且传递给操作系统执行。Linux 发行版都提供一个名为 bash 的shell 程序。bash 全称为 Bourne Again Shell。

同时,终端(Terminal)也能访问 shell。启动终端时,提示如下:

1
fingsinz@FingsinzStudio:~$

其解释如下:当前用户名@主机名:工作目录$

  • 其中 $ 表示这个终端具有 root(超级管理员)权限;
  • 如果是 # 则表示当前权限是普通用户权限。

可以尝试输入一些命令:

1
fingsinz@FingsinzStudio:~$ abcd
  • 上面的命令并不是一条有效命令,只是举例。

还有,可以通过 按键获取上次输入的命令,也可以通过 按键移动光标从而编辑命令。

不要尝试在终端里使用 ctrl + cctrl + v 进行拷贝粘贴操作,这两个控制代码有着不同的含义。

1.2 简单命令

现在尝试运行一些简单的命令:

  1. date,显示系统当前时间和日期。
1
2
fingsinz@FingsinzStudio:~$ date
Tue Jul 9 13:53:43 CST 2024
  1. cal,显示当前月份日历。
1
2
3
4
5
6
7
8
fingsinz@FingsinzStudio:~$ cal
July 2024
Su Mo Tu We Th Fr Sa
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
  1. df,查看磁盘剩余空间数量。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
fingsinz@FingsinzStudio:~$ df
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/sdb 263174212 1673872 248062184 1% /
tmpfs 6499788 0 6499788 0% /mnt/wsl
tools 124064548 105175296 18889252 85% /init
none 6497704 0 6497704 0% /dev
none 6499788 16 6499772 1% /run
none 6499788 0 6499788 0% /run/lock
none 6499788 0 6499788 0% /run/shm
none 6499788 0 6499788 0% /run/user
tmpfs 6499788 0 6499788 0% /sys/fs/cgroup
drivers 124064548 105175296 18889252 85% /usr/lib/wsl/drivers
lib 124064548 105175296 18889252 85% /usr/lib/wsl/lib
C:\ 124064548 105175296 18889252 85% /mnt/c
D:\ 124708860 102747776 21961084 83% /mnt/d
E:\ 488372220 367103492 121268728 76% /mnt/e
F:\ 488372220 416662024 71710196 86% /mnt/f
  1. free,显示空闲内存的数量。
1
2
3
4
fingsinz@FingsinzStudio:~$ free
total used free shared buff/cache available
Mem: 12999576 86816 11784240 80 1128520 12640980
Swap: 4194304 0 4194304
  1. exit,关闭终端。

1.3 幕后控制台

在完全的 Linux 系统下,即使终端仿真器没有运行,在后台仍然有几个终端运行着。它们叫做虚拟终端或者是虚拟控制台。这些终端会话都可以通过按下 Ctrl + Alt + F1Ctrl + Alt + F6 访问。当一个会话被访问的时候,它会显示登录提示框,需要输入用户名和密码。要从一个虚拟控制台转换到另一个,按下 Alt 和 F1-F6 (中的一个)。返回图形桌面,按下 Alt + F7

二、文件系统中跳转

2.1 理解文件系统树

Linux 以分层目录结构来组织所有文件,将所有文件组成了一棵树型目录。文件系统中的第一级目录称为根目录(/)。根目录包含文件和子目录, 子目录包含更多的文件和子目录。

当首次登录系统(或者启动终端仿真器会话)后,当前工作目录是家目录(~)。每个用户都有他自己的家目录,当用户以普通用户的身份操控系统时,家目录是唯一允许用户写入文件的地方。

2.2 文件目录的相关命令

命令 ls 可以列出(一个或多个)目录(默认是工作目录)的内容:

1
2
3
fingsinz@FingsinzStudio:~$ ls /
bin dev home lib lib64 media opt root sbin srv tmp var
boot etc init lib32 lost+found mnt proc run snap sys usr

命令 pwd (print working directory)可以显示当前工作目录:

1
2
fingsinz@FingsinzStudio:~$ pwd
/home/fingsinz

命令 cd 可以进入某个目录,把某个目录作为工作目录:

1
2
3
4
fingsinz@FingsinzStudio:~$ cd /
fingsinz@FingsinzStudio:/$ ls
bin dev home lib lib64 media opt root sbin srv tmp var
boot etc init lib32 lost+found mnt proc run snap sys usr
  • cd 的目录可用绝对路径或相对路径。

  • 绝对路径是以根目录 / 开始。

  • 相对路径中,. 表示当前工作目录,.. 表示当前工作目录的上一级目录(父目录)。

cd 有一些快捷的输入:

  • cd 可以更改工作目录到家目录

  • cd - 可以更改工作目录到先前的工作目录。

  • cd ~user_name 可以更改工作目录到用户家目录。

2.3 文件名的相关规则

关于文件名的重要规则

  1. 以 “.” 字符开头的文件名是隐藏文件。这仅表示,ls 命令不能列出它们,需要用 ls -a 命令。当创建帐号后,几个配置帐号的隐藏文件被放置在家目录下。另外,一些应用程序也会把它们的配置文件以隐藏文件的形式放在你的家目录下面。
  2. 文件名和命令名是大小写敏感的。文件名 “File1” 和 “file1” 是指两个不同的 文件名。
  3. Linux 没有“文件扩展名”的概念。可以用你喜欢的任何名字来给文件起名。文件内容或用途由其它方法来决定。虽然类 Unix 的操作系统,不用文件扩展名来决定文件的内容或用途,但是有些应用程序会。
  4. 虽然 Linux 支持长文件名,文件名可能包含空格,标点符号,但标点符号仅限“.”、“-”、下划线。最重要的是,不要在文件名中使用空格。如果你想表示词与词间的空格,用下划线字符来代替。

三、探究操作系统

3.1 查询命令帮助

命令通常会有一些选项,选项通过一些参数设定,如:

1
command -options arguments

当不清楚命令的用法时,可以使用 man 进行查询,了解其功能以及参数,如:

1
man ls

3.2 ls 的乐趣

对于 ls 比较常用的估计是 ls -l

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
fingsinz@FingsinzStudio:/$ ls -l
total 420
drwxr-xr-x 2 root root 4096 Jul 9 12:04 bin
drwxr-xr-x 2 root root 4096 May 21 2019 boot
drwxr-xr-x 8 root root 2740 Jul 9 12:12 dev
drwxr-xr-x 91 root root 4096 Jul 9 12:44 etc
drwxr-xr-x 3 root root 4096 Jul 9 12:05 home
-rwxr-xr-x 2 root root 644432 Aug 1 2023 init
drwxr-xr-x 20 root root 4096 Jul 9 12:42 lib
drwxr-xr-x 2 root root 4096 Jul 9 12:42 lib32
drwxr-xr-x 2 root root 4096 Jul 9 12:23 lib64
drwx------ 2 root root 16384 Apr 11 2019 lost+found
drwxr-xr-x 2 root root 4096 May 21 2019 media
drwxr-xr-x 7 root root 4096 Jul 9 12:04 mnt
drwxr-xr-x 2 root root 4096 May 21 2019 opt
dr-xr-xr-x 153 root root 0 Jul 9 12:12 proc
drwx------ 2 root root 4096 May 21 2019 root
drwxr-xr-x 9 root root 220 Jul 9 12:23 run
drwxr-xr-x 2 root root 4096 Jul 9 12:04 sbin
drwxr-xr-x 2 root root 4096 Mar 21 2019 snap
drwxr-xr-x 2 root root 4096 May 21 2019 srv
dr-xr-xr-x 11 root root 0 Jul 9 12:12 sys
drwxrwxrwt 2 root root 4096 Jul 9 12:47 tmp
drwxr-xr-x 11 root root 4096 Jul 9 12:42 usr
drwxr-xr-x 13 root root 4096 May 21 2019 var

对于上面输出的第一行 drwxr-xr-x 2 root root 4096 Jul 9 12:04 bin,含义依次如下:

  • drwxr-xr-x 表示文件访问权限。第一个字符表示文件类型,“-”表示普通文件,“d”表示目录;后三个字符是文件所有者的访问权限;再后三个字符是文件所属组中成员的访问权限,最后三个字符是其他所有人的访问权限。完整含义后面讨论。
  • 2 表示文件硬链接数目。
  • root 表示文件所有者用户名。
  • root 表示文件所属用户组名字。
  • 4096 表示文件字节数大小。
  • Jul 9 12:06 表示上次修改文件的时间和日期。
  • bin 表示文件名。

3.4 确定文件类型

命令 file 可以输出文件内容的简单描述。

1
2
fingsinz@FingsinzStudio:~$ file man.png
man.png: PNG image data, 1175 x 731, 8-bit/color RGBA, non-interlaced

3.5 less浏览文件内容

命令 less 可以查看文本文件。

1
fingsinz@FingsinzStudio:~$ less hello.cpp

less 运行起来后,如果文件内容多于一页,那么可以上下滚动文件。按下“q”键,退出 less 程序。下面还有一些常用的键盘命令:

命令 行为
PageUpb 向上翻滚一页
PageDown空格 向下翻滚一页
上箭头 向上翻滚一行
下箭头 向下翻滚一行
G 移到最后一行
1Gg 移动到开头1行
/字符 查找指定字符串
n 向前查找下一个出现的字符串
h 显示帮助

3.6 符号链接和硬链接

运行命令:

1
2
3
4
5
6
7
8
fingsinz@FingsinzStudio:~$ ls -l /bin/
total 15320
-rwxr-xr-x 1 root root 1113504 May 3 2019 bash
...
-rwsr-xr-x 1 root root 64424 Mar 10 2017 ping
lrwxrwxrwx 1 root root 4 Mar 10 2017 ping4 -> ping
lrwxrwxrwx 1 root root 4 Mar 10 2017 ping6 -> ping
...

可以看到,ping4ping6 都有 -> ping,其含义是符号链接(也称为软链接或者 symlink )。在大多数“类Unix”系统中,有可能一个文件被多个文件名所指向。在这种链接下,当使用 ping4 时,实际上是使用 ping

还有一种链接类型,叫做硬链接。硬链接同样允许文件有多个名字,但是硬链接以不同的方法来创建多个文件名。更多见后面章节。

3.7 部分目录含义

目录 含义
/ 根目录,一切起源
/bin 包含系统启动和运行所必需的可执行二进制程序
/boot Linux 内核、初始 RAM 磁盘映像和启动加载程序
/dev 设备结点目录,内核维护着所有设备的列表
/etc 系统层面的配置文件
/home 给每个用户在此分配家目录
/lib 核心系统查询所使用的共享库文件,类似于 Windows 中的 DLL
/lost+found 当部分恢复一个损坏的文件系统时会用到
/media 可移动介质挂载的地方
/mnt 可移动介质(存储空间)挂载的地方
/opt 用来安装可选的软件。这个主要用来存储可能安装在系统中的商业软件产品
/proc 由内核维护的虚拟文件系统,它所包含的文件是内核的窥视孔
/root 超级管理员的家目录
/sbin 包含系统二进制文件,通常为超级用户保留。
/tmp 存储由各种程序创建的临时文件的地方
/usr 包含普通用户所需要的所有程序和文件
/usr/bin 包含系统安装的可执行程序
/usr/lib 包含由 /usr/bin 目录中的程序所用的共享库
/usr/local 是非系统发行版自带程序的安装目录
/usr/sbin 包含许多系统管理程序
/usr/share 包含许多由 /usr/bin 目录中的程序使用的共享数据。
/usr/share/doc 大多数安装在系统中的软件包会包含一些文档
/var 存放动态文件。各种数据库,假脱机文件,用户邮件等等
/var/log 包含日志文件、各种系统活动的记录

四、操作文件和目录

4.1 通配符

通配符,一些特殊字符帮助快速指定一组文件名。

通配符 意义
* 匹配任意多个字符(包括零个或一个)
? 匹配任意一个字符(不包括零个)
[字符] 匹配任意一个属于字符集中的字符
[!字符] 匹配任意一个不是字符集中的字符
[[:class:]] 匹配任意一个属于指定字符集类中的字符

字符类有:

字符类 意义
[:alnum:] 匹配任意一个字母或数字
[:alpha:] 匹配任意一个字母
[:digit:] 匹配任意一个数字
[:lower:] 匹配任意一个小写字母
[:upper:] 匹配任意一个大写字母

举一些例子:

  • *:匹配所有文件。
  • g*:匹配文件名以“g”开头的文件。
  • b*.txt:匹配文件名以“b”开头,中间可以有零个或任意多个字符,且以“.txt”结尾的文件。
  • Data???:匹配以“Data”开头,其后接着3个字符的文件。
  • [abc]*:匹配文件名以“a”或“b”或“c”开头的文件。
  • BACKUP.[0-9][0-9][0-9]:匹配以“BACKUP.”开头,后接三个数字的文件。
  • [[:upper:]]*:匹配以大写字母开头的文件。
  • *[[:lower:]123]:匹配文件名以小写字母结尾,或以“1”、“2”、“3”结尾的文件。

4.2 创建目录

创建目录命令:

1
mkdir directory...

如:

1
2
3
fingsinz@FingsinzStudio:~$ mkdir tests
fingsinz@FingsinzStudio:~$ ls
hello.cpp man.png tests

可以一次性创建多个目录。

4.3 复制文件和目录

复制文件或者目录命令:

1
cp item1 item2
  • 意思是复制文件或目录 item1 到 文件或目录 item2
1
cp item... directory
  • 意思是复制多个文件或目录到 directory 中。

cp 命令有一些常用选项:

选项 意义
-a--archive 复制文件和目录,以及它们的属性,包括所有权和权限。通常副本具有用户所操作文件的默认属性
-i--interactive 重写已存在文件之前,提示用户确认。如果不指定该选项,则默认重写文件
-r--recursive 递归复制目录以及目录中的内容
-u--update 当把文件从一个目录复制到另一个目录时,仅复制目标目录中不存在的文件,或者是文件内容新于目标目录中已经存在 的文件
-v--verbose 显示翔实的命令操作信息

举例:

  • cp file1 file2:复制文件 file1 内容到文件 file2。如果 file2 已经存在,file2 的内容会被 file1 的内容重写。如果 file2 不存在,则会创建 file2
  • cp -i file1 file2:这条命令和上面的命令一样,但是如果文件 file2 存在的话, 在文件 file2 被重写之前,会提示用户确认信息。
  • cp file1 file2 dir1:复制文件 file1 和文件 file2 到目录 dir1。目录 dir1 必须存在。
  • cp dir1/* dir2:使用一个通配符,在目录 dir1 中的所有文件都被复制到目录 dir2 中。dir2 必须已经存在。
  • cp -r dir1 dir2:复制目录 dir1 中的内容到目录 dir2。如果目录 dir2 不存在, 创建目录 dir2,操作完成后,目录 dir2 中的内容和 dir1 中 的一样。如果目录 dir2 存在,则目录 dir1 (和目录中的内 容)将会被复制到 dir2 中。

4.4 移动和重命名文件

mv 命令可以执行文件的移动和文件的命名。使用与 cp 命令类似:

1
mv item1 item2
  • 意思是文件或目录 item1 移动或重命名为 item2
1
mv item... directory
  • 意思是移动多个文件或目录到 directory 中。

mv 命令有一些常用选项:

选项 意义
-i--interactive 重写已存在文件之前,提示用户确认。如果不指定该选项,则默认重写文件
-u--update 当把文件从一个目录移动到另一个目录时,仅移动目标目录中不存在的文件,或者是文件内容新于目标目录中已经存在 的文件
-v--verbose 显示翔实的命令操作信息

举例:

  • mv file1 file2:移动文件 file1 到文件 file2。如果 file2 已经存在,file2 的内容会被 file1 的内容重写。如果 file2 不存在,则会创建 file2。之后 file1 不再存在。
  • mv -i file1 file2:这条命令和上面的命令一样,但是如果文件 file2 存在的话, 在文件 file2 被重写之前,会提示用户确认信息。
  • mv file1 file2 dir1:移动 file1file2 到目录 dir1。目录 dir1 必须存在。
  • mv dir1 dir2:如果 dir2 不存在则创建,并且移动目录 dir1 的内容到目录 dir2 中,同时删除目录 dir1。如果 dir2 存在,则移动 dir1 以及它的内容到目录 dir2

4.5 删除文件和目录

删除文件和目录:

1
rm item..

rm 有一些常用选项:

选项 意义
-i--interactive 在删除已存在文件前,提示确认信息。
-r,–recursive` 递归删除文件。当删除一整个目录时,需要该选项
-f--force 忽视不存在的文件,强力删除
-v--verbose 显示翔实的命令操作信息

举例:

  • rm file1:删除文件 file1
  • rm -i file1:删除之前提示确定。
  • rm -r file dir1:递归删除文件 file1、目录 dir1 以及里面的内容。
  • rm -rf file1 dir1:强制删除文件 file1 和 目录 dir1 以及里面的内容。

注意:rm 命令一旦删除没有复原,你需要知道你删的是什么,特别是与通配符一起用的情况,很容易删完所有文件。

4.6 链接

硬链接时最初 Unix 创建链接的方式,每个文件默认会有一个硬链接,这个硬链接给予文件名字。每创建一个硬链接,就为一个文件创建了一个额外的目录下。硬链接的局限性如下:

  1. 一个硬链接不能关联它所在文件系统之外的文件,即一个链接不能关联与链接本身不在同一个磁盘分区上的文件。
  2. 一个硬链接不能关联一个目录。

一个硬链接和文件本身没有什么区别。当列出一个包含硬链接的目录内容时,会看到没有特殊的链接指示说明。当一个硬链接被删除时,这个链接被删除,但是文件本身的内容仍然存在(这是说,它所占的磁盘空间不会被重新分配),直到所有关联这个文件的链接都删除掉。

符号链接克服了硬链接的局限性。符号链接生效是通过创建一个特殊类型的文件, 这个文件包含一个关联文件或目录的文本指针。在这一方面,和 Windows 的快捷方式差不多。

一个符号链接指向一个文件,而且这个符号链接本身与其它的符号链接几乎没有区别。例如,如果往一个符号链接里面写入东西,那么相关联的文件也被写入。然而,当你删除一个符号链接时,只有这个链接被删除,而不是文件自身。如果先于符号链接删除文件,这个链接仍然存在,但是不指向任何东西。在这种情况下,这个链接被称为坏链接。在许多实现中,ls 命令会以不同的颜色展示坏链接,比如说红色,来显示它们的存在。

ln 命令可以创建硬链接或者符号链接。

  • 创建硬链接:
1
ln file link
  • 创建符号链接:
1
ln -s item link

4.7 实操命令

首先在家目录中创建一个 playground 目录:

1
2
3
fingsinz@FingsinzStudio:~$ mkdir playground
fingsinz@FingsinzStudio:~$ ls
playground

进入 playground 目录,同时创建两个子目录:

1
2
3
fingsinz@FingsinzStudio:~/playground$ mkdir dir1 dir2
fingsinz@FingsinzStudio:~/playground$ ls
dir1 dir2

复制一些数据到 playground 中:

1
2
3
fingsinz@FingsinzStudio:~/playground$ cp /etc/passwd .
fingsinz@FingsinzStudio:~/playground$ ls
dir1 dir2 passwd

尝试一下 cp 的选项:

1
2
3
fingsinz@FingsinzStudio:~/playground$ cp -iv /etc/passwd .
cp: overwrite './passwd'? y
'/etc/passwd' -> './passwd'

感受一下 mv 文件移动,尝试理解下面的操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
fingsinz@FingsinzStudio:~/playground$ ls
dir1 dir2 passwd
fingsinz@FingsinzStudio:~/playground$ mv passwd dir1/
fingsinz@FingsinzStudio:~/playground$ ls dir1
passwd
fingsinz@FingsinzStudio:~/playground$ cd dir1
fingsinz@FingsinzStudio:~/playground/dir1$ mv -v passwd ../dir2/
renamed 'passwd' -> '../dir2/passwd'
fingsinz@FingsinzStudio:~/playground/dir1$ ls ../dir2
passwd
fingsinz@FingsinzStudio:~/playground$
fingsinz@FingsinzStudio:~/playground$ rm -r dir2
fingsinz@FingsinzStudio:~/playground$ ls
dir1
fingsinz@FingsinzStudio:~/playground$ mv dir1/passwd dir2
fingsinz@FingsinzStudio:~/playground$ ls
dir1 dir2
fingsinz@FingsinzStudio:~/playground$ ls dir2
dir2
fingsinz@FingsinzStudio:~/playground$ ls dir1
fingsinz@FingsinzStudio:~/playground$ ls dir1/
  • 注意17行处,此时的 dir2 是一个文件,是 passwd 文件改名后,并不是一个目录。

好的现在恢复原样:

1
2
3
4
5
6
fingsinz@FingsinzStudio:~/playground$ ls
dir1 dir2
fingsinz@FingsinzStudio:~/playground$ mv dir2 passwd
fingsinz@FingsinzStudio:~/playground$ mkdir dir2
fingsinz@FingsinzStudio:~/playground$ ls
dir1 dir2 passwd

再试试创建硬链接:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
fingsinz@FingsinzStudio:~/playground$ ln passwd test
fingsinz@FingsinzStudio:~/playground$ ln passwd dir1/test
fingsinz@FingsinzStudio:~/playground$ ln passwd dir2/test
fingsinz@FingsinzStudio:~/playground$ ls -l . dir1 dir2
.:
total 16
drwxr-xr-x 2 fingsinz fingsinz 4096 Jul 10 14:04 dir1
drwxr-xr-x 2 fingsinz fingsinz 4096 Jul 10 14:04 dir2
-rw-r--r-- 4 fingsinz fingsinz 1562 Jul 10 13:51 passwd
-rw-r--r-- 4 fingsinz fingsinz 1562 Jul 10 13:51 test

dir1:
total 4
-rw-r--r-- 4 fingsinz fingsinz 1562 Jul 10 13:51 test

dir2:
total 4
-rw-r--r-- 4 fingsinz fingsinz 1562 Jul 10 13:51 test
  • 可以看到 passwdtest 文件的硬链接数目都是 4。文件至少有一个硬链接,因为文件名就是由链接创建的。

通过 ls -li 展示文件索引节点信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
fingsinz@FingsinzStudio:~/playground$ ls -li . dir1 dir2
.:
total 16
2261 drwxr-xr-x 2 fingsinz fingsinz 4096 Jul 10 14:04 dir1
2285 drwxr-xr-x 2 fingsinz fingsinz 4096 Jul 10 14:04 dir2
2307 -rw-r--r-- 4 fingsinz fingsinz 1562 Jul 10 13:51 passwd
2307 -rw-r--r-- 4 fingsinz fingsinz 1562 Jul 10 13:51 test

dir1:
total 4
2307 -rw-r--r-- 4 fingsinz fingsinz 1562 Jul 10 13:51 test

dir2:
total 4
2307 -rw-r--r-- 4 fingsinz fingsinz 1562 Jul 10 13:51 test
  • 可知所有的 testpasswd 的索引号都是一样的,这就证实这些文件是同一个文件。

先把之前的硬链接简单删掉,然后创建符号链接玩玩:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
fingsinz@FingsinzStudio:~/playground$ rm test dir1/test dir2/test
fingsinz@FingsinzStudio:~/playground$ ln -s passwd test
fingsinz@FingsinzStudio:~/playground$ ln -s passwd dir1/test
fingsinz@FingsinzStudio:~/playground$ ls -li . dir1
.:
total 12
2261 drwxr-xr-x 2 fingsinz fingsinz 4096 Jul 10 14:13 dir1
2285 drwxr-xr-x 2 fingsinz fingsinz 4096 Jul 10 14:12 dir2
2307 -rw-r--r-- 1 fingsinz fingsinz 1562 Jul 10 13:51 passwd
2364 lrwxrwxrwx 1 fingsinz fingsinz 6 Jul 10 14:13 test -> passwd

dir1:
total 0
2366 lrwxrwxrwx 1 fingsinz fingsinz 6 Jul 10 14:13 test -> passwd
  • 需要注意,此处第14行的 test 应该是红色名字的,这表示是一个坏链接,找不到文件 passwd

删掉这个坏链接,然后进入到 dir1 目录重新建立符号链接:

1
2
3
4
5
6
7
fingsinz@FingsinzStudio:~/playground/dir1$ ls
test
fingsinz@FingsinzStudio:~/playground/dir1$ rm test
fingsinz@FingsinzStudio:~/playground/dir1$ ln -s ../passwd test
fingsinz@FingsinzStudio:~/playground/dir1$ ls -li
total 0
2366 lrwxrwxrwx 1 fingsinz fingsinz 9 Jul 10 14:17 test -> ../passwd
  • 此时第7行的链接应该不是红色的了,是有效链接。
  • 符号链接的文件索引并不一样,但是 ls 命令会提示链接的是什么。

建立符号链接时应当注意目录,符号链接的目录是目标文件的相对目录。建立符号链接时,可以使用绝对路径名,这样万无一失。

最后,删掉 playground/passwd,观察链接情况:

1
2
3
4
5
6
7
8
9
10
11
12
13
fingsinz@FingsinzStudio:~/playground$ ls
dir1 dir2 passwd test
fingsinz@FingsinzStudio:~/playground$ rm passwd
fingsinz@FingsinzStudio:~/playground$ ls -li . dir1
.:
total 8
2261 drwxr-xr-x 2 fingsinz fingsinz 4096 Jul 10 14:17 dir1
2285 drwxr-xr-x 2 fingsinz fingsinz 4096 Jul 10 14:19 dir2
2364 lrwxrwxrwx 1 fingsinz fingsinz 6 Jul 10 14:13 test -> passwd

dir1:
total 0
2366 lrwxrwxrwx 1 fingsinz fingsinz 9 Jul 10 14:17 test -> ../passwd
  • 此时所有的链接都已失效,名字呈红色。

最后的最后,恢复现场,把 playground 一并删了,记得 -r 递归:

1
2
3
4
fingsinz@FingsinzStudio:~/playground$ cd ..
fingsinz@FingsinzStudio:~$ rm -r playground/
fingsinz@FingsinzStudio:~$ ls -li
total 0

五、使用命令

命令可以是:

  1. 一个可执行程序,是诸如 C 和 C++ 语言写成的程序编译的二进制文件,也可以是由诸如 shell,perl, python,ruby 等等脚本语言写成的程序。
  2. 一个 shell 自身的命令。bash 支持若干命令, 例如 cd 命令。
  3. 一个 shell 函数。这些是小规模的 shell 脚本,它们混合到环境变量中。
  4. 一个命令别名。可以定义自己的命令,建立在其它命令之上。

5.1 显示命令类型

type 命令是 shell 内部的命令,会显示命令的类型:

1
type command

一些使用例子:

1
2
3
4
5
6
fingsinz@FingsinzStudio:~$ type ls
ls is aliased to `ls --color=auto'
fingsinz@FingsinzStudio:~$ type cp
cp is /bin/cp
fingsinz@FingsinzStudio:~$ type cd
cd is a shell builtin
  • shell builtin:表示是 shell 自身的命令,内建于 shell 的命令。

5.2 显示可执行程序的位置

为了确定所给定的执行程序的准确位置,使用 which 命令:

1
which exe

由前面可以知道,/bin 目录下存放的是一些二进制文件,所以可以试试:

1
2
3
4
fingsinz@FingsinzStudio:~$ which cp
/bin/cp
fingsinz@FingsinzStudio:~$ which cd
fingsinz@FingsinzStudio:~$
  • which 只能用于显示可执行程序的位置,上面操作中, cd 并不是一个可执行程序,故没有输出。

5.3 获取shell内建命令的帮助文档

有时候我们并不能完全记住每个命令的用法,这个时候需要查阅帮助文档。

  • help 命令可以获取 shell 内建命令的帮助文档。
  • man 命令可以获取程序的帮助文档(手册)。
1
2
3
4
5
6
7
8
fingsinz@FingsinzStudio:~$ help cd
cd: cd [-L|[-P [-e]] [-@]] [dir]
Change ...(省略)
fingsinz@FingsinzStudio:~$ cd --help
cd: cd [-L|[-P [-e]] [-@]] [dir]
Change ...(省略)
fingsinz@FingsinzStudio:~$ man cp
# 省略 man cp 的输出

在大多数Linux 系统中,man 使用 less 工具来显示参考手册。所显示的参考手册,被分成几个章节,它们不仅仅包括用户命令,也包括系统管理员 命令、程序接口、文件格式等等:

章节 内容
1 用户命令
2 程序接口内核系统调用
3 C库函数程序接口
4 特殊文件,比如设备结点和驱动程序
5 文件格式
6 游戏娱乐
7 其他方面
8 系统管理员命令

默认情况下,会自动匹配 man 的对象属于什么内容显示。但如果要查找一 种文件格式,而同时它也是一个命令名时,这种情况没有指定章节号,总是得到第一个匹配项。具体使用:

1
man section xxx

5.4 显示命令说明

手册只是参考,阅读起来很困难。使用 whatis 程序可以显示匹配特定关键字的手册的名字和一行命令说明:

1
2
3
4
fingsinz@FingsinzStudio:~$ whatis rm
rm (1) - remove files or directories
fingsinz@FingsinzStudio:~$ whatis ls
ls (1) - list directory contents

5.5 给命令起别名

使用 alias 命令可以创建自己的命令:

1
alias name='string'

首先,多个命令可以通过 ; 连接在一行使用,比如:

1
2
3
4
5
fingsinz@FingsinzStudio:~$ mkdir playground; cd playground; ls -liha; cd ..; rm playground -r;
total 8.0K
509 drwxr-xr-x 2 fingsinz fingsinz 4.0K Jul 18 11:20 .
1396 drwxr-xr-x 11 fingsinz fingsinz 4.0K Jul 18 11:20 ..
fingsinz@FingsinzStudio:~$
  • 一番操作下来,创建并进入 playground 文件夹,然后列出目录文件,最后退出目录并删除。

在起别名之前最好用 type 命令看看是否已经被用了:

1
2
fingsinz@FingsinzStudio:~$ type test
test is a shell builtin

然后再起别名:

1
2
3
4
5
6
7
fingsinz@FingsinzStudio:~$ alias foo='mkdir playground; cd playground; ls -liha; cd ..; rm playground -r;'
fingsinz@FingsinzStudio:~$ foo
total 8.0K
509 drwxr-xr-x 2 fingsinz fingsinz 4.0K Jul 18 11:22 .
1396 drwxr-xr-x 11 fingsinz fingsinz 4.0K Jul 18 11:22 ..
fingsinz@FingsinzStudio:~$ type foo
foo is aliased to `mkdir playground; cd playground; ls -liha; cd ..; rm playground -r;'

删除别名使用 unalias 命令:

1
2
3
fingsinz@FingsinzStudio:~$ unalias foo
fingsinz@FingsinzStudio:~$ type foo
-bash: type: foo: not found

在此章节介绍中,建立的别名会在 shell 会话结束时会消失。随后的章节里, 会了解怎样把自己的别名添加到文件中去,每次登录系统,这些文件会建立系统环境。

六、重定向

6.1 标准输入、输出和错误

命令运行结果会输送到一个叫做标准输出的特殊文件(经常用stdout表示),而它们的状态信息则送到另 一个叫做标准错误的文件(stderr)。默认情况下,标准输出和标准错误都连接到屏幕,而不是保存到磁盘文件。除此之外,许多程序从一个叫做标准输入stdin)的设备得到输入,默认情况下,标准输入连接到键盘。

I/O 重定向允许更改输出地点和输入来源。一般地,输出送到屏幕,输入来自键盘,但 是通过 I/O 重定向,可以做出改变。

6.2 标准输出重定向

重定向符 > ,比如:

1
2
3
4
fingsinz@FingsinzStudio:~$ ls / > ls-output.txt
fingsinz@FingsinzStudio:~$ ls -lh
total 12K
-rw-r--r-- 1 fingsinz fingsinz 112 Jul 18 11:51 ls-output.txt
  • 重定向符输出的文件如果不存在,会自动创建。

再比如:

1
2
3
4
fingsinz@FingsinzStudio:~$ ls /aaaaa > ls-output.txt
ls: cannot access '/aaaaa': No such file or directory
fingsinz@FingsinzStudio:~$ ls -lh ls-output.txt
-rw-r--r-- 1 fingsinz fingsinz 0 Jul 18 11:53 ls-output.txt
  • 尝试将一个不存在的目录 ls 出来。
  • 错误信息显示在屏幕,并没有输出到文件中,因为 ls 程序不把它的错误信息输送到标准输出,而是输送到标准错误。
  • 每次重定向输出是,文件重视从头开始重写。

这有一个技巧,简单地使用重定向符,没有命令在它之前,这会清空一个已存在文件的内容或是创建一个新的空文件:

1
fingsinz@FingsinzStudio:~$ > ls-output.txt

如果想要追加输出,使用 >>

1
2
3
4
5
6
7
8
fingsinz@FingsinzStudio:~$ ls -lh ls-output.txt
-rw-r--r-- 1 fingsinz fingsinz 0 Jul 18 11:58 ls-output.txt
fingsinz@FingsinzStudio:~$ ls / >> ls-output.txt
fingsinz@FingsinzStudio:~$ ls -lh ls-output.txt
-rw-r--r-- 1 fingsinz fingsinz 112 Jul 18 11:58 ls-output.txt
fingsinz@FingsinzStudio:~$ ls / >> ls-output.txt
fingsinz@FingsinzStudio:~$ ls -lh ls-output.txt
-rw-r--r-- 1 fingsinz fingsinz 224 Jul 18 11:58 ls-output.txt

6.3 标准错误重定向

文件流的标准输入、标准输出和标准错误分别对应 shell 内部的文件描述符012。。shell 使用件描述符提供了一种表示法来重定向文件。标准错误和文件描述符 2 一样:

1
2
3
4
fingsinz@FingsinzStudio:~$ ls /aaaa 2> ls-error.txt
fingsinz@FingsinzStudio:~$ ls -lh ls-error.txt
-rw-r--r-- 1 fingsinz fingsinz 53 Jul 18 16:52 ls-error.txt
fingsinz@FingsinzStudio:~$

6.4 标准输出和错误到同一个文件

使用 &>

1
2
3
fingsinz@FingsinzStudio:~$ ls -l /aaa &> ls-output.txt
fingsinz@FingsinzStudio:~$ ls -lh ls-output.txt
-rw-r--r-- 1 fingsinz fingsinz 52 Jul 18 16:54 ls-output.txt

6.5 处理不需要的输出

如果不需要命令的输出结果,可以重定向到 /dev/null

  • /dev/null 是系统的一个设备,叫做位存储桶,可以接受输入且不对输入做处理。
1
fingsinz@FingsinzStudio:~$ ls -l /aaa 2> /dev/null

6.6 cat命令

cat 命令可以读取一个或多个文件,然后复制到标准输出:

1
cat [file]

cat 的对象只有一个文件时,可以用来显示文件里面的内容:

1
2
3
fingsinz@FingsinzStudio:~$ ls -l /aaa 2> ls-output.txt
fingsinz@FingsinzStudio:~$ cat ls-output.txt
ls: cannot access '/aaa': No such file or directory

cat 的对象有多个文件时,可以用来拼接文件:

1
2
3
4
5
6
7
fingsinz@FingsinzStudio:~$ cat ls-output.txt ls-output.txt
ls: cannot access '/aaa': No such file or directory
ls: cannot access '/aaa': No such file or directory
fingsinz@FingsinzStudio:~$ cat ls-output.txt ls-output.txt > ls-output2.txt
fingsinz@FingsinzStudio:~$ cat ls-output2.txt
ls: cannot access '/aaa': No such file or directory
ls: cannot access '/aaa': No such file or directory

cat 不带参数时,它会从标准输入读入数据并输出到标准输出:

1
2
3
4
fingsinz@FingsinzStudio:~$ cat
Hello World
Hello World
fingsinz@FingsinzStudio:~$
  • 使用 ctrl + d 告诉 cat 从标准输入的读取结束。

6.7 标准输入重定向

使用符号<

1
2
fingsinz@FingsinzStudio:~$ cat < ls-output.txt
ls: cannot access '/aaa': No such file or directory
  • 虽然不使用 <,单靠 cat 也可以完成,但是 < 就是一个重定向标准输入符号,后面会有更好的例子。

6.8 管道线

使用管道操作符 |(竖杠),可以让一个命令的标准输出通过管道送至另一个命令的标准输入:

1
command1 | command2
  • 管道符前面的命令需要有标准输出,后面的命令需要接受标准输入。

如:

1
fingsinz@FingsinzStudio:~$ ls / | less

6.9 过滤器

有可能会把几个命令放在一起组成一个管道线。 以这种方式使用的命令被称为过滤器。

比如:

1
fingsinz@FingsinzStudio:~$ ls / | sort | less
  • sort 具有排序的作用。

6.10 报道或忽略重复行

uniq 从标准输入或单个文件名参数接受数据有序列表(详情查看uniq 手册页),默认情况下,从数据列表中删除任何重复行。

  • 如果想看到重复的数据列表,让 uniq 命令带上 -d 选项。

比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
fingsinz@FingsinzStudio:~$ mkdir playground
fingsinz@FingsinzStudio:~$ cd playground/
fingsinz@FingsinzStudio:~/playground$ ls
fingsinz@FingsinzStudio:~/playground$ > a; > b
fingsinz@FingsinzStudio:~/playground$ mkdir test
fingsinz@FingsinzStudio:~/playground$ > test/a
fingsinz@FingsinzStudio:~/playground$ ls . test/
.:
a b test

test/:
a
fingsinz@FingsinzStudio:~/playground$ ls . test/ | sort | uniq | cat

.:
a
b
test
test/:
fingsinz@FingsinzStudio:~/playground$ ls . test/ | sort | uniq -d | cat
a
  • 先创建一个演示环境,在 playground 里面创建文件 ab和文件夹 test,在文件夹 test 内创建文件 a
  • 使用管道符和 uniq 连接并重定向到 cat 中,输出并没有出现重复的文件 a
  • 第一行是空格是因为,ls 两个目录时中间会空一行,经过 sort 后排序到第一位。

6.11 wc命令

wc(字计数)命令是用来显示文件所包含的行数、字数和字节数:

1
2
fingsinz@FingsinzStudio:~$ wc ls-output.txt
1 9 52 ls-output.txt
  • 输出的三个数字分别是:行数、单词数和字节数。
  • -l 选项可以限制只输出行数。

同样可以通过管道线进行统计数据:

1
2
fingsinz@FingsinzStudio:~/playground$ ls ./ test/ | sort | uniq | wc -l
6
  • 6 表示输出有6行。

6.12 grep命令

grep 用来找到文件中的匹配文本:

1
grep pattern [file...]
  • 匹配的模式支持正则表达式。

比如现在要从系统安装的程序中找到包含 zip 的文件:

1
2
3
4
5
6
7
8
fingsinz@FingsinzStudio:~$ ls /bin /usr/bin | uniq | grep zip
bunzip2
bzip2
bzip2recover
gunzip
gzip
gpg-zip
zipdetails

grep 有一些方便的选项:-i 使得 grep 在执行搜索时忽略大小写(通常,搜索是大小写敏感的);-v 选项会告诉 grep 只打印不匹配的行。

6.13 head和tail命令

head 命令可以输出文件的前几行,tail 命令可以输出文件的后几行。

  • 默认输出十行,可以通过 -n 调整打印的行数。
  • 也可以用到管道线中。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
fingsinz@FingsinzStudio:~$ ls /bin | head
bash
btrfs
btrfs-debug-tree
btrfs-find-root
btrfs-image
btrfs-map-logical
btrfs-select-super
btrfs-zero-log
btrfsck
btrfstune
fingsinz@FingsinzStudio:~$ ls /bin | tail -n 2
zmore
znew

tail 命令的 -f 选项可以持续检测文件,当新内容添加后会立即出现,直至 ctrl + c

6.14 tee命令

tee 命令制造了一个 “tee”安装到管道上。tee 程序从标准输入读入数据,并且同时复制数据到标准输出(允许数据继续随着管道线流动)。

当在某个中间处理阶段来捕捉一个管道线的内容时,这很有帮助,如:

1
2
3
4
5
6
7
8
9
10
fingsinz@FingsinzStudio:~$ ls /bin /usr/bin | sort | tee bin.txt | grep zip
bunzip2
bzip2
bzip2recover
gpg-zip
gunzip
gzip
zipdetails
fingsinz@FingsinzStudio:~$ ls -lh bin.txt
-rw-r--r-- 1 fingsinz fingsinz 14K Jul 18 18:18 bin.txt

配置文件和shell环境

常见任务和基本工具

编写 shell脚本