计算机教育缺失的一环_1
前言
这是本人观看该课程所做的第一部分的笔记,包含前三课的内容,水平有限,不一定全面。课后习题这边只贴出了部分个人觉得容易有问题的题目以及个人的答案。
课程链接:点击这里
中文讲义:点击这里
第1讲 - 课程概览与 shell
课程目的
如何充分利用你已经了解的工具,同时也介绍一些你之前不知道的工具并怎么将这些工具结合起来。
SHELL
一般我们的计算机都是自带SHELL,通过打开终端就可看到。SHELL是我们与计算机交互的主要文本界面。
使用SHELL:
SHELL提示符
通常包含了用户名,机器名,当前所在路径,根据你所配置的一些东西,SHELL提示符也会有所不同,如下所示:
在提示符号后,可以输入命令
,命令最终会被 shell
解析。最简单的命令是执行一个程序,比如我们输入date
命令,就会执行date
这个程序,打印出当前的日期和时间:
echo命令:打印参数,如输入echo hello
会输出hello
:
有多个参数时用’’或者””包裹参数即可,如echo "Hello world"
。
像date
这种程序是计算机自带的,存储在文件系统之中。SHELL通过环境变量来搜索这些程序。SHELL就是一种编程语言,可以做到其他语言能实现的基本功能,如for循环、while循环等等。
进行程序搜索的路径:
1 | echo $PATH # 列出路径列表,当你在键入每个程序的名称时,它都会在计算机上挨个查找这些目录中是否有与命令匹配的程序或文件的名称,然后运行它。 |
>>
表示追加。|
(管道符)表示将一个程序的输出和另外一个程序的输入连接起来。
EX:1
2XXX:~$ ls -l / | tail -n1 # 打印列表的最后一行
XXX:~$ curl --head --silent google.com | grep -i content-length # 打印header的内容长度
ROOT用户(根用户)
可以在系统上做任何事情,无视权限限制。但要注意,如果用root用户的身份执行一些错误的操作,有时候会导致不可逆的影响。
sudo
命令:以root用户的身份执行命令。sudo su
命令:切换用户为root用户。- SHELL提示符的
$
表示非root用户,#
表示root用户。 tee
命令:输入内容到文件中同时打印输入。xdg-open
命令:用合适的方式(文本编辑器/浏览器等等)打开指定文件。
课后习题(部分)
- 将以下内容一行一行地写入 semester 文件:通过使用echo加上
1
2!/bin/sh
curl --head --silent https://missing.csail.mit.edu>
以及>>
即可解决,答案如下:1
2echo '#!/bin/sh' > semester
echo 'curl --head --silent https://missing.csail.mit.edu' >> semester - 使用 chmod 命令改变权限,使
./semester
能够成功执行,不要使用 sh semester 来执行该程序。
答案如下:1
2chmod +x semester
./semester # 执行这个文件 - 使用 | 和 > ,将 semester 文件输出的最后更改日期信息,写入主目录下的 last-modified.txt 的文件中
stat
命令来获取semester文件的最后更改日期,个人没想到怎么用上|
,答案如下:1
stat -c %y semester > ~/last-modified.txt
- 写一段命令来从 /sys 中获取笔记本的电量信息,或者台式机 CPU 的温度。
这边就只做获取电量的了,答案如下:1
cat /sys/class/power_supply/BAT0/uevent
第2讲 - Shell 工具和 BASH 脚本
脚本相关
定义变量
语法如下:
1 | foo=bar |
注意,定义时不能带空格,如:foo = bar
。因为空格是用来分隔参数的字符。
定义字符串
有两种方式:
1 | echo "hello" # 双引号,会将变量进行转义 |
定义函数
bash 可以接受参数并基于参数进行操作。
示例函数:
1 | mcd () { |
注意,带有$
的一般都是shell中的保留关键字,如下所示:
$1
到$9
表示bash脚本的第一个到第九个参数$0
表示脚本名称$?
可以获取前一个命令的返回值,示例如下:
注意,退出码常用于进行条件判断。$_
用于获取上一条命令的最后一个参数,如下所示:
!!
获取完整的上一条命令,包括参数(!!
会被直接替换成命令)$(命令)
将一个命令的输出存储到一个变量中,如foo=$(pwd)
,也可以用在字符串中对字符串进行拓展, 如:echo "We are in $(pwd)"
.进程替换:
cat <(ls) <(ls ..)
,<(ls)
会将结果输出到一个临时文件中,并将文件名进行替换,提供给cat
命令,<(ls ..)
同理。$#
表示参数个数$$
表示该脚本的进程的pid$@
表示所有参数
脚本实例
1 |
|
使用man test
或者访问这里可查看一系列的比较运算符.
在输入文件名参数的时候,可以善用通配符?
(1或多)和*
(0或多)来匹配文件。(正则)
EX: ls *.sh #显示当前目录下所有的sh文件
而涉及文件格式变化的话,可以这样convert image.{png,jpg}
.
(PS:注意,想使用 convert
需要安装 imagemagick
,安装指令如下:
1 | sudo apt-get update |
)
当你有一系列的命令,其中包含一段公共子串时,可以用{}
来自动展开这些命令。这在批量移动或转换文件时非常方便。命令如果包含多个{}
,会以笛卡尔积的形式进行拓展。
EX:touch {foo,bar}/{a..j} # 在foo和bar下分别创建命名为a到j的路径/文件夹
如果在终端里使用其他语言的脚本的话,需要更改脚本内开头第一行的 shebang
去指定具体的解释器。例如使用python脚本,shebang
是这样的 #!/usr/bin/env python
。
(PS:/usr/bin/
下有很多二进制文件。)
shellcheck
这样的工具可以帮助你定位 bash 脚本中的错误。
Ubuntu安装:
1 | sudo apt install shellcheck |
除此之外,`locate`也是一个好用的文件查找工具,使用`locate`命令查找会直接输出所有包含参数的路径,安装命令如下:
1
sudo apt install mlocate
grep
命令是用于对输入文本进行匹配的通用工具,常用于查找代码,它有很多选项,一下是部分选项:1
2
3# -R:遍历整个目录。
# -C:获取查找结果的上下文。EX:`grep -C 5` 会输出匹配结果前后五行。
# -v:对结果进行反选,也就是输出不匹配的查找使用过的命令,第一种方式是”上箭头”,但是并不高效。
第二种方法就是使用history
命令查找历史记录,而查找指定的历史记录,可以与grep
相配合,如:history 1 | grep convert
会从头查找所有带convert的记录。
第三种方式就是使用CTRL+R
进行回溯查找,输入内容后连续按CTRL+R
可以继续向下循环查找。
课后习题(部分)
- 阅读
man ls
,然后使用ls
命令进行如下操作:
- 所有文件(包括隐藏文件)
- 文件打印以人类可以理解的格式输出 (例如,使用454M 而不是 454279954)
- 文件以最近访问顺序排序
- 以彩色文本显示输出结果
前三个就不说了,第四个的话就是--color=auto
,不过大部分Linux
系统中,ls
命令的输出已经默认启用了彩色显示,所以加不加效果都是一样的。
- 编写两个bash函数
marco
和polo
执行下面的操作。每当你执行marco
时,当前的工作目录应当以某种形式保存,当执行polo
时,无论现在处在什么目录下,都应当cd
回到当时执行marco
的目录。为了方便debug,你可以把代码写在单独的文件marco.sh
中,并通过source marco.sh
命令,(重新)加载函数。
首先通过vim marco.sh
创建marco.sh
(vim
不熟的话就先记这几个,按i
进入编辑模式,编辑完后按esc
,然后输入:wq
保存退出)。
然后具体内容如下:
1 |
|
- 假设您有一个命令,它很少出错。因此为了在出错时能够对其进行调试,需要花费大量的时间重现错误并捕获输出。 编写一段bash脚本,运行如下的脚本直到它出错,将它的标准输出和标准错误流记录到文件,并在最后输出所有内容。加分项:报告脚本在失败前共运行了多少次。 建立两个脚本,一个叫
1
2
3
4
5
6
7
8
9
10
11
n=$(( RANDOM % 100 ))
if [[ n -eq 42 ]]; then
echo "Something went wrong"
>&2 echo "The error was using magic numbers"
exit 1
fi
echo "Everything went according to plan"bugger.sh
,复制上述脚本;一个叫runner.sh
编写以下内容:这边解释一下1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 保存输出的文件名
output_file="output.log"
# 记录运行次数
count=0
# 循环执行脚本,直到它出错
while true; do
# 每次执行前增加计数
((count++))
# 执行脚本并将标准输出和标准错误流记录到文件
./bugger.sh >> "$output_file" 2>&1
# 检查脚本的退出状态
if [ "$?" -ne 0 ]; then
echo "The script failed after $count runs"
break
fi
done
# 输出记录的内容
echo "Contents of $output_file:"
cat "$output_file"2>&1
,2
表示标准错误流,1
表示标准输出流,>&
表示重定向,这里就是将标准错误流重定向到标准输出流然后一起输入到output.log
内。
然后在source runner.sh
的时候会有bugger.sh
的权限问题,chmod +x bugger.sh
更改执行权限就好了。
4、使用xargs 命令,它可以使用标准输入中的内容作为参数。如 ls | xargs rm 会删除当前目录中的所有文件。您的任务是编写一个命令,它可以递归地查找文件夹中所有的HTML文件,并将它们压缩成zip文件。注意,即使文件名中包含空格,您的命令也应该能够正确执行(提示:查看 xargs的参数-d)。
使用touch {1..10}.html
生成html文件, 然后执行find . -type f -name "*.html" | xargs -d '\n' zip myhtml.zip
即可。-d '\n'
表示以\n
(也就是换行符)为输入的定界符。
第3讲 - Vim编辑器
根据Stack Overflow
的调查显示,最受欢迎的图形编辑器是VS Code
,而基于命令行的最受欢迎的编辑器是Vim
。Vim
的背后具有很多有趣的思想并且得到了许多其他工具广泛的支持与认可(模拟Vim
),不管最后会不会使用Vim
去编程,这些思想也应该去了解学习。
本节课目的:学习Vim
的核心设计哲学以及一些基础的操作。
Vim的核心设计哲学
Vim
是一个模态编辑器(model editor),具有多种操作模式,可以用不同的操作模式去处理不同类型的任务。Vim
避免使用鼠标,因为那样太慢了。Vim
甚至避免用上下左右键因为那样需要太多的手指移动。Vim
需要很少的键盘操作,允许你编辑的速度跟上你思维的速度。Vim
最重要的设计思想是Vim
本身就是一种基于命令的程序语言。
Vim的相关操作
模式切换
打开Vim
会先进入普通模式,该模式用于移动光标、阅读内容、从文件到文件的跳转等。
在这种模式下,不同的按键有不同的含义。最经常用的就是i
键,用于进入插入模式对文件进行编辑。
切换到其他模式的话,按R
进入替换模式,v
进入可视模式,可视模式里又有可视行与可视块,V
进入可视行模式,<C-v>
(Ctrl-V
, 有时也写作 ^V
)进入可视块模式,:
进入命令模式。
从其他模式返回普通模式下用esc
。
打开Vim
在命令行输入vim 指定的文件
,执行即可。
编辑文件
- 按
i
进入插入模式,如图:
(注意,光标在哪里进入插入模式就会在哪里开始插入) - 按
:
进入命令行模式,命令行常用退出vim
。
一些常用命令如下:
:q
,退出:w
,保存(写):wq
,保存然后退出:e {文件名}
,打开要编辑的文件:ls
,显示打开的缓存:help {标题}
,打开帮助文档(按:q
返回):help :w
,打开:w
命令(命令行模式)的帮助文档:help w
,打开w
命令(普通模式)的帮助文档
缓存区、窗口、标签页
- 用
:sp
(上下切分)或者:vsp
(左右切分)来分割窗口 - 标签页可用于多文件编辑,在普通模式下使用
:tabnew 文件名
就可以在新的标签页打开指定文件。使用gt
切换到下一个标签页,gT
切换到上一个标签页 - 一个标签页可以有多个窗口,每个窗口只对应一个缓存区。一个文件维护一个缓存区,同一个缓存区可以在多个窗口中显示。(因此在一个窗口内改动内容,其他窗口也可以同步看到改动的内容。)
:q
更具体来说是关闭当前窗口,:qa
关闭所有的窗口。
普通模式的工作原理
- 移动
- 移动光标:
hjkl
(左, 下, 上, 右) - 以词为单位移动:
w
(下一个词初),b
(上一个词初),e
(移动到词尾或者下一个词的词尾) - 行的移动(源于正则):
0
(移到行初),$
(移到行尾),^
(移到行的第一个非空格字符) - 滚动:
Ctrl-u
(上翻),Ctrl-d
(下翻) - 整个文件的移动:
gg
(文件头),G
(文件尾) - 整个屏幕的移动:
H
(屏幕首行),M
(屏幕中间),L
(屏幕底部) - 查找:
f字符
(移动到光标以后的第一个目标字符),F字符
(移动到光标以前的第一个目标字符),t字符
(移动到光标以后的第一个目标字符的前一个字符),T字符
(移动到光标以前的第一个目标字符的后一个字符)
- 编辑
O
/o
,在光标之上/之下插入行后开始编辑d移动命令
,表示根据移动命令进行删除。例如,dw
删除词,de
删除到词尾,d$
删除到行尾,d0
删除到行头。dd
会删除光标所在的行u
,撤销c移动命令
,表示改变,在执行删除后进入插入模式进行更改。cc
会删除光标所在的行并进入插入模式x
,删除字符(等同于dl
)r
,替换字符(先按r
,再按想要的字符就会进行替换)y移动命令
,复制。p
,粘帖。yy
复制当前行,yw
复制词
基于可视模式的操作
常用可视模式来进行文本块复制。可视模式下大部分的移动命令是可用的。
普通可视模式(正常选中):
可视行模式(按行选中):
可视块模式(按块选中,是常用编辑器无法做到的):~
,反转选中部分的大小写计数
执行指定操作若干次,比如:
5j
,向下移动5行3w
,向后移动三个词7dw
,删除7个词
在可视模式内依旧可用。
- 修饰符
修饰符有i
,表示“内部”或者“在内”,和a
,表示“周围”。光标通过悬停在不同的括号内对不同的括号内容进行操作。
%
,移动到匹配的括号ci(
,改变当前括号内的内容ci[
,改变当前方括号内的内容da'
,删除一个单引号字符串,包括周围的单引号
所以i
与a
之间的关系就是是否包含符号的关系。
具体演示
建议直接看视频,38:00处开始。
自定义Vim
Vim
通过一个名为.vimrc
的文件来进行相关自定义,使用vim ~/.vimrc
命令进行配置操作。在github与许多博客里都可以找到很多相关的内容。Vim
有很多扩展插件可以提供拓展内容(自行了解)。
课后习题(部分)
- 完成 vimtutor。
这边直接在终端里面输入vimtutor
就可以做了,都是一些基础性练习。
后面这些题目就不贴了,都是比较实践性的题目(安装插件,改配置什么的),大家自己去做就好了,能参考的地方也比较多(比如讲义)。