教授本科生 Unix 课程

背景故事——接手 Unix 课程

2002 年,我还是一名计算机科学专业的本科生,那是我初次真正接触 Unix 系统。我清楚地记得,在我的第一堂编程课上,教授打开了他的 ThinkPad 笔记本,同时以这样一句话开始了讲座:

“本系的教授分为两种:一种使用 Unix——我属于这一类;另一种使用 Windows——那就是其他所有人。”

他不仅教我们编程,还完全在命令行中进行教学。他用 cat 命令展示程序,在 vi 编辑器中编写代码,使用 make 进行编译,在 X11 下播放幻灯片。所有这些都很基础,但却让我产生了浓厚的兴趣——或许是因为我从小用 DOS,却从未意识到终端还能带来什么样的体验。毕竟,在当时的计算机科学圈子里,能在自己的电脑上运行 Linux 或其他 Unix 系统,就意味着你是个“酷”家伙。

在他的课上,我学完了高级编程、操作系统,接着又修了分布式系统课程。到那时,我已经在自己的笔记本上安装了 Linux,并在发现 FreeBSD 后,很快就完全转向了它。

这位教授还开设了一门非必修课程,名为 Unix for Developers(面向开发者的 Unix)。在这门课上,Unix 本身就是主要的学习内容。虽然它的风格有些“老派”,但对我来说却非常有吸引力。我们学习了各种 Unix 工具,学会了如何高效地编辑文件,并使用 shell 和 awk 编写脚本,以便在需要时补充缺失的功能。这门课很有挑战性,但我渴望学习,并在自己的系统上尽可能多地尝试。

随着时间推移,教授最终换用了 Mac(许多学生也随之跟进),并且参与了更多的课程和项目工作,因而没有时间再教授 Unix for Developers 这门课了。那时,我已经毕业,并在系里担任实验室工程师。他可能还记得我对这门课的热情,于是问我是否愿意接手。我答应了,他向我介绍了课程的运作方式。

当时的课程内容已经有些过时,比如仍然讲授 Linux 2.4 版本的内核,而 Linux 2.6 早已发布。因此,我不仅对课程内容进行了更新,还在其中加入了一些 BSD 相关的内容。

几年后,我用德语教授了这门课程后,学校问我是否愿意用英语授课,以便让交换生也能学习。由于很多 Unix 相关的概念本身就是英语,翻译成德语反而不够准确,我便重新整理了一遍课程讲义并翻译成了英文。从那以后,我一直用英语授课,甚至偶尔在一些会议上将部分内容作为教程分享。

但让我们回到最初的那些日子……

课程组织结构

就这样,我接手了一门必修课,并需要安排一个学期的课程内容。这门课在冬季学期授课,大致覆盖 10 月到 1 月间的 15 周,中间有圣诞假期。书面考试安排在 2 月,这意味着从最后一节课到考试日,学生约有两周的时间进行复习。

课程包括每周一次的 90 分钟讲座,以及单次 3 小时的实验课。由于这门选修课很受欢迎,通常会有 40 名学生选修。因此,每个实验小组大约 16 人,每 14 天轮流上一次实验课,这样每个小组总共会有 5 次实验。实验课虽然不评分,但学生必须完成(通常是两人一组)才能获得考试资格。课程没有期中考核,最终成绩完全由考试结果决定。

这个评分体系曾被多次讨论,特别是是否应该对实验课进行评分,毕竟学生投入了不少精力。但在这所德国大学中,大多数课程都采用类似的结构(尽管有少数例外),因此它已成为一种固定模式。

由于这是门选修课,选修的学生都是对这个主题感兴趣的。没有任何学生必须选修这门课才能毕业——他们只需要在成绩单上修满一定数量的选修课程,而具体选哪几门完全由他们自己决定。这不仅减少了总体的学生数量,也导致选修这门课的学生大致可以分为两类:一类是想学习 Unix 但几乎没有基础的,另一类是已经熟悉 Unix,想进一步深入学习(或者只是想拿个轻松的学分)。稍后我们会看到,如何平衡这两类学生的需求并不总是那么容易……

讲座

正如前面提到的,当我接手这门课程时,它已经有些过时,并且在此之前已经停开了一段时间。我认为可以加入一些 BSD 相关的内容,使课程更具 Unix 通用性,反正我也需要重新制作幻灯片。

每学期的第一节课,总会有学生问:

“我们要用哪款 Linux 发行版?”

这个问题往往会引起争论,因为 Linux 发行版实在太多了。如果我说 Ubuntu,Linux Mint 用户会失望;如果我说 Mint,则 Arch Linux 用户会大跌眼镜。

