Lecture1&2 导论与命令行环境
Lecture1¶
glob & regular expression¶
glob 和 regular expression的区别:glob通配符,适合表达路径之类的概念;regular expression正则表达式,适合表达文本的概念
glob * {} ?
glob is a very simple pattern language
regular expression is more complicated
常用¶
sed用来查找替换(内置了自己的编程语言)
grep用来找内容(not recursively default);
find用来找文件(recursively default)
chmod用来更改权限
control+c to cancel
awk从半结构化数据中提取信息(内置了自己的编程语言)
| 管道
<> 文件重定向输入输出(即将文件作为输入内容/输出位置)
/>> to append
if 不是一个program,pipeline不是一个program,它们都是bash language的一部分
question¶
cd 为何内置于shell中?
因为外部程序无法改变父进程,也就是当前 Shell 的工作目录。
bash编程¶
用于将一个功能单独存起来,需要的时候直接调用
homework¶
ls的-l选项(flag)作用是什么?运行ls -l /并观察输出。每一行最前面的 10 个字符分别代表什么?(提示:man ls)
l选项表示更多信息(long),1个字符表示文件类型,9个字符表示权限(依次是所有者,所属组,其他用户)。
其中第一个字符:
/- 普通文件
d 目录
l 符号链接
c 字符设备
b 块设备
p 命名管道(FIFO)
s Unix 域套接字
后面9个字符:r读,w写,x执行
- 在命令
find ~/Downloads -type f -name "*.zip" -mtime +30中,*.zip是一个 「glob」。什么是 glob ?新建一个测试目录并创建一些文件,试试ls *.txt、ls file?.txt、ls {a,b,c}.txt等模式。参见 Bash 手册中的 Pattern Matching 。
glob是shell根据一定的规则自动匹配文件名或路径名的机制
主要包括*,[],{},?(在fish中被弃用)
glob
'单引号'、"双引号"和$'ANSI 引号'有什么区别?写一条命令,输出一个同时包含字面量$、!和换行符的字符串。参见 Quoting 。
| 写法 | 主要行为 |
|---|---|
'单引号' |
内容几乎完全按字面量处理,$、!、\n 都不会被解释;单引号内部不能直接包含单引号 |
"双引号" |
保留空格和换行,但仍会进行 $变量、$(命令) 等展开;在 Bash 交互模式中,! 还可能触发历史展开 |
$'ANSI-C 引号' |
解析 \n、\t、\x41、\u4e2d 等转义序列;普通的 $ 和 ! 通常按字面量处理 |
- Shell 有三条标准流:stdin(0)、stdout(1)、stderr(2)。运行
ls /nonexistent /tmp,把 stdout 和 stderr 分别重定向到两个文件。你将如何把两者都重定向到同一个文件?参见 Redirections 。
分别重定向
| Bash | |
|---|---|
重定向到一个文件
| Bash | |
|---|---|
0: stdin
1: stdout
2: stderr
&> 是一个整体的重定向运算符,把2追加到1的地址里
$?保存上一条命令的退出状态(0 表示成功)。&&仅在前一条成功时执行后一条;||仅在前一条失败时执行后一条。写一个一行命令:仅当/tmp/mydir不存在时才创建它。参见 Exit Status 。
| Bash | |
|---|---|
- 写一个脚本,接收文件名参数(
$1),用test -f或[ -f ... ]检查该文件是否存在,并根据结果输出不同提示。参见 Bash Conditional Expressions 。- 把上一题完成的脚本保存为文件(如
check.sh)。先运行./check.sh somefile,会发生什么?然后执行chmod +x check.sh再试一次。为什么这一步是必须的?(提示:比较chmod前后的ls -l check.sh输出)
- 在脚本的
set选项(flag)里加入-x会发生什么?写个简单脚本试试并观察输出。参见 The Set Builtin 。
会追踪命令的展开
| Bash | |
|---|---|
- 写一条命令,把文件复制为带当天日期的备份文件名(例如
notes.txt→notes_2026-01-12.txt)。(提示:$(date +%Y-%m-%d))参见 Command Substitution
| Bash | |
|---|---|
- 修改讲义中的「复现偶尔才会失败的测试」脚本(flaky test),使它能够从命令行参数接收测试命令,而不是在脚本中写死
cargo test my_test。(提示:$1或$@)参见 Special Parameters 。
使用管道找出你「home 目录」中最常见的 5 种文件扩展名。(提示:组合
find、grep/sed/awk、sort、uniq -c以及head)
xargs会把 stdin 的每一行转换为命令参数。结合find和xargs(不要用find -exec),找出目录中所有.sh文件,并用wc -l统计每个文件行数。加分项:正确处理文件名中的空格。(提示:-print0和-0)参见man xargs。
| Bash | |
|---|---|
- 使用
curl获取 课程网站 的 HTML,并通过grep统计列出了多少讲。(提示:找出每讲课程名称在那份 HTML 中的共性;用curl -s关闭进度输出。)
| Bash | |
|---|---|
jq是处理 JSON 的强大工具。用 curl 获取示例数据 https://microsoftedge.github.io/Demos/json-dummy-data/64KB.json,再用 jq 提取 version 大于 6 的人员姓名。(提示:先jq. 看结构;再试jq '.[] | select(...) | .name')
| Bash | |
|---|---|
awk可以按列值过滤行并改写输出。例如,awk '$3 ~ /pattern/ {$4=""; print}'会只输出第三列匹配pattern的行,并省略第四列。请写一个awk命令:只输出第二列大于 100 的行,并交换第一列和第三列。可用这条命令测试:printf 'a 50 x\nb 150 y\nc 200 z\n'
| Bash | |
|---|---|
lecture 2 命令行环境¶
需要知道的几个概念
- 参数(Arguments)
- 流(Streams)
- 环境变量(Environment variables)
- 返回码(Return codes)
- 信号(Signals)
1、参数¶
Shell的参数本质是纯字符串,由程序决定如何解析这些字符串
通过\(可以访问参数,\)1访问第一个参数,$@以列表形式访问所有参数,$#获取参数个数,$0获取程序本身名称
语法糖:支持传入不定数量的同类型参数,对每个参数执行相同操作。➡️配合通配符使用
2、流¶
管道中的所有程序是并发的
输入流:stdin
输出流:stdout,stderr
fzf:模糊查找,从stdin中逐行读取输入,提供交互式界面筛选和选择
3、环境变量¶
在shell中,空格的作用是分隔参数。
shell变量没有类型,本质上全部都是字符串。
把一个命令的输出保存到变量里:使用命令替换
当shell调用别的程序时,会同时传入环境变量
特性:进程替换,<(command)把输出存入临时文件,在某个程序只接受文件作为输入时很有用
printenv打印当前环境变量
4、返回码¶
表示程序运行结束状态,0表示一切正常,非0表示执行中遇到了问题
Shell中的&&和||分别表示And和Or,Shell中的这两个运算符基于程序的返回码工作
在shell的if中,0表示True,非0表示False
5、信号¶
信号的本质是一种软件终端,如,按下control+c时,会给shell一个中断当前进程的信号
6、远程机器¶
ssh(secure shell)
| Bash | |
|---|---|
ssh还可以非交互式地执行命令
7、终端复用器¶
终端复用器允许同时操控多个shell会话,不再需要nohup技巧
8、定制shell¶
shell本身是通过dotfiles配置的程序之一
如何配置自己的dotfiles
推荐的做法是:放在一个单独的目录里,纳入版本控制,再用脚本通过符号链接(symlink) 链接到实际位置。好处如下:
- 安装方便:登录到一台新机器时,应用这些配置只需要一分钟。
- 可移植性:无论在哪台机器上,工具的行为都尽量保持一致。
便于同步:你可以在任何地方更新 dotfiles,并让它们始终保持同步。
- 变更可追踪:你大概率会在整个职业生涯中一直维护这些 dotfiles,而长期项目保留版本历史总是件好事。
9、shell中的AI¶
homework¶
- 你可能见过像
cmd --flag -- --notaflag这样的命令。这里的--是一个特殊参数,它告诉程序后面不要再继续解析选项(flag)了。也就是说,--后面的所有内容都会被当作位置参数(positional argument)。这有什么用?试着运行touch -- -myfile,然后在不使用--的情况下把它删掉。
| Bash | |
|---|---|
- 进程替换
<(command)可以让你把一个命令的输出当成文件来用。试着配合diff和进程替换,比较printenv与export的输出。它们为什么不一样?(提示:可以试试diff <(printenv | sort) <(export | sort))
fish中使用psub进行进程替换
| Bash | |
|---|---|
- 写两个 bash 函数
marco和polo,行为如下:每次执行marco时,都要以某种方式保存当前工作目录;之后无论你切到哪个目录,只要执行polo,它都应该把你cd回执行marco时所在的目录。为了方便调试,你可以把代码写进marco.sh,然后通过执行source marco.sh把这些定义重新加载到当前 shell。
| Bash | |
|---|---|
- 假设你有一个很少失败的命令。为了调试它,你需要把它的输出保存下来,但等到一次失败运行可能会很耗时。写一个 bash 脚本,不断运行下面这个脚本直到它失败为止,并把标准输出和标准错误分别保存到文件里,最后把结果打印出来。如果你还能顺便报告它运行了多少次才失败,就加分。