寒假_计算机教育缺失的一个学期

寒假_计算机教育缺失的一个学期

周日 2月 09 2025
2734 字 · 12 分钟

MIT-Missing-Semester

这门课程包含许多大学的课堂上不会涉及但却对每个 CSer 无比重要的工具或者知识点。例如 Shell 编程、命令行配置、Git、Vim、tmux、ssh 等等。其中的一些内容对于我们来说可能略有耳闻,或者只知道如何使用而不知道其原理,那么这堂课无疑是了解这些工具的good way。通过这门课程的学习,我了解到了linux的一些高端操作,以及为什么用linux的电脑才是真正的掌握自己的电脑。

Part 1 shell入门

一些简要的文件系统操作这里不再记录。

重定向输入输出 ,<,>

SH
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

重定向输出,(行末追加)>> 管道符| 允许我们将一个程序的输出和另外一个程序的输入连接起来:

SH
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软件可以非常方便的将命令行中你想要的输出进行拷贝,具体用法:

SH
ls | xclip -sel c
  • 一个很基础实用的软件tee,作用是一个三通管道,通过输入流进入后重定向输出到一个文件中,同时在命令行输出输入流。

下面是一个有趣的操作例子

在linux中,系统被挂在在/sys文件中,sysfs 文件则暴露了一些内核(kernel)参数。 因此,不需要借助任何专用的工具,就可以轻松地在运行期间配置系统内核。注意 Windows 和 macOS 没有这个文件wsl也不行()

我们可以对电脑屏幕亮度进行更改。 首先我们来到/sys/class/backlight中,以我的电脑为例,其中有

SH
yoo_koishi@YOOkoishi /s/c/b/intel_backlight> ls
actual_brightness  brightness  max_brightness  scale       type
bl_power           device@     power/          subsystem@  uevent

等文件,这个时候我们就可以通过修改brightness文件来更改屏幕亮度了(需要root权限),一般来说,我们可能希望使用

SH
~$ sudo echo 3 > brightness

来修改文件,不过此时命令行提示我们权限不够,这是为什么? 关于 shell,有件事我们必须要知道。|、>、和 < 是通过 shell 执行的,而不是被各个程序单独执行。 echo 等程序并不知道 | 的存在,它们只知道从自己的输入输出流中进行读写。 所以,根据这点,使用刚才提到的tee软件

SH
~$ 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 中的字符串通过 '" 分隔符来定义,但是它们的含义并不相同。以 ' 定义的字符串为原义字符串,其中的变量不会被转义,而 " 定义的字符串会将变量值进行替换。

BASH
foo=bar
echo "$foo"
# 打印 bar
echo '$foo'
# 打印 $foo

bash支持if,case,while,for这些控制流关键字。 bash 也支持函数,它可以接受参数并基于参数进行操作。

特殊变量 bash中有一些特殊的变量,具有特定的含义,下面是一些常用的特殊变量。

  • $0 - 脚本名
  • $1$9 - 脚本的参数。 $1 是第一个参数,依此类推。
  • $@ - 输入的参数的具体内容(将输入的参数作为一个多个对象,即是所有参数的一个列表)。
  • $* - 输入的参数的具体内容(将输入的参数作为一个单词)。
  • $# - 参数个数
  • $? - 前一个命令的返回值
  • $$ - 当前脚本的进程识别码
  • !! - 完整的上一条命令,包括参数。常见应用:当你因为权限不足执行命令失败时,可以使用 sudo !! 再尝试一次。
  • $_ - 上一条命令的最后一个参数。如果你正在使用的是交互式 shell,你可以通过按下 Esc 之后键入 . 来获取这个值。

示例代码:

BASH
#!/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

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。

所以,我们可以写出类似

BASH
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) 会显示文件夹 foobar 中文件的区别。

统配(globbing)

  • 通配符 - 当你想要利用通配符进行匹配时,你可以分别使用 ?* 来匹配一个或任意个字符。例如,对于文件 foo, foo1, foo2, foo10bar, rm foo? 这条命令会删除 foo1foo2 ,而 rm foo* 则会删除除了 bar 之外的所有文件。

  • 花括号 {} - 当你有一系列的指令,其中包含一段公共子串时,可以用花括号来自动展开这些命令。这在批量移动或转换文件时非常方便。如

SHELL
convert image.{png,jpg}
# 会展开为
convert image.png image.jpg

编写 bash 脚本有时候会很别扭和反直觉。例如 shellcheck 这样的工具可以帮助你定位 sh/bash 脚本中的错误。

shebang (#!)行中使用 env 命令是一种好的实践,它会利用环境变量中的程序来解析该脚本,这样就提高了您的脚本的可移植性。env 会利用我们第一节讲座中介绍过的 PATH 环境变量来进行定位。 例如,使用了 envshebang看上去是这样的 #!/usr/bin/env python

一些工具
  • 觉得man太显示内容长了?不妨试试TLDR pages
  • fd,find的替代品,更友好一些。
  • fzf 模糊查找shell的历史记录。
  • rg,ack,aggrep的替代品,更符合人的直觉。
  • tree,broot,等软件可以很好的展示文件结构。
  • 更好的文件管理器:nnn,ranger
  • xrags 它可以使用标准输入中的内容作为参数。 例如 ls | xargs rm会删除当前目录中的所有文件。
一些终端推荐

个人目前使用较多的终端为tmuxfish,另外也推荐zsh等其他终端。

Part 3 Vim

vim作为一个老牌的代码编辑器,功能十分强大,在程序设计基础实验这门课里,我们或多或少接触了vim。当按下:wq的时候,vim神秘的面孔,逐渐显现。

基本操作模式

  • 正常模式:用于导航和执行命令。
  • 插入模式:插入文本。
  • 可视模式:选择文本块。
  • 命令模式:执行特定命令。

切换模式:

  • i 进入插入模式。
  • v 进入可视模式。
  • : 进入命令模式。
  • <Esc> 返回正常模式。

提示:由于频繁使用 <Esc>,可以考虑将其映射到更方便的键位。

基本操作

插入文本
  • 在正常模式下,按 i 进入插入模式。
  • 输入文本。
  • <Esc> 返回正常模式。
缓冲区、标签页和窗口
  • 缓冲区:Vim 中打开的文件。
  • 标签页:可以包含多个窗口。
  • 窗口:显示缓冲区的视图,一个缓冲区可以在多个窗口中打开。
命令行模式
  • :q:退出。
  • :w:保存。
  • :wq:保存并退出。
  • :e {文件名}:打开文件。
  • :ls:列出缓冲区。
  • :help {命令}:查看

Part 4 数据整理

Part 5 命令行环境


Thanks for reading!

寒假_计算机教育缺失的一个学期

周日 2月 09 2025
2734 字 · 12 分钟