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
Fri 10 Jan 2020 11:49:31 AM EST
missing:~$

我们可以在执行命令的同时向程序传递参数

missing:~$ echo hello
hello

这里,我们执行了一个程序 echo,并传递了一个参数 hello

shell 基于空格分割命令并进行解析,然后执行第一个单词代表的程序,并将后续的单词作为程序可以访问的参数。如果希望传递的参数中包含空格(例如一个名为 My Photos 的文件夹),则要么用使用单引号,双引号将其包裹起来,要么使用转义符号 \ 进行处理(My\ Photos)。

shell 如何知道要执行的程序在哪?

其实,类似于 Python 或 Ruby,shell 是一个==编程环境==,所以它具备变量、条件、循环和函数(下一课进行讲解)。当你在 shell 中执行命令时,你实际上是在执行一段 shell 可以==解释执行==的==简短代码==。

如果你要求 shell 执行某个指令,但是该指令并不是 shell 所了解的编程关键字,那么它会去咨询 环境变量 $PATH,它会列出当 shell 接到某条指令时,进行程序搜索的路径:

missing:~$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
missing:~$ which echo
/bin/echo
missing:~$ /bin/echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

当我们执行 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

接下来依次解释这一行输出各部分的含义:

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
missing:~$ cat hello.txt
hello
missing:~$ cat < hello.txt
hello
missing:~$ cat < hello.txt > hello2.txt
missing:~$ cat hello2.txt
hello

使用 > 是覆盖内容,使用 >> 是追加内容。

使用管道( pipes ),我们能够更好的利用文件重定向。 | 操作符允许我们==将一个程序的输出和另外一个程序的输入连接起来==:

missing:~$ ls -l / | tail -n1
drwxr-xr-x 1 root root 4096 Jun 20 2019 var
missing:~$ curl --head --silent google.com | grep --ignore-case content-length | cut --delimiter=' ' -f2
219

我们会在数据清理一章中更加详细的探讨如何更好的利用管道。

root 用户

对于大多数的类 Unix 系统,有一类用户是非常特殊的,那就是:==根用户(root user)==。 你应该已经注意到了,在上面的输出结果中,根用户几乎不受任何限制,他可以创建、读取、更新和删除系统中的任何文件。

通常我们并不会以根用户的身份直接登录系统,因为这样可能会因为某些错误的操作而破坏系统。 取而代之的是我们会在需要的时候使用 sudo 命令。顾名思义,它的作用是让你可以==以 su(super user 或 root 的简写)的身份执行一些操作==。 当你遇到拒绝访问(permission denied)的错误时,通常是因为此时你必须是根用户才能操作。然而,请再次确认你是真的要执行此操作。

使用 sudo 的注意事项⚠️:在 shell 中,|>、和 < 是通过 shell 执行的,而不是被各个程序单独执行。 echo 等程序并不知道 | 的存在,它们只知道从自己的输入输出流中进行读写。如果要向一个只有 root 用户才有权限访问的文件中写入内容,需要用 sudo 修饰可以往文件中写入内容的某程序,才能顺利写入。总的要点来说:要访问权限受限的文件时,需要用 sudo 修饰访问该文件的程序。