COMP2041 Software Construction 是 UNSW 计算机系最让人又爱又恨的课程之一。它横跨 Shell Scripting、Python 文本处理、Perl 和正则表达式——每个工具都有独特的语法陷阱,合在一起对很多同学是巨大挑战。
本文是针对 COMP2041 的系统学习指南,基于历年学生反馈整理,帮你在 Autotest 失败之前就理解常见坑点。
为什么 COMP2041 难?
很多同学学过 Python 或 Java,却在 COMP2041 上碰壁,原因在于:
- Shell 的思维方式完全不同:它不是一门"标准"编程语言,而是命令的组合与流
- Regex 有多种风格:POSIX BRE / ERE / Python
re/ Perl 各有差异 - Autotest 在 Linux 评分,你在 MacOS 开发:环境差异会导致本地能跑、线上失败
- 课程内容多且跳跃:从 bash 到 awk 到 Perl 到 Python,知识点密集
第一部分:Shell Scripting 核心语法
1.1 变量赋值——最常见的 syntax error
# ❌ 错误:等号两侧有空格
name = "Alice"
# ✅ 正确:等号两侧无空格
name="Alice"
echo $name
规则:Shell 里 = 不是运算符,它是赋值语法的一部分,两侧绝对不能有空格。
1.2 引号的三种行为
name="World"
echo "Hello $name" # 双引号:变量展开 → Hello World
echo 'Hello $name' # 单引号:字面量 → Hello $name
echo Hello\ $name # 反斜杠转义 → Hello World(不安全,少用)
实战规则:
- 文件名、路径用双引号:
"$filename"(防空格拆分) - 字面字符串用单引号:
'[0-9]+'(Regex 里常用)
1.3 条件语句与比较
# 数字比较用 -eq -ne -lt -gt -le -ge
if [ "$count" -eq 0 ]; then
echo "Empty"
fi
# 字符串比较用 = !=
if [ "$str" = "hello" ]; then
echo "Match"
fi
# 文件测试
if [ -f "$file" ]; then
echo "File exists"
fi
注意:[ ] 内侧必须有空格,[" $var" = "x"] 是错的,要写 [ "$var" = "x" ]。
1.4 循环
# for 遍历文件
for file in *.txt; do
echo "Processing: $file"
done
# while 读取行
while IFS= read -r line; do
echo "$line"
done < input.txt
IFS= read -r line 是读取文件标准写法:IFS= 防止行首空格被删,-r 防止反斜杠被解释。
第二部分:正则表达式(Regex)——高频失分点
2.1 BRE vs ERE 的区别
| 特性 | BRE(grep 默认) | ERE(grep -E / egrep) |
|---|---|---|
| 分组 | \(abc\) | (abc) |
| 量词 | \+、\? | +、? |
| 或 | | | ` |
实战:写 Regex 时优先用 grep -E(Extended),语法更直观。
2.2 常见 Regex 模式速查
# 匹配邮件
grep -E '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' file.txt
# 匹配 IP 地址(简化版)
grep -E '^([0-9]{1,3}\.){3}[0-9]{1,3}$' file.txt
# 提取 HTML 标签内容
grep -oE '>[^<]+<' file.html
# 匹配一行开头的数字
grep -E '^[0-9]+' file.txt
2.3 sed 替换
# 基本替换(只替换第一个)
sed 's/old/new/' file.txt
# 全局替换(加 g flag)
sed 's/old/new/g' file.txt
# 删除空行
sed '/^$/d' file.txt
# 原地修改文件
sed -i 's/old/new/g' file.txt # Linux GNU sed
sed -i '' 's/old/new/g' file.txt # MacOS BSD sed ← 注意差异!
2.4 awk 基础
# 打印第 2 列
awk '{print $2}' file.txt
# 条件过滤(打印第 3 列 > 100 的行)
awk '$3 > 100 {print}' file.txt
# 计算列的和
awk '{sum += $1} END {print sum}' file.txt
# 自定义分隔符(CSV)
awk -F ',' '{print $1}' file.csv
第三部分:MacOS vs Linux 差异——Autotest 失败的隐藏原因
这是 COMP2041 最坑的部分,很多同学本地测试通过,提交后 Autotest 失败。
关键差异对照表
| 命令 | MacOS (BSD) | Linux (GNU) | 建议 |
|---|---|---|---|
sed -i | 需要 sed -i '' | sed -i 即可 | 开发时用 Docker/WSL |
date | BSD 格式 | GNU 格式,date -d 有效 | 避免依赖 date 命令 |
echo | 不支持 -e | 支持 -e 转义 | 用 printf 代替 |
grep -P | 不支持 Perl Regex | 支持 | 改用 -E |
wc | 输出有前导空格 | 无前导空格 | 注意管道处理空格 |
解决方案
选项1(推荐):用 UNSW CSE 系统开发
# SSH 到 UNSW CSE 服务器
ssh z1234567@login.cse.unsw.edu.au
选项2:本地用 WSL(Windows Subsystem for Linux)或 Docker
# 用 Docker 跑 Ubuntu 环境
docker run -it ubuntu bash
选项3:用 #!/bin/bash 并在提交前手动检查 sed、grep 命令
第四部分:Python 文本处理(COMP2041 后半段)
4.1 文件读取的标准写法
# 读取所有行
with open('input.txt', 'r') as f:
lines = f.readlines()
# 逐行处理(内存友好)
with open('input.txt', 'r') as f:
for line in f:
line = line.rstrip('\n') # 去掉行末换行符
print(line)
4.2 正则表达式(re 模块)
import re
# 匹配和提取
pattern = r'(\d+)-(\d+)-(\d+)' # 日期格式 YYYY-MM-DD
match = re.search(pattern, '2024-06-15')
if match:
year, month, day = match.groups()
print(year, month, day) # 2024 06 15
# 替换
result = re.sub(r'\d+', 'NUM', 'Call 123 or 456')
# → 'Call NUM or NUM'
# 全部匹配
emails = re.findall(r'[\w.]+@[\w.]+', text)
4.3 sys.argv 处理命令行参数
import sys
# sys.argv[0] 是脚本名,sys.argv[1:] 是参数
if len(sys.argv) < 2:
print(f"Usage: {sys.argv[0]} <filename>", file=sys.stderr)
sys.exit(1)
filename = sys.argv[1]
第五部分:Autotest 失败排查清单
拿到 Autotest 失败时,按这个顺序排查:
- 检查输出格式:
diff显示的差异是多了空格、换行符,还是内容错误? - 检查空白处理:
echovsprintf,尾部是否多了换行? - 检查路径:测试时用的相对路径还是绝对路径?
- 检查 shebang:脚本第一行是否有
#!/bin/bash或#!/usr/bin/env python3? - 检查权限:
chmod +x script.sh是否已执行? - 检查 Linux vs MacOS 差异(见第三部分)
- 用
xxd检查隐藏字符:Windows 换行符\r\nvs Unix\n
# 查看文件中的不可见字符
cat -A script.sh # $ 代表行末,^M 代表 \r
dos2unix script.sh # 转换 Windows 换行符
COMP2041 历年考点速查
| 考点 | 频率 | 重点掌握 |
|---|---|---|
| Shell 变量和引号 | ⭐⭐⭐⭐⭐ | 双引号/单引号区别、变量展开 |
| grep/sed/awk 正则 | ⭐⭐⭐⭐⭐ | BRE vs ERE、sed 替换、awk 列处理 |
| Python re 模块 | ⭐⭐⭐⭐ | search/findall/sub/groups |
| Pipeline 管道组合 | ⭐⭐⭐⭐ | 多命令组合处理文本 |
| 文件操作 | ⭐⭐⭐ | with open、readline、sys.argv |
| Perl 基础 | ⭐⭐⭐ | 正则替换、print、split |
需要辅导?
如果你在 COMP2041 的 Assignment 上卡住了,或者 Autotest 失败找不到原因,可以通过微信联系我们的 UNSW CS 辅导导师——大多数导师自己考过 COMP2041,熟悉每个 Assignment 的常见陷阱。
相关资源:
