MIT-Missing-Semester
这门课程包含许多大学的课堂上不会涉及但却对每个 CSer 无比重要的工具或者知识点。例如 Shell 编程、命令行配置、Git、Vim、tmux、ssh 等等。其中的一些内容对于我们来说可能略有耳闻,或者只知道如何使用而不知道其原理,那么这堂课无疑是了解这些工具的good way。通过这门课程的学习,我了解到了linux的一些高端操作,以及为什么用linux的电脑才是真正的掌握自己的电脑。
Part 1 shell入门
一些简要的文件系统操作这里不再记录。
重定向输入输出 ,<,>
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重定向输出,(行末追加)>> 管道符| 允许我们将一个程序的输出和另外一个程序的输入连接起来:
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上图第二条为对google.com的信息进行数据整理操作,在part4会有更多操作实例。
顺带一提,利用管道符和xclip软件可以非常方便的将命令行中你想要的输出进行拷贝,具体用法:
ls | xclip -sel c- 一个很基础实用的软件
tee,作用是一个三通管道,通过输入流进入后重定向输出到一个文件中,同时在命令行输出输入流。
下面是一个有趣的操作例子
在linux中,系统被挂在在/sys文件中,sysfs 文件则暴露了一些内核(kernel)参数。 因此,不需要借助任何专用的工具,就可以轻松地在运行期间配置系统内核。注意 Windows 和 macOS 没有这个文件, wsl也不行()
我们可以对电脑屏幕亮度进行更改。 首先我们来到/sys/class/backlight中,以我的电脑为例,其中有
yoo_koishi@YOOkoishi /s/c/b/intel_backlight> ls
actual_brightness brightness max_brightness scale type
bl_power device@ power/ subsystem@ uevent等文件,这个时候我们就可以通过修改brightness文件来更改屏幕亮度了(需要root权限),一般来说,我们可能希望使用
~$ sudo echo 3 > brightness来修改文件,不过此时命令行提示我们权限不够,这是为什么? 关于 shell,有件事我们必须要知道。|、>、和 < 是通过 shell 执行的,而不是被各个程序单独执行。 echo 等程序并不知道 | 的存在,它们只知道从自己的输入输出流中进行读写。 所以,根据这点,使用刚才提到的tee软件
~$ echo 3 | sudo tee brightness就可以实现对屏幕亮度的更改了。
此外还有我们还可以对键盘上的灯光进行操控。
在/sys/class/leds目录下可以对电脑的灯光进行控制。通过相同的操作,我们可以利用大写锁定键的灯光来实现邮件提醒的操作。
Part 2 shell工具与脚本
shell脚本
大多数 shell 都有自己的一套脚本语言,包括变量、控制流和自己的语法。shell 脚本与其他脚本语言不同之处在于,shell 脚本针对 shell 所从事的相关工作进行了优化。因此,创建命令流程(pipelines)、将结果保存到文件、从标准输入中读取输入,这些都是 shell 脚本中的原生操作,这让它比通用的脚本语言更易用。
在 bash 中为变量赋值的语法是 foo=bar,访问变量中存储的数值,其语法为 $foo。 需要注意的是,foo = bar (使用空格隔开)是不能正确工作的,因为解释器会调用程序 foo 并将 = 和 bar 作为参数。 总的来说,在 shell 脚本中使用空格会起到分割参数的作用,有时候可能会造成混淆。
Bash 中的字符串通过 ' 和 " 分隔符来定义,但是它们的含义并不相同。以 ' 定义的字符串为原义字符串,其中的变量不会被转义,而 " 定义的字符串会将变量值进行替换。
foo=bar
echo "$foo"
# 打印 bar
echo '$foo'
# 打印 $foobash支持if,case,while,for这些控制流关键字。 bash 也支持函数,它可以接受参数并基于参数进行操作。
特殊变量 bash中有一些特殊的变量,具有特定的含义,下面是一些常用的特殊变量。
$0- 脚本名$1到$9- 脚本的参数。 $1 是第一个参数,依此类推。$@- 输入的参数的具体内容(将输入的参数作为一个多个对象,即是所有参数的一个列表)。$*- 输入的参数的具体内容(将输入的参数作为一个单词)。$#- 参数个数$?- 前一个命令的返回值$$- 当前脚本的进程识别码!!- 完整的上一条命令,包括参数。常见应用:当你因为权限不足执行命令失败时,可以使用 sudo !! 再尝试一次。$_- 上一条命令的最后一个参数。如果你正在使用的是交互式 shell,你可以通过按下 Esc 之后键入 . 来获取这个值。
示例代码:
#!/bin/bash
echo "脚本的名字是:$0"
echo "输入的第一个参数:$1"
echo "输入的第二个参数:$2"
echo "输入的参数个数:$#"
echo "所有参数(使用\$@):$@"
echo "所有参数(使用\$*):$*"
echo "上一个命令的返回值:$?"
echo "当前 Shell 环境的进程ID号:$$"
n=1
echo "使用\$@的参数列表为:"
for temstr in "$@"
do
echo "第$n个参数是:$temstr"
let n+=1
done
n=1
echo "使用\$*的参数列表为:"
for temstr in "$*"
do
echo "第$n个参数是:$temstr"
let n+=1
done假设脚本名为 test.sh,执行命令 ./test.sh 1 2 3,输出结果如下: 脚本的名字是:./test.sh
输入的第一个参数:1
输入的第二个参数:2
输入的参数个数:4
所有参数(使用$@):1 2 3 4
所有参数(使用$*):1 2 3 4
上一个命令的返回值:0
当前 Shell 环境的进程ID号:12345
使用$@的参数列表为:
第1个参数是:1
第2个参数是:2
第3个参数是:3
第4个参数是:4
使用$*的参数列表为:
第1个参数是:1 2 3 4返回值妙用 命令通常使用 STDOUT 来返回输出值,使用 STDERR来返回错误及错误码,便于脚本以更加友好的方式报告错误。 返回码或退出状态是脚本/命令之间交流执行状态的方式。返回值 0 表示正常执行,其他所有非 0 的返回值都表示有错误发生。
退出码可以搭配 &&(与操作符)和||(或操作符)使用,用来进行条件判断,决定是否执行其他程序。它们都属于短路 运算符(short-circuiting) 同一行的多个命令可以用; 分隔。程序true的返回码永远是 0,false的返回码永远是 1。
所以,我们可以写出类似
false || echo "Oops, fail"来进行一些error handling。
命令替换(command substitution) 可以通过$( CMD )这样的方式来执行CMD命令,例如,如果执行 for file in $(ls) ,shell 首先将调用 ls ,然后遍历得到的这些返回值。还有一个冷门的类似特性是 进程替换(process substitution), <( CMD )会执行 CMD 并将结果输出到一个临时文件中,并将 <( CMD ) 替换成临时文件名。这在我们希望返回值通过文件而不是 STDIN 传递时很有用。例如, diff <(ls foo) <(ls bar) 会显示文件夹 foo 和 bar 中文件的区别。
统配(globbing)
通配符 - 当你想要利用通配符进行匹配时,你可以分别使用
?和*来匹配一个或任意个字符。例如,对于文件foo,foo1,foo2,foo10和bar,rm foo?这条命令会删除foo1和foo2,而rm foo*则会删除除了bar之外的所有文件。花括号
{}- 当你有一系列的指令,其中包含一段公共子串时,可以用花括号来自动展开这些命令。这在批量移动或转换文件时非常方便。如
convert image.{png,jpg}
# 会展开为
convert image.png image.jpg编写 bash 脚本有时候会很别扭和反直觉。例如 shellcheck↗ 这样的工具可以帮助你定位 sh/bash 脚本中的错误。
在 shebang (#!)行中使用 env 命令是一种好的实践,它会利用环境变量中的程序来解析该脚本,这样就提高了您的脚本的可移植性。env 会利用我们第一节讲座中介绍过的 PATH 环境变量来进行定位。 例如,使用了 env的 shebang看上去是这样的 #!/usr/bin/env python。
一些工具
- 觉得
man太显示内容长了?不妨试试TLDR pages↗ fd,find的替代品,更友好一些。fzf模糊查找shell的历史记录。rg,ack,ag,grep的替代品,更符合人的直觉。tree,broot,等软件可以很好的展示文件结构。- 更好的文件管理器:
nnn,ranger。 xrags它可以使用标准输入中的内容作为参数。 例如ls | xargs rm会删除当前目录中的所有文件。
一些终端推荐
个人目前使用较多的终端为tmux和fish,另外也推荐zsh等其他终端。(9.26修改)
Part 3 Vim
vim作为一个老牌的代码编辑器,功能十分强大,在程序设计基础实验这门课里,我们或多或少接触了vim。当按下:wq的时候,vim神秘的面孔,逐渐显现。
基本操作模式
- 正常模式:用于导航和执行命令。
- 插入模式:插入文本。
- 可视模式:选择文本块。
- 命令模式:执行特定命令。
切换模式:
- 按
i进入插入模式。 - 按
v进入可视模式。 - 按
:进入命令模式。 - 按
<Esc>返回正常模式。
提示:由于频繁使用 <Esc>,可以考虑将其映射到更方便的键位。
基本操作
插入文本
- 在正常模式下,按
i进入插入模式。 - 输入文本。
- 按
<Esc>返回正常模式。
缓冲区、标签页和窗口
- 缓冲区:Vim 中打开的文件。
- 标签页:可以包含多个窗口。
- 窗口:显示缓冲区的视图,一个缓冲区可以在多个窗口中打开。
命令行模式
:q:退出。:w:保存。:wq:保存并退出。:e {文件名}:打开文件。:ls:列出缓冲区。:help {命令}:查看
Part 4 数据整理
Part 5 命令行环境
…无限拖更下去
