[MIT]计算机科学课堂中学不到的知识 The Missing Semester

前注:
此笔记内容来自BV1x7411H7wa
本视频几乎所有操作都是在linux系统上运行,如果想体验一下的话,可能需要安装linux系统,或安装linux虚拟机
屏幕显示内容、脚本内容、代码内容使用
```
此处为脚本内容
```
加以标注
大多数平台都提供了Shell, 例如在Windows上有 PowerShell。但是也可以找到别的shell可用,例如bash 。MacOS 通常也有bash的旧版本。
注:PowerShell在资源管理器(打开文件夹)页面,长按Shift,在空白位置右键,即可打开PowerShell
本视频以 Linux 的 Terminal 为例。
注: 终端(terminal)的作用是提供一个命令的输入输出环境,在linux下可使用ctrl+alt+T; shell 是一个命令行解释器,是linux系统的一个外壳,负责外界与linux内核的交互。shell接受用户或者其他应用程序的命令,然后将命令转化为内核能理解的语言并传给内核,内核执行命令完成后,将结果返回给用户或者应用程序。当我们在terminal输入命令后,shell会负责解释命令。
—— https://blog.csdn.net/weixin_38214171/article/details/90050340
Terminal的外观大致像这样
只有在顶部有一行,这就是所谓的shell prompt(shell 提示/shell指令),其中包括用户名,当前使用的机器名字,以及(下文将会提到的)path(路径)
```
[jon@xpanse missing-semester]$
```
你可以自定义配置shell prompt。如果你配置了一些设置之后,shell prompt可能看起来像这样(视频并没有介绍怎么配置,只是略微说了一下)
&6:32
shell可以执行命令。例如 输入命令 date ,屏幕会打印日期和时间
```
[jon@xpanse missing-semester]$ date
Mon 13 Jan 2020 02:12:55 PM EST
[jon@xpanse missing-semester]$
```
shell 也可以执行带有参数(argument)的程序,增加参数可以修改程序的行为。
指令echo 可以打印你列出的参数, 参数只需要空格分隔即可
注: argument 在这里不是“论点”“论据”,视频字幕有误
```
[jon@xpanse missing-semester]$ echo hello
hello
[jon@xpanse missing-semester]$ echo "Hello world"
```
如果参数中带有空格,可以将参数用(英文标点)单引号或双引号括起来,这样即使中间具有空格,也会作为一个参数传输。或者用反斜杠(转义符)将空格转义(escape)。下面两个指令执行结果相同。
```
[jon@xpanse missing-semester]$ echo "Hello world"
[jon@xpanse missing-semester]$ echo hello\ World
```
注:按照弹幕说法以及本人实际实验,PowerShell不能用反斜杠转义空格。
此视频的大多数操作都是针对于linux系统的,有些不能在PowerShell上使用
你可能想知道shell怎么知道这些程序是应该怎样执行的。是这样的,你的电脑中有很多的内置程序(built-in program / builtin program),存储于文件系统中。shell有一套叫做invariant (恒定的,不变的)environment variable(环境变量)的东西用来检索这些内置程序的位置。环境变量可用于(BASH)编程语言。
事实上,Bourne Again SHell(简称BASH)真的是一种编程语言。你打出的shell prompt(shell提示/shell指令)并不是仅仅可以运行带参数的程序,你也可以使用while循环(while loop)或for循环(for loop)以及条件语句(conditionals),也可以使用变量(variable)。下一个讲座将会有很多关于shell脚本的内容。
注: Bourne Again Shell是作为GUN项目开发的,诞生于1987年。许多Linux发行版很快就采用了它。—— https://www.aoetc.com/117a48.html
环境变量储存着,你的主目录、你的用户名等信息存储的位置。
```
[jon@xpanse missing-semester]$ echo $PATH
/usr/local/sbin:usr/local/bin:/usr/bin:/bin:/opt/inter/vtune_
后面内容省略
[jon@xpanse missing-semester]$
```
用美元符号(dollar)+PATH,这样可以打印(show)机器上所有路径。
PATH变量是一个存储着路径的列表,以冒号分隔,shell会从这些路径中寻找程序。每当你输入一个程序名字时,shell会从这些路径中搜索,找到符合名字的程序并运行。
可以用which命令找到指令的位置。
```
[jon@xpanse missing-semester]$ which echo
/usr/bin/echo
[jon@xpanse missing-semester]$
```
路径(path)是表示文件在计算机上的位置的方式。在Linux和MacOS上,这些路径以正斜杠(slash)分隔,而Windows路径上通常以反斜杠(back slash)分隔。在路径最开始的正斜杠表示是文件系统的顶部。echo在文件系统顶部下的usr目录(directory)下的bin目录下。Windows的路径上通常有多个根目录(root),例如C:\\和D:\\,每一个驱动器(Drive)是一个根目录。Windows具有不同的路径层次结构(file system path hierarchies)。而Linux的驱动器全部安装在一个名字空间下。
绝对路径(absolute paths)(与概念”相对路径“相对应)是完全确定一个文件位置的路径。例如上面的echo的路径就是一个绝对路径。还有一个东西叫做“相对路径”(relative paths),相对路径与你当前所在的位置相关。
指令 pwd (present working directory)可以打印当前的工作目录。
指令cd可以更改当前目录
```
[jon@xpanse missing-semester]$ pwd
/home/jon/dev/pdos/classs/missing-semester
[jon@xpanse missing-semester]$ cd /home
[jon@xpanse home]$ pwd
/home
[jon@xpanse home]$
```
有一些特殊地址,一个点(.)和两个点(..)。一个点表示当前目录,两个点表示父目录。
./home 表示当前目录下名为home的子目录
```
[jon@xpanse home]$ cd ..
[jon@xpanse /]$ pwd
/
[jon@xpanse]$ cd ./home
[jon@xpanse home]$
[jon@xpanse home]$ cd ./home
bash: cd: ./home: No such file or dierctory
[jon@xpanse home]$ cd jon/dev/pdos/classes/missing-semester/
[jon@xpanse missing-semester]$ ../../../../../bin/echo world
world
[jon@xpanse missing-semester]$
```
指令ls可以打印出当前路径下的所有文件
```
[jon@xpanse missing-semester]$ ls
404.html data-wrangling.md lectures.html
后面内容省略
[jon@xpanse missing-semester]$ cd ..
[jon@xpanse classes]$ ls
6.824 6.828 6.858 6.HT grade missing-semester web-submit
[jon@xpanse classes]$
```
ls 后面可以带有参数,例如下面的示例,以当前文件夹的父文件夹 .. 为参数
```
[jon@xpanse missing-semester]$ ls ..
6.824 6.828 6.858 6.HT grade missing-semester web-submit
[jon@xpanse missing-semester]$
```
还有一些字符,例如波浪线字符(tilde character, ~)可以带你回到home目录。例如这里,~指的是 /home/jon
可以传给指令cd 参数dash(减号,横杠,-)可以返回到上一次的目录中
注: cd - PowerShell不可用
```
[jon@xpanse /]$ cd ~/dev/pdos/classes/missing-semester
[jon@xpanse missing-semester]$ cd -
/
[jon@xpanse /]$ cd -
/home/jon/dev/pdos/classes/missing-semester
[jon@xpanse missing-semester]$
```
大多数程序都可以以 --help 作为参数,以打印帮助内容
```
[jon@xpanse missing-semester]$ ls --help
Usage: ls [OPTION]... [FILE]...
中间内容省略
-l use a long listing format
中间内容省略
[jon@xpanse missing-semester]$
```
例如,帮助中有这样一条 -l use a long listing format,我们可以实际试验一下。
```
[jon@xpanse missing-semester]$ ls -l
部分内容省略
-rw-r--r-- 1 jon jon 102 Dec 5 14:05 404.html
drwxr-xr-x 1 jon jon 24 Jan 13 12:41 _data
-rw-r--r-- 1 jon jon 18647 Dec 5 14:06 static
-rw-r--r-- 1 jon jon 5671 Dec 28 06:50 virtual-machines.md
-rw-r--r-- 1 jon jon 10073 Dec 5 14:06 web.md
```
我们来看一下这些是什么意思。条目(entries)开头的d表示这是一个目录(directory),所以这里的 \_data 是一个目录,而这里的 404.html 不是一个目录。
```
drwxr-xr-x 1 jon jon 24 Jan 13 12:42 _data
```
第一个字符 d: 是否是文件夹,
二—五字符 rwx: 该文件对于文件所有者的权限
六—八字符 -xr: 该文件对于拥有此文件的组(group)所具有的的权限
九—11字符 r-x: 该文件对于其余所有人的权限
第一个 jon : 文件所有者
第二个 jon : 拥有此文件的组
对于文件:
r : 可以读此文件
w: 可以写此文件
x : 可以执行此文件
\- : 无相应权限
例如, ls -l /bin 中的所有文件都具有 x 权限,因为这个目录下 echo 等指令应该给所有用户开放使用。
对于文件夹:
r : 可以查看有哪些文件在此文目录中
w: 可以重命名、创建或者删除此目录中的文件
x : 如果该目录,及其所有父目录都具有 x 权限,该目录下的文件才可以执行
如果仅具有一个文件的 w 权限,但是没有其所在目录的 w 权限,你只可以清空(empty, v.)它,但不能删除它,因为这会修改目录本身。
部分目录的第一个字母 l 几乎与本次讲座没什么关系,如果好奇的话,请自己查询资料或讲座结束后单独来办公室询问。
注:第一个字符代表文件类型,d是文件夹,l是链接文件,-是普通文件 —— https://blog.csdn.net/chiwen8728/article/details/100649290
mv可以用来移动或重命名文件。例如下面的示例,将 dotfiles.md重命名为foo.md,然后又修改了回去。
```
[jon@xpanse missing-semester]$ ls
[jon@xpanse missing-semester]$ mv dotfiles.md foo.md
[jon@xpanse missing-semester]$ mv foo.md dotfiles.md
```
还有cp指令,可以复制文件
```
[jon@xpanse missing-semester]$ cp dotfiles.md ../food.md
[jon@xpanse missing-semester]$ ls ..
6.824 6.828 6.858 6.HT food.md grade missing-semester web-submit
[jon@xpanse missing-semester]$
```
rm指令可以移除文件
```
[jon@xpanse missing-semester]$ rm ../food.md
[jon@xpanse missing-semester]$
```
在linux上,rm指令默认是不能递归(recursion)的,所以不能通过传入目录作为rm 的参数来删除目录。可以传入-r 标记(flag)即可递归删除,即删除一个目录下所有内容。
rmdir指令可以用来删除目录。如果该目录为空,则会成功删除该目录;
下面是本人在虚拟机上的示例
```
j****@j****-virtual-machine:~$ rm Lab2
rmdir: failed to remove 'Lab2': Directory not empty
j****@j****-virtual-machine:~$
```
mkdir 指令可以用于创建新目录。例如,下面的指令会创建两个目录,分别名为 My 和 Photos。
```
[jon@xpanse missing-semester]$ mkdir My Photos
```
man 指令(manual)接受另一个指令作为参数,然后向你展示该指令的参数。
```
[jon@xpanse missing-semester]$ man ls
```
man ls 和 ls --help 相似,只是 man 更容易阅读,同时还具有示例。
#清屏
Ctrl+L 可以清除终端。
也许你可能需要将多个程序链接在一起,或者与文件操作等需求,而shell给出的流(stream)这个概念可以解决这个问题。每个程序都有两个流,分别为输入流(input stream)和输出流(output stream)。
通常输入流来自于键盘,通过终端输入进程序。而当程序尝试打印一些东西时,会打印到输出流中。
shell 提供了可以重定向输入流和输出流的方式:使用尖括号标志(angle bracket ,<>)。
```
[jon@xpanse missing-semester]$ echo hello > hello.txt
[jon@xpanse missing-semester]$
```
然后shell就会创建一个文件叫 hello.txt ,里面的内容是
```
hello
```
指令 cat 打印文件的内容
弹幕: cat 是 concatenate 的缩写
```
[jon@xpanse missing-semester]$ cat hello.txt
hello
[jon@xpanse missing-semester]$
```
cat 也可以复制(duplicate)它的输入到输出
```
[jon@xpanse missing-semester]$ cat < hello.txt
hello
[jon@xpanse missing-semester]$
```
cat也可以用来复制文件
```
[jon@xpanse missing-semester]$ cat < hello.txt > hello2.txt
[jon@xpanse missing-semester]$ cat hello2.txt
hello
[jon@xpanse missing-semester]$
```
程序cat并不知道输入和输出是否被重定向
>>也可以用来输出,但是是在文件后面追加,而不是覆盖文件
```
[jon@xpanse missing-semester]$ cat < hello.txt > hello2.txt
[jon@xpanse missing-semester]$ cat hello2.txt
hello
[jon@xpanse missing-semester]$ cat < hello.txt >> hello2.txt
[jon@xpanse missing-semester]$ cat hello2.txt
hello
hello
[jon@xpanse missing-semester]$
```
管道符号(pipe character, vertical bar, |)的含义是,将左面程序的输出,作为右面程序的输出,
指令 tail 打印输入的最后1行
注:
通常tail 打印最后10行。tail -n1 打印最后一行
-n\[+\]NUM
n后面可以跟参数决定输出的行数,或是通过跟加号跟参数,输出指定的行数之后的所有行。
```
[jon@xpanse missing-semester]$ ls -l / | tail -n1
drwxr-xr-x 1 root root 116 Jan 13 10:57 var
[jon@xpanse missing-semester]$
```
在这里ls不知道tail, tail也不知道 ls,它们是不同的程序,也没有通过互相兼容来共同运行,仅仅是对输入进行处理,并输出。
管道符号将wires(直译为电线)连接到一起。在这里,ls的输出(output)连接到tail的输入(input),tail的输出输出到terminal
我们也可以将tail的输出重定向(reware)到文件当中
```
[jon@xpanse missing-semester]$ ls -l / | tail -n1 > ls.txt
[jon@xpanse missing-semester]$
```
注:使用↑方向键可以调出刚刚执行过的指令
[jon@xpanse missing-semester]$ curl --head --silent | grep -i content-length
content-lentgh: 219
[jon@xpanse missing-semester]$ curl --head --silent | grep -i content-length | cut --delimiter=' ' -f2
219
[jon@xpanse missing-semester]$
```
管道符号不仅仅可以作用于文本,也可以作用于图像之类的东西
Linux的root user相当于Windows上的管理员用户,其用户ID为0
root用户可以对文件系统做任何事,即使文件不具有读写权限
大多数时候,不会使用root权限,因为root权限很危险。
sudo 指令可以允许你用root权限执行指令。sudo意思是do as su,而su指的是super user
弹幕:
sudo是substitute do ,不是super user do
<-两种说法都有
switch user do
如果你切换到 cd /sys 这是一个全新的世界
```
[jon@xpanse missing-semester]$ cd /sys
[jon@xpanse sys]$ ls
block bus class dev devices firmware fs hypervisor kernel module power
[jon@xpanse sys]$
```
这里的文件实际上并不是文件,而是内核(kernel)参数,即计算机的核心。这里可以查看内核参数,看上去就像文件系统一样
```
[jon@xpanse sys]$ cd class/
[jon@xpanse class]$ ls
backlight dmi input nvme-subsystem remoteproc typec
下面内容省略
[jon@xpanse sys]$ cd backlight/
[jon@xpanse backlight]$ ls
intel_backlight
[jon@xpanse backlight]$ cd intel_backlight/
[jon@xpanse inter_backlight]$ ls
actual_brightness brightness max_brightness scale type
bl_power device power subsystem uevent
[jon@xpanse inter_backlight]$ cat brightness
1060
[jon@xpanse inter_backlight]$ cat max_brightness
1060
[jon@xpanse inter_backlight]$ echo 500 > brightness
bash: brightness: Permission denied
[jon@xpanse inter_backlight]$
```
例如,这个backlight可以直接调节笔记本电脑上的背光。
你可能想到用指令 sudo 来修改,但是不可行
```
[jon@xpanse inter_backlight]$ sudo echo 500 > brightness
bash: brightness: Permission denied
[jon@xpanse inter_backlight]$
```
原因是,在这里,程序 sudo 执行的是 echo 500,将输出发送到名为 brightness的文件,然而打开brightness的并不是 sudo 程序。所以此时出现了权限下降错误(permission down error)。
```
[jon@xpanse inter_backlight]$ echo 1 > /sys/net/ipv4_forward
```
这个指令可以用来设置防火墙。如果前面是英镑符号的话,这个指令可以运行。dollar符号表示你没有以root用户身份运行。
注:我也不知道为啥他管\#符号叫英镑符号
sudo su指令可以切换为超级用户(super user)模式。切换为超级用户模式之后,用户名从原来的jon切换为了root,同时美元符号变成了英镑符号。
```
[jon@xpanse inter_backlight]$ sudo su
[sudo] password for jon:
[root@xpanse inter_backlight]# echo 500 > brightness
[root@xpanse inter_backlight]# exit
[jon@xpanse inter_backlight]$
```
据讲师所说,屏幕亮度变暗了,但是从视频中看不到。
```
[jon@xpanse inter_backlight]$ echo 1060 | sudo tee brightness
1060
[jon@xpanse inter_backlight]$
```
tee命令获取输入并写入到指定的文件中,可用来存储日志文件。
可以用find指令
```
[jon@xpanse inter_backlight]$ cd ..
[jon@xpanse backlight]$ cd leds/
[jon@xpanse leds]$ ls
input4::capslock phy0-led tpacpi::kbd_backlight tpacpi::thinklight
下面内容省略
[jon@xpanse leds]$ cd input4\:\scrolllock
```
也许大多数人不知道什么是scrolllock,也许你在键盘上看到这样一个scrolllock的按键,但是大家不知道这个键是干什么的。这个键已经成了死键了。
```
[jon@xpanse input4::scrolllock]$ cat brightness
0
[jon@xpanse input4::scrolllock]$ echo 1 | sudo tee brightness
1
[jon@xpanse input4::scrolllock]$
```
如果你想设置为,每当收到 email 的时候,scrolllock LED 闪烁的话,可以弄一个程序用来检查是否收集到 email ,然后将输出使用管道字符输出到 sudo tee brightness 中
```
[jon@xpanse missing-semester]$ xdg-open lectures.html
```
xdg-open,这个指令只在linux和macOS上起作用,在windows上叫做open 。这个指令会使用合适的方式打开指定的文件。
---
下节预告:如何完成自动化之类的任务、如何编写运行一堆程序的脚本,如何实现条件语句和循环语句
---
おわり