为了避免这种情况(同时也让所有人有机会学习新知识,而不影响他们已有的习惯),我通常会这样回答:

“所有发行版,即没有特定的发行版。我们将使用 FreeBSD,但如果有人想用自己喜欢的发行版,我不会阻止你。毕竟,这是门入门课程,而不是填鸭课程。”

我向学生解释,如果他们是新手,那么从 FreeBSD 入门和使用所有 Linux 发行版的起点是一样的,概念也可以很好地迁移。而对于已经熟悉某款 Linux 发行版的学生,他们可以借此机会接触 BSD 系统,并会发现很多基础知识都是通用的。这通常能让所有人都满意,同时我也成功避开了发行版之争。

不过,如果学生选择使用自己喜欢的发行版,那他们就不能指望从我这里得到任何帮助。这是他们的系统,他们的选择,他们的管理工作,而非我的责任。

不同 Linux 发行版的流行程度随着学生一代代更替而变化,而 FreeBSD 一直保持相对稳定——无意外、易上手,而且免费。值得注意的是,我教授的很多内容实际上是与发行版无关的,因此在不同系统之间基本没有区别。有时候,在课堂演示时我们会对比不同系统的细节(稍后会提到),但本质上,我们使用的命令都能完成预期的任务。

课程内容

本课程包含以下内容:

  • Unix 概述(基础知识,如登录、lscp 等命令)

  • 编辑器vi/vim 速成)

  • Shell(命令历史、Tab 补全、重定向、管道、Here 文档、后台作业)

  • Shell 脚本编程 I(变量、控制结构、循环、调试)

  • Shell 脚本编程 IIcdialog 编程、函数、信号捕获 trap

  • grepsedawk(从文件中提取数据,并进行各种处理,awk 编程)

  • 文件系统(在这一部分介绍 ZFS)

  • Ansible(安装、运行临时命令、编写 Playbook,并对多个 jail 并行更改)

这看起来可能不多,但对于 15 周的课程来说,内容已经相当紧张了。有人可能会质疑,“文件系统” 是否适合放在一门偏向编程的课程里。其实,这部分是我当年上这门课时留下的遗产,我认为用 ZFS 替代传统的文件系统概念是个不错的折中方案。

此外,Shell 脚本编程部分的内容被增补了,因为有些(但不是全部)教授会在操作系统必修课中讲解 Shell。我还增加了对话框编程(可以参考 FreeBSD 安装程序的界面来理解它的用途)、函数和信号捕获(trap)。这些内容相互配合得很好,因为 trap 机制通常需要在执行时调用特定的函数。

有些内容会随着时间推移而调整,这取决于我的兴趣和学生的反馈。从现实情况来看,在一节 90 分钟的课上,考虑到提问和讨论,每张幻灯片大约需要 2-3 分钟,因此大概只能舒适地展示 40 张幻灯片。

课堂教学模式

当疫情爆发后,这种传统的授课方式变得难以实施,所以我和大多数同事都转向了翻转课堂(Inverted Classroom)模式。

在这种教学模式下,学生需要提前自学课程内容,而课堂时间主要用于解答问题和讨论难点。这种方式让教师能够提供更丰富的材料,同时利用课堂时间来判断学生是否遇到了共性问题,并进行集中讲解。

当然,这种模式也对学生的主动性提出了更高的要求。如果课堂上没有太多问题,我会假设他们已经理解了(这对内向的学生可能不太友好),然后进行一两个演示——通过投影仪/视频会议共享我的终端。

我发现学生们很喜欢这种方式,因为他们可以立即在自己的机器上尝试,还能看到我犯错误(毕竟人无完人)。相较于传统的“逐张幻灯片讲解”方式,这样的课堂更加动态,也更具吸引力。

课程内容会根据学生的反馈不断添加和更新。如果我发现学生对某个概念感到吃力,我会额外准备几张幻灯片来帮助他们理解。这也取决于学生是否有相关的基础经验,或者完全是 Unix 新手。总体来说,即使是经验丰富的 Unix 用户,在课程中也能学到新东西,所以有些学生以前接触过 Unix 也没有太大影响。

通常,ZFS 和 Ansible 对学生来说都是新颖且令人兴奋的内容,尤其是 ZFS。很多学生在后来(比如进入硕士阶段时)都会告诉我,他们很高兴当初学了 ZFS,还在家用 NAS 上应用了它。

实验课

实验课的目的是让学生通过实际操作来证明他们理解了某个主题,并能够将其应用到具体问题中。学生通常以两人一组合作,并向我展示他们的成果进行评估。所有 5 次实验都必须完成,才能参加期末考试。

