[MIT The Missing Semester] Lec01: The Shell
Lec01:The Shell
本 Lec 主要内容:
- 了解什么是 shell
- shell 的 prompt 各部分的含义
- shell 环境
- 在 shell 中导航
- shell 的权限系统
- 管道符的使用
- root 用户
为什么需要 shell
如今有很多交互接口可以让我们进行指令的输入,比如 GUI、语音输入甚至 AR/VR。这些交互接口可以覆盖 80% 的使用场景。但是,如果你想要完成一个操作,而这个操作恰好没有对应的按钮或语言输入,这些交互接口就捉襟见肘了。为此,使用文字接口 shell 成为了最终的选择 —— 它是全能的,任何你能在图形化接口做的事,它都能做,而且可以做的事更多。
使用 shell
初见 shell
当打开终端时,一般会看到如下内容:
missing:~$ |
这是 shell 最重要的文本接口。这一行内容的含义是:你的==主机名==是 missing 并且==当前的工作目录==(”current working directory”)或者说当前所在的位置是 ~ (表示 ==“home”==)。 $ 符号表示现在的身份==不是 root 用户==(稍后会介绍)。
在 shell 中执行命令
在 shell 中,最简单的命令是执行一个程序:
missing:~$ date |
我们可以在执行命令的同时向程序传递参数:
missing:~$ echo hello |
这里,我们执行了一个程序 echo,并传递了一个参数 hello。
shell 基于空格分割命令并进行解析,然后执行第一个单词代表的程序,并将后续的单词作为程序可以访问的参数。如果希望传递的参数中包含空格(例如一个名为 My Photos 的文件夹),则要么用使用单引号,双引号将其包裹起来,要么使用转义符号
\进行处理(My\ Photos)。
shell 如何知道要执行的程序在哪?
其实,类似于 Python 或 Ruby,shell 是一个==编程环境==,所以它具备变量、条件、循环和函数(下一课进行讲解)。当你在 shell 中执行命令时,你实际上是在执行一段 shell 可以==解释执行==的==简短代码==。
如果你要求 shell 执行某个指令,但是该指令并不是 shell 所了解的编程关键字,那么它会去咨询 环境变量 $PATH,它会列出当 shell 接到某条指令时,进行程序搜索的路径:
missing:~$ echo $PATH |
当我们执行 echo 命令时,shell 了解到需要执行 echo 这个程序,随后它便会在 $PATH 中搜索由 : 所分割的一系列目录,基于名字搜索该程序。当找到该程序时便执行(假定该文件是 可执行程序,后续课程将详细讲解)。
确定某个程序名代表的是哪个具体的程序,可以使用 which 程序。
我们也可以绕过 $PATH,通过直接指定需要执行的程序的路径来执行该程序
在 shell 中导航
路径是什么
shell 中的路径是一组被分割的目录,在 Linux 和 macOS 上使用 / 分割,而在Windows上是 \。路径 / 代表的是系统的根目录,所有的文件夹都包括在这个路径之下,在Windows上每个盘都有一个根目录(例如: C:\)。
相对路径和绝对路径
如果某个路径以 / 开头,那么它是一个 绝对路径,其他的都是 相对路径 。相对路径是指相对于当前工作目录的路径。
一些导航的常用命令
| 命令名 | 作用 | 说明 | 标记和选项(--help 省略) |
|---|---|---|---|
pwd |
获取当前工作目录 | 输出到终端上 | - |
cd |
切换目录 | . 表示当前目录,.. 表示上级目录;可以用绝对路径切换,也可以用相对路径切换。 |
- |
ls |
查看指定目录下包含哪些文件 | 不带参数,则查看当前目录下包含哪些文件 带参数,则查看参数所在路径下包含哪些文件 |
-l:更加详细地列出目录下文件或文件夹信息。 |
mv |
重命名或移动文件 | 后跟两个参数,第一个原文件路径,后一个目的文件路径 | - |
cp |
拷贝文件 | 后跟两个参数,第一个原文件路径,后一个拷贝目的文件路径 | |
mkdir |
新建文件夹 | 后跟多个参数,表示创建多个文件夹 | - |
rm |
删除文件 | 后跟多个参数,为待删除文件路径 | - |
rmdir |
删除文件夹 | 后跟多个参数,为待删除文件夹 只能删除空文件夹 |
- |
cat |
获取一个文件中的所有内容 | 后跟一个参数,为文件路径;默认将内容输出到终端 | |
tail |
获取输入流内容末尾 n 行的内容 |
后跟一个可选参数,表示文件路径;如果输入流中已经有内容,可以不指定;默认输出到终端 | -n?:-n 为选项,? 为任意一个数字,合在一起指定获取末尾内容的行数。 |
grep |
在输入流内容中查找指定内容 | 默认输出到终端 | |
man |
获取某个程序的文档(用户手册) | 后跟一个参数:程序名 | - |
文件和文件夹权限
当使用 ls -l 时,可以看到如下的结果:
missing:~$ ls -l /home |
接下来依次解释这一行输出各部分的含义:
drwxr-xr-x:文件类型和权限 |
1:链接数 |
missing:所有者 |
users:所有组 |
4096:文件大小 |
Jun 15 2019:最后修改时间 |
missing:文件名 |
|---|---|---|---|---|---|---|
| 第一个字符表示这是一个目录 接下来九个字符分成三组,每组三个字符,分别表示不同用户的访问权限: - 第一组表示所有者的权限 - 第二组表示所有组的权限 - 第三组表示其他用户的权限 rwx 三个字母分别代表 ==读、写、执行== 权限 |
这是目录的硬链接数,对于目录来说,这是其子目录(包括 . 和 ..)的数量。这里显示 1,表示该目录下没有子目录(只有 . 和 ..)。 |
这是该目录的所有者,即用户 missing。 |
这是该目录所属的组,即组 users。 |
这是该目录的大小,单位是==字节==。对于目录来说,大小一般是包含目录项所需的字节数。 | 这是该目录最后一次修改的时间。格式为 月 日 年,表示该目录在 2019 年 6 月 15 日进行了最后一次修改。 | 这是目录的名称,即 missing。 |
对于文件来说:
rwx对应的就是文件的 ==读、写、执行==;但是对于文件夹来说:rwx对应的是该文件夹 ==是否能列出其包含的内容、是否能添加、删除、重命名其包含的内容、是否能进入该目录==。**注意⚠️:**如果没有对一个文件夹的执行权限,相当于这个文件夹里的所有文件我都无能为力。
**因为:**不管是ls命令还是写文件还是读文件内容,都需要给出文件的路径,而如果对文件所处文件夹的没有执行权限,在路径解析到文件夹的时候就拒绝访问了,所以不能执行任何操作。
在程序间创建连接
在 shell 中,程序有两个主要的 ==“流”== :它们的==输入流==和==输出流==。 当程序尝试==读取信息==时,它们会从==输入流中进行读取==,当程序==打印信息==时,它们会将==信息输出到输出流==中。 通常,一个程序的输入输出流都是终端。也就是,用户键盘作为输入,显示器作为输出。 但是,我们也可以重定向这些流!
最简单的重定向是 < file 和 > file。这两个命令可以将程序的输入输出流分别重定向到文件:
missing:~$ echo hello > hello.txt |
使用
>是覆盖内容,使用>>是追加内容。
使用管道( pipes ),我们能够更好的利用文件重定向。 | 操作符允许我们==将一个程序的输出和另外一个程序的输入连接起来==:
missing:~$ ls -l / | tail -n1 |
我们会在数据清理一章中更加详细的探讨如何更好的利用管道。
root 用户
对于大多数的类 Unix 系统,有一类用户是非常特殊的,那就是:==根用户(root user)==。 你应该已经注意到了,在上面的输出结果中,根用户几乎不受任何限制,他可以创建、读取、更新和删除系统中的任何文件。
通常我们并不会以根用户的身份直接登录系统,因为这样可能会因为某些错误的操作而破坏系统。 取而代之的是我们会在需要的时候使用 sudo 命令。顾名思义,它的作用是让你可以==以 su(super user 或 root 的简写)的身份执行一些操作==。 当你遇到拒绝访问(permission denied)的错误时,通常是因为此时你必须是根用户才能操作。然而,请再次确认你是真的要执行此操作。
使用
sudo的注意事项⚠️:在 shell 中,|、>、和<是通过 shell 执行的,而不是被各个程序单独执行。echo等程序并不知道|的存在,它们只知道从自己的输入输出流中进行读写。如果要向一个只有 root 用户才有权限访问的文件中写入内容,需要用sudo修饰可以往文件中写入内容的某程序,才能顺利写入。总的要点来说:要访问权限受限的文件时,需要用sudo修饰访问该文件的程序。