The Shell
echo $PATH
列出所有环境变量which echo
查找echo的位置- macos、linux路径是斜杠,而windows是反斜杠*
~
用户文件夹-
上一个位置ls --help
查看帮助文档- ~/bin 中文件所有用户均可执行
mv
重命名/移动文件位置cp
复制文件rm
删除文件(永久删除,不进回收站) rmdir 删除指定空目录Ctrl
+L
清屏终端并回到顶部echo “hello” > hello.txt
重定向输入输出(如echo到文件中、从文件中echo)cat hello.txt
打印文件内容到终端>>
在输入输出流后面追加内容|
管道,将|前面的输出连接为|后面的输入tail -n5
打印出输入文本的最后五行- ~/sys 各种硬件配置
- 常见命令行标志参数
--help
显示简略用法--version
或-V
显示软件版本信息--verbose
或-v
输出详细的运行信息--
停止处理后面的标志参数(若文件名是-r
时,防止歧义)
Shell Scripting
foo=bar
(中间无空格)将bar赋给变量foo$foo
调用“bar” (fish中是set foo bar)$(ls)
调用括号内容(如ls的输出) 如foo=$(pwd) 将pwd输出内容存到foo变量中' '
引用的字符串输出原本字符 如echo ‘Value is $foo’ 输出为$foo" "
引用的字符串输出特殊含义 如上面一句输出为foo储存的量$ + 字符
$?
判别上一个命令是否产生错误,即返回值 echo $?若错误或未执行,返回 1 (理解为未正确执行的报错1);
若正确,返回 0 (理解为正确执行后的退出代码return 0)
$0
正在运行的脚本的名称$1
到\$9
脚本的第~个参数$#
参数数量$$
正在运行的命令的进程ID$@
进程中的所有参数$_
上一条命令的最后一个参数(交互式shell中可按Esc后键入,来获取该值)
true 永远真, $? == 0 ; false 永远假,$? == 1
&&
逻辑且 如果前面真($? == 0) 后面才会执行;只要有一个$? == 1,就不会向后执行||
逻辑或 如果前面假($? == 1) 后面才会执行;只要有一个$? == 0,就不会向后执行;
连接两端代码,但语句结尾不加分号shell函数格式
func () { mkdir -p "$1" cd "$1" }
加载写在文件中的shell函数
source func.sh
$( cmd )
的值是cmd命令的输出,即命令替换<( cmd )
会执行cmd命令,并将结果输出到一个临时文件中,即进程替换grep foobar "$file"
寻找文件中是否有该字符串,有则返回0,没有则返回1for file in "$@"; do grep foobar "$file" > /dev/null 2> /dev/null # 如果模式没有找到,则grep退出状态为 1 # 我们将标准输出流和标准错误流重定向到Null,因为我们并不关心这些信息 if [[ $? -ne 0 ]]; then echo "File $file does not have any foobar, adding one" echo "# foobar" >> "$file" fi done
bash中进行比较时,尽量用双方括号[[ ]]而非单方括号[ ]
通配符:
- ? 代表一个或多个字符
- * 代表零个或多个字符
- { } 压缩公共子串,如image.{png, jpg}对应这两个文件
- {a..z} a到z的字符串
shebang行
shebang是由
#
与!
构成的字符序列,为了让内核知道用python解释器而不是shell命令来运行这段脚本#!/usr/local/bin/python
shell函数和脚本的不同点:
- 函数只能与shell使用相同的语言,脚本可以使用任意语言。因此在脚本中包含
shebang
是很重要的 - 函数仅在定义时被加载,脚本会在每次被执行时加载。函数的加载比脚本略快一些,但每次修改函数定义,都要使用source重新加载一次
- 函数只能与shell使用相同的语言,脚本可以使用任意语言。因此在脚本中包含
Shell Tools
find 命令 递归查找文件/文件夹
-name -type -path -size -mtime 限定名称、类型、路径、大小、修改日期
-exec + 命令 操作文件
grep命令:查找文件中的文本
grep的选项:
-i 不区分大小写查找
-C 获取查找结果的上下文
-v 输出不匹配的结果,反选
-R 递归地进入子目录并搜索
history 访问历史命令
xargs命令 接受标准输入作为参数,并处理
-d参数 可更改分隔符,如
echo "ONE TWO THREE" | xargs mkdir # 会生成三个文件夹"ONE,TWO,THREE" echo "ONT TWO THREE" | xargs -d "\t" mkdir # 将分隔符改为制表符,只生成一个文件夹"ONE TWO THREE"
tar命令 压缩、解压文件
-c 压缩 -x 解压 -t 查看内容 -r 向压缩文件末尾追加文件 -u 更新原压缩包文件 (只能用其中一个功能)
-z 有zip属性的 -v 显示所有过程
-f 命名为(只能放在最后一个)
head -num 文件 查看文件前num行内容
Editors(Vim)
- 普通模式快捷键
- i 在闪烁词前面插入文本(insert)
- a 在闪烁词后面插入文本
- x 删除闪烁词
- w 选中至下一个单词(word)(中文就是汉字)
- b 单词的开头(beginning)
- e 单词的结尾(ending)
- d 删除(delete)
- u 撤销一步操作(undo)
- U 撤销一行中的所有改动
- r 替换(replace)
- R 进入替换模式
- y 复制
- p 粘贴(paste)
- o 行首/在光标下面插入一行
- O 在光标上面插入一行
- $ 行尾
- v 进入可视模式(vision)
- V 进入整行选中模式
- ~ 改变选中字符的大小写
快捷键组合使用
dw 光标处删除一个单词
dd 删除一整行
d$ 从行尾往前删除
d+数字 删除多少个
如:d2w 删除两个单词
2dd 删除两行
cw/ce 删除光标以后一个单词,并进入insert模式(c: change)
c$ 删除光标后内容直至行末,并进入insert模式
f+字母 跳到第一个字母
H 屏幕上的首行
M 屏幕上的中间
L 屏幕上的底部
gg 跳转到文件首行
G 跳转到文件末行
数字+G 跳转到第_行
ctrl+r 撤销之前的撤销命令
ctrl+g 显示文件信息/当前所在的行列(goto)
ctrl+o 回到之前位置
ctrl+i 回到较新位置
ctrl+v 进入矩形框选中模式
ctrl+u 上翻页
ctrl+d 下翻页
查找
/+字符串 查找
- n 查找下一个
- N 查找上一个
?+字符串 查找(逆向)
在括号处按% 查找对应括号位置
命令
:set ic 查找不区分大小写模式
:set noic 查找区分大小写模式
:s/old/new 替换第一个old为new
:s/old/new/g 替换一行中所有的old为new
:%s/old/new/g 替换全文所有old为new,并提示确认(/gc)
:!命令 执行外部命令(如 ls mkdir)
:w 文件名 保存为_
:e 文件名 打开文件(edit)
:r+… 提取…文件/…命令并插入到光标下面
:qa 退出所有窗口
Data Wrangling
journalctl命令 查看日志文件
sed 基于ed构建的流编辑器,可利用简单的脚本命令来修改文件,有很多可选参数
s命令格式:sed -E ‘s/regex/substitution/‘ 将符合正则表达式regex的内容替换为substitution
wc命令 计算字数、行数、字节数
正则表达式REGEX
.
除换行符之外的任意单个字符a*
匹配前面字符零次或多次a+
匹配前面字符一次或多次[abcd]
匹配a, b, c, d中的任意一个字符[^abc]
匹配除a, b, c以外的任意一个字符[0-6]
匹配0到6的任意一个字符[ ]代表一个字符
[abc]{5}
匹配5个abc中的字符a{1,3}
匹配a不少于1次,不超过3次(rx1|rx2)
任何能够匹配rx1或rx2的结果a?
匹配0个或1个a^start
匹配行首是start的行end$
匹配行尾是end的行( )
与命令结合,起数学中括号作用
\d
匹配任意数字字符
\w
代表[A-Za-z0-9],用于匹配英文文本
\s
空格字符
\
转义符,将有特殊意义的字符转换为本身意义;或把普通字符 转换为特殊意义
\D
大写的字符表示原意义的相反含义,如\D表示匹配任意一个 非数字字符
sort命令 将输入数据进行排序
-n 升序排序
-r 倒序排序
uniq命令 检查文件中重复出现的行列
-c 在每列旁边显示该行重复出现的次数
awk命令 强大的文本处理工具
awk是一种编程语言,格式为
awk '{模式串} {代码块}'
awk '{print $2}' # 代码块中,$0表示整行内容,\$1到\$n表示一行中的n个区域(默认用空格分割) awk '$1 == 1 && $2 ~ /^c[^ ]*e$/ { print $2 }' # 模式串中,先筛选第一部分为1的,还要满足下面的正则表达式,再执行操作
paste命令 用于合并文件
bc命令 计算器,计算输入的值
bc 文件
计算文件中的运算值tee命令 读取输入数据,并保存到文件中
Command-line Environment
进程控制
SIGINT信号,用Ctrl+c发出
SIGQUIT信号,用Ctrl+\发出
SIGTERM信号,用kill命令发出,
SIGSTOP信号,用Ctrl+z发出,暂停/挂起进程
SIGHUP信号,关闭终端时发出的信号
fg命令 在前台恢复暂停的工作
bg命令 在后台恢复暂停的工作
jobs命令 列出当前终端会话中尚未完成的全部任务
可用pid选取进程,也可用
%+进程编号
来选取进程$!
选择最近的一个进程pgrep命令 查看进程的pid
pgrep 关键字 查找进程pid
ps命令 查看正在运行的进程
pkill命令 给予进程名来结束进程
守护进程(daemon):在后台保持运行,不需要用户手动运行或者交互的进程
以守护进程运行的程序名一般以
d
结尾,比如 SSH 服务端sshd
终端多路复用
tmux是一个终端多路复用器,可基于面板和标签分割出多个终端窗口,可以同时与多个 shell 会话进行交互;可以分离当前终端会话并在将来重新连接(可用于clash开机自启、保持启动)
会话:一个独立的工作区。在shell中,会话与终端窗口绑定,而在tmux中解除绑定
tmux 开始一个新的会话
tmux new -s NAME 以制定名称开始一个新的会话
tmux ls 列出当前所有会话
<Ctrl+b> d 将当前回话分离
tmux -t a 重新连接会话(没有-t则连接最后一个)
窗口:从视觉上将一个回话分割为多个部分
<Ctrl+b> c 创建新窗口 <Ctrl+d> 关闭
<Ctrl+b> N 跳转到第N个窗口
<Ctrl+b> p 上一个窗口 <Ctrl+b> n 下一个窗口
<Ctrl+b> w 列出所有窗口
面板:分屏,在一个屏幕里显示多个shell
别名与配置文件
alias命令 设置别名
alias 别名="原命令"
alias 列出所有别名
alias 别名 获取别名定义
unalias 别名 删除别名
在默认情况下 shell 并不会保存别名。为了让别名持续生效,需要将配置放进 shell 的启动文件里,像是
.bashrc
或.zshrc
可编辑配置文件来加强可移植性,如
# 针对不同的设备编写不同的配置 if [[ "$(uname)" == "Linux" ]]; then {do_something}; fi # 使用和 shell 相关的配置时先检查当前 shell 类型 if [[ "$SHELL" == "zsh" ]]; then {do_something}; fi # 针对特定的设备进行配置 if [[ "$(hostname)" == "myServer" ]]; then {do_something}; fi # 在不同程序间共享别名 if [ -f ~/.aliases ]; then source ~/.aliases fi
远程设备
ssh命令
ssh foo@bar,mit.edu
用ssh连接到其他服务器,并可以直接远程执行命令ssh-keygen命令 可生成密钥
# 生成名字叫id_ed25519的密钥 ssh-keygen -o -a 100 -t ed25519 -f ~/.ssh/id_ed25519
ssh会查询
.ssh/authorized_keys
来确认哪些用户可以被允许登录,可用以下命令拷贝公钥cat .ssh/id_ed25519 | ssh foobar@remote 'cat >> ~/.ssh/authorized_keys' # 或者 ssh-copy-id -i .ssh/id_ed25519.pub foobar@remote
scp命令 安全传输文件
# 从该服务器下载文件或目录 # -r 递归复制整个目录 scp -r root@192.168.1.1:/home/t.log ./ # 上传文件到该服务器 scp t.log root@192.168.1.1:/home
rsync命令 安全传输文件(只传输更改的文件,速度比scp更快),语法与scp相似
-a 同步文件元信息(大小、修改日期)
ssh端口转发
ssh -L 本地端口转发 ssh -R 远程端口转发
# 监听远程服务器foobar的8888端口,并建立从本地端口9999的转发 # 此时访问localhost:9999即可监听 ssl -L 9999:localhost:8888 foobar@remote_server
ssh配置
编辑
~/.ssh/config
文件Host vm User foobar HostName 172.16.174.141 Port 2222 IdentityFile ~/.ssh/id_ed25519 LocalForward 9999 localhost:8888 # 在配置文件中也可以使用通配符 Host *.mit.edu User foobaz
Version Control(Git)
git中的对象
- Blob对象 数据对象,即文件
- Tree 树,即目录
- commit 提交
git存储数据时,所有的对象都会基于它们的SHA-1哈希进行寻址
# 用下面命令可查看 git cat-file -p 698281bc680d1995c5f4caaf3359721a5a58d48d
用引用(指向commit的指针)可以赋予这些哈希值人类可读的名字
当前的位置索引:
HEAD
HEAD可指向分支,也可以指向提交,可分离HEAD
暂存区
git命令行接口(<>忽略)
git init
创建一个新的git仓库,数据会存放在.git
目录下git status
显示当前的仓库状态git commit
创建一个新的提交/快照/版本--amend
修改上一次提交git diff <filename>
显示与暂存区文件的差异git diff <reversion> <filename>
显示某文件两个版本之间的差异git branch
显示分支git branch <name>
创建分支git checkout <name>
改变HEAD/目前的分支git merge <version>
把<version>合并到当前分支git rebase <version>
线性化合并分支到<version>^
向上移动到parent^<num>
从左到右依次移动到第<num>个parent# 移动到分支main的parent节点 git checkout main^ # 依次移动到目标 git checkout HEAD^3
~<num>
一次向上移动<num>次-f
将分支强制指向某个提交,如# 将main分支强制指向HEAD的第三季parent提交 git branch -f main HEAD~3
git reset <version>
将当前分支撤销到<version>这个节点git revert <version>
撤销更改(并分享给别人)原理:多一个新提交,引入更改来撤销上个提交
git cherry-pick <version1> ...
将<version1>等一些提交复制到当前HEAD所在位置下面git rebase -i <version>
交互式排序各个提交git tag <v1> <version>
将<version>这个提交贴上<v1>标签git dscribe <name>
输出离<name>最近的taggit checkout -- <file>
丢弃更改git log <file>
列出文件历史提交记录-<num>
列出文件最新的num次提交git blame <file>
列出文件的修改记录git show <object>
列出查看的对象git add <file>
将文件添加到暂存区
git远端操作
git clone
上传/下载仓库远端分支命名规范为
ogigin/<name>
git push
将本地数据推送到远程仓库git push <origin> <place>
切换到<place>分支,再到远程的<origin>/<place>分支中,将没有的记录更新上去git push <origin> <source>:<destination>
将<source>这一节点推送到远程<origin>的<distination>分支若<source>为空白,则删除<origin>的<distination>分支
git fetch
从远程仓库获取数据(只会更新到最新的origin/main状态)git fetch <origin> <place>
切换到远程<place>分支,再到本地的<origin>/<place>分支中,将没有的记录更新上去git push <origin> <source>:<destination>
将<source>这一节点推送到本地<origin>的<distination>分支若<source>为空白,则在本地<origin>创建一个新的<destination>分支
git pull
从远程仓库获取数据并合并到本地(fetch+merge)git pull --rebase
(fetch+rebase)git checkout -b foo origin/main
切换到一个叫foo的新分支,并使其追踪远程的main或:
git branch -u origin/main foo
git remote
列出远端git remote add <name> <url>
添加一个远端
PR pull requestion 即将自己的代码提交上去,让原作者拉取
Debugging and profiling
seq 开始 步长 结束
输出固定间隔的数字# 在终端中打印多种颜色 for R in $(seq 0 20 255); do for G in $(seq 0 20 255); do for B in $(seq 0 20 255); do printf "\e[38;2;${R};${G};${B}m█\e[0m"; done done done
journalctl
命令 查看系统日志/var/log/
大多数程序日志的所在地pdb是Python的调试器
- l(ist) - 显示当前行附近的11行或继续执行之前的显示
- s(tep) - 执行当前行,并在第一个可能的地方停止
- n(ext) - 继续执行直到当前函数的下一条语句或者 return 语句
- b(reak) - 设置断点(基于传入的参数)
- p(rint) - 在当前上下文对表达式求值并打印结果
- r(eturn) - 继续执行直到当前函数返回
- q(uit) - 退出调试器
time 命令
在命令前面加上time前缀,可统计命令执行的实际时间、用户时间、系统时间- real - 从程序开始到结束流失掉的真实时间,包括其他进程的执行时间以及阻塞消耗的时间(例如等待 I/O或网络)
- user - CPU 执行用户代码所花费的时间
- sys - CPU 执行系统内核代码所花费的时间
进程消耗的实际CPU = user + sys
Metaprogramming
make
指令 最常用的构建工具,可由构建目标、相关依赖和构建规则来构建出文件make -f rules.txt
根据构建规则rule.txt了来构建文件Makefile文件由一系列rules构成
# 以下是每一条rule的格式 # <target>是必须的,<prerequisites>和<command>至少存在一个 # <target> : <prerequisites1> ... # <command> # 如: result.txt: source.txt cp source.txt result.txt
若make命令运行时没有指定目标,默认执行makefile文件的第一个目标
<target>也可以是某个操作的名字,叫作伪目标(phony target),可以在rule前面加一行
.PHONY: <P_target>
来声明,防止伪目标与文件名重名前置条件(prerequisites)通常是一组文件名,之间用空格分隔.只要有一个前置文件不存在,或者有过更新,”目标”就需要重新构建
命令(command)由一行或多行的Shell命令组成,它的运行结果通常就是生成目标文件。每行命令之前必须有一个tab键
每行命令在一个单独的shell中执行。这些Shell之间没有继承关系。解决方法:
# 多行命令写到一行中,用;分隔 var-kept: export foo=bar; echo "foo=[$$foo]" # 在换行符前加反斜杠转义 var-kept: export foo=bar; \ echo "foo=[$$foo]" # 用.ONESHELL命令 .ONESHELL: var-kept: export foo=bar; echo "foo=[$$foo]"
Security
熵度量了不确定性,并可以用来决定密码的强度
熵的单位是比特,对于一个均匀分布的随机离散变量,熵等于$\log_2n$.(n是所有可能的个数)
密码散列函数:可将任意大小的数据映射为一个固定大小的输出,如SHA-1, SHA-2等
sha1sum
命令 接收字符串,输出加密过的SHA-1密码$ printf 'hello' | sha1sum aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d
对称加密
信息的发送方和接收方使用同一个密钥去加密和解密数据,所以又叫私钥加密
非对称加密
用公钥或私钥中的任何一个进行加密,用另一个进行解密,所以又叫公钥加密
API
curl
利用url工具上传、下载文件的工具curl <url>
下载该url的html文件,并打印到屏幕大多数线上服务提供的 API(应用程序接口)让你可以通过编程方式来访问这些服务的数据
它们的结构化 URL 通常使用
api.service.com
作为根路径,用户可以访问不同的子路径来访问需要调用的操作,以及添加查询参数使 API 返回符合查询参数条件的结果