实验内容会紧跟课程讲授的内容,但有时也会涉及课堂上没有讲解的部分。这些内容可能是因为太细碎而不适合课堂讲解,或者是一个独立主题,不便纳入课程主线。

实验任务通常包括:

  • 熟悉系统(了解 Unix 的基础概念)

  • 编程练习(或者在此之前,创建有用的 shell 管道)

  • 文本处理

  • 修改系统配置 等类似任务

对我(教师)来说,最难的实验一直是第一个实验——安装 Unix 系统。

原因? 我们的学生通常分为两类:

  • 一部分学生甚至连最基础的安装程序都会卡住;

  • 另一部分学生则早已把系统配置得完美无缺,进入实验室 5 分钟就完成演示,然后直接离开。

如果学生之前安装过任意一款 Unix 发行版,那么 FreeBSD 的特定部分通常很好上手。但如果是初次接触 Unix,新手可能会觉得很难。

第一节实验课的目标是让所有学生最终都拥有一款能用的系统,以便后续课程跟上节奏。待所有人都成功安装了系统,后续实验的难度就会大大降低,因为大家都在同一基础环境上进行练习。

多年来,我尝试了不同的实验教学形式,以找到最适合的方法,既让新手不会被压垮,同时又不让有经验的学生感到无聊。

起初,我使用投影仪,在 VirtualBox 虚拟机里演示安装过程,边操作边讲解相关概念和术语。这种方法部分有效,但也存在问题——有经验的学生往往会直接跳到下一个步骤,而新手则还在听我讲解。这种情况最终让安装指导变成了一场额外的讲座,而不是实验课本身。

后来,我改用另一种方式——提供一份安装后的系统要求,例如:特定的分区布局、一个独立于 root 的本地用户,以及可用的网络连接。

然而,这种方法带来的结果五花八门,尽管所有学生都使用了相同的虚拟硬件平台。有些学生到了 14 天后的实验课忘记了自己的密码,有些人分区划得太小,导致无法安装任何软件。此外,作弊也变得更加容易,因为学生可以直接共享已经配置好的虚拟机映像,然后其他人只需导入即可。

更重要的是,学生并未真正理解安装过程。他们只是一路按回车键,完全不了解背后发生了什么(如分区操作、DHCP 网络配置等)。

手动安装方案

为了解决这些问题,同时让学生更深入理解系统安装的细节,我决定让他们手动安装系统:

  • 进入 shell,手动设置分区

  • 解压 FreeBSD 源码

  • 配置基础网络

  • 安装 bootloader

同时,我还提供了详细的说明,解释每个命令的作用。

为了防止作弊,我要求他们在 gpart 中用 VirtualBox 生成的唯一磁盘 ID 来标记分区。这样,每个系统都有自己的 ID,我可以轻松检查是否有重复的安装配置。

这套方案在一定程度上有效,但仍然有一些挑战:

  • 有些学生安装完后重启,却发现系统无法启动,可能是因为不小心把引导代码写到了错误的分区(例如写到了 swap 分区)。

  • 有些学生中途暂停虚拟机,做其他事情后再继续安装,结果发现 FreeBSD ISO 提供的虚拟 CD 盘已经被卸载,导致所有输入的命令都报 “command not found”。

  • 还有些学生安装完后,一直只是挂起虚拟机而不重启,直到几周后第一次重启,才发现系统根本无法启动。而最糟糕的是,他们所有的解决方案都存储在这个无法启动的系统里。

这些学生通常会来问我如何修复他们的安装问题,而我则需要在几个月后回溯他们的具体安装步骤,来找出问题所在……

尽管我后来在手动安装指南中加入了虚拟机快照的建议,以便学生能随时回滚,但问题依然存在。很多学生不看我的讲解,而是直接翻到下一条命令输入,完全忽略 12 页的详细说明(包括示例图片)。这显然违背了手动安装的初衷——帮助他们理解 FreeBSD 安装过程及其组成部分。

当然,新手在这个实验上的挣扎远多于 Unix 经验丰富的学生。不过,好消息是,大多数学生最终都能顺利完成实验,只有少数学生遇到困难。

后续的新实验模式

目前,我正在和一个小型学生团队合作,尝试新的实验课模式。我们计划给每个学生提供一个预配置的 jail 服务器,其中运行着某个应用程序。

学生的任务是:保持该应用正常运行,而我的任务是在他们的系统中注入各种故障,让他们找到并修复问题。

为了增加挑战性,我们会引入全球排行榜,根据学生团队解决问题的速度进行排名。我们设计了自动检查程序,它会扫描系统,判断注入的错误是否已被修复,并给予相应分数。

此外,我还可以为每个团队注入不同类型的错误,甚至同时引入多个故障,例如:

  • 关闭关键服务

  • 移除执行权限

  • 删除关键文件

这些故障的可能性几乎是无限的(至少在我的设想中是这样)。

核心目标是:

  1. 让学生学会如何维持系统的正常运行,而不是一开始就被安装过程绊住(这更符合企业环境的实际情况)。

  2. 让他们掌握常见错误的排查与修复,提升问题诊断能力。

目前,我们仍在完善实验细节,但我相信这将会是一种更有趣、更具挑战性的学习方式。

考试

要谈论考试,又不能透露太多具体内容,该怎么说呢?

自从几年前我改用全英文授课后,学生们一直担心自己听不懂考试题目。但事实证明,这并不是问题。考试题目通常与编程相关,比如:“找出这段短小的 shell 脚本中的错误”,这种形式能很好地弥合语言障碍。此外,考试还包括:

  • 多项选择题

  • 填空题

  • 编写一个简短的脚本

  • 解释 ZFS 里的 CoW(写时复制)是什么意思

到了这个阶段,学生们已经熟悉这些题型。从成绩来看,新手和有 Unix 经验的学生在本课程中获得好成绩的机会是相同的。我无法判断后者是否有认真复习,但可以肯定的是,完全不复习并不能保证好成绩。

考试通常是实验课内容的变形,这也让我能看出实验中谁真正做了练习,谁只是“搭顺风车”。虽然这对学生和我来说都是个迟来的真相,但有时候我的直觉也未必准确,考试成绩往往能带来意想不到的结果。

考试后的反思

评分完成后,学生可以查看自己的试卷(尽管他们很少会这样做),课程就算正式结束了。但这并不意味着老师的工作也就此告一段落。

由于这是一门每年开设的课程,我会在暑假期间反思和调整教学内容,基于课堂和实验课中的反馈,优化甚至完全重写某些部分。一般来说,我会重点修改:

  • 在实验课上引发大量提问的内容

  • 在考试中学生提出的小问题

同时,我也会关注 Unix 领域的新发展,寻找值得加入课程的新内容。在系统管理工作中,我偶尔会遇到一些有趣的代码片段或问题,之后就可能把它们改编成考试题目。暑假里收集这些材料,不仅能让我自己保持新鲜感,也能为下一届学生带来更丰富的课程体验。

因此,连续两年的课程很少会完全一样,否则不仅我自己会觉得无聊,学生们也可能通过往年的实验和考试答案轻松蒙混过关。

课程的局限性与调整

我是否能教授 Unix 的所有内容,或者所有我认为学生应该掌握的知识?当然不可能。我所能做的只是揭开 Unix 的一角,希望学生能对它产生兴趣,在课程结束后继续深入学习。

一些更高级的主题由其他老师负责,例如:

  • 云应用开发管理

  • Rust 语言的系统编程

  • 其他选修课涉及的进阶内容

偶尔也有学生抱怨我没有讲 Docker,但我会提醒他们,我们已经学习了 jail,它同样具备强大的功能。

课程内容也需要适应时代发展。例如,几年前,我们仍然需要在另一门课程中介绍 HTML 基础,但现在大多数学生已经在学校和业余时间接触过它了。类似的情况也发生在硬件知识上——许多学生从未自己组装过电脑,只使用过成品机器。因此,当我们讨论 CPU、RAM 和存储之间的交互时,这些内容对他们来说可能是全新的,尽管它们已经包含在操作系统必修课里。

如果学生只使用平板电脑,或者只熟悉图形界面,那么让他们适应纯文本的 shell 界面(一个闪烁的光标)可能会很困难。但这不仅仅是 FreeBSD 课程的问题,因为每种 Unix 系统最终都会依赖 shell 交互,即使它们运行在功能齐全的 GUI 上。

课程的意义

尽管 Unix 在操作系统课程中也有所涉及,但那些课程通常更关注:

  • 调度器的工作原理

  • MMU(内存管理单元)的功能

  • 系统调用在编程中的作用

相比之下,我的课程更贴近实际,专注于 Unix 作为日常操作系统的使用。

这门课程当然并不完美,需要不断适应变化。但我喜欢它现在的形式,学生们似乎也很喜欢。


Benedict Reuschling 是 FreeBSD 项目的文档提交者,同时是 文档工程团队 的成员。他曾连任两届 FreeBSD 核心团队 成员,并在德国达姆施塔特应用科技大学管理一个大数据集群。此外,他还为本科生教授《Unix for Developers》课程,并担任 BSDNow.tv 播客的联合主持人。

最后更新于

这有帮助吗?