Shell¶
基本概念¶
计算机最根本的交互接口。常用Bourne Again SHell, 简称 “bash” 。本质是一个编程环境
命令界面¶
missing:~$ echo My\ Photos
My Photos
missing: 主机名, ~:主shell工作目录, #/$:是/否root echo:命令(由PATH中搜索) My\ Photos: 参数(shell通过空格分割命令, \为转义符)
变量与通配符¶
foo=bar #注意不要空格
echo "$foo" # 打印 bar
echo '$foo' # 打印 $foo
shell中的变量赋值后,可以采用$foo的形式调用;
注意Bash中的字符串通过' 和 "分隔符来定义,但以'定义的字符串为原义字符串,其中的变量不会被转义,而 "定义的字符串会将变量值进行替换。
mv *{.py,.sh} folder
执行脚本可以分别使用 ? 和 * 来匹配一个或任意个字符。
同时也可以用花括号{} 来自动展开这些命令。
配置文件¶
很多程序的配置都是通过纯文本格式的被称作点文件的配置文件来完成的
对于 bash来说,在大多数系统下,您可以通过编辑 .bashrc 或 .bash_profile 来进行配置别名,或者是环境变量。
最好能够通过版本控制系统对这些配置文件进行管理。
同时也可以去参考别人的配置文件,见dotfiles 仓库
常用快捷键¶
| 快捷键 | 解释 | 快捷键 | 解释 |
|---|---|---|---|
Ctrl + A |
移动光标到行首 | Ctrl + E |
移动光标到行尾 |
Ctrl + U |
删除光标到行首的所有字符 | Ctrl + K |
删除光标到行尾的所有字符 |
Ctrl + W |
删除光标前的一个单词 | Ctrl + Y |
粘贴最后一次删除的文本 |
Ctrl + L |
清屏,相当于执行 clear 命令 |
Ctrl + R |
搜索命令历史 |
Ctrl + C |
终止当前命令 | Ctrl + D |
退出当前 Shell 会话 |
Alt + F |
向前移动一个单词 | Alt + B |
向后移动一个单词 |
常见指令¶
| 指令 | 指令含义 | 常用参数1 | 常用参数2 | 常用参数3 |
|---|---|---|---|---|
ls |
列出目录内容 | -l(长格式) |
-a(显示隐藏文件) |
-h(人类可读格式) |
cd |
切换目录 | -(返回上个目录) |
..(上一级目录) |
/(根目录) |
cp |
复制文件或目录 | -r(递归复制) |
-v(显示过程) |
-i(交互模式) |
mv |
移动或重命名文件 | -i(交互模式) |
-v(显示过程) |
-n(不覆盖) |
rm |
删除文件或目录 | -r(递归删除) |
-f(强制删除) |
-i(交互模式) |
chmod |
修改文件权限 | -R(递归修改) |
+x(添加执行权限) |
-w(移除写权限) |
tee |
从标准输入读取数据并写入标准输出和文件 | -a(追加到文件末尾) |
-i(忽略中断信号) |
多个文件参数(同时写入) |
grep |
搜索文本内容 | -i(忽略大小写) |
-r(递归搜索) |
-v(反转匹配) |
find |
查找文件或目录 | -name(按名称) |
-type(按类型) |
-size(按大小) |
tar |
压缩或解压文件 | -c(创建归档) |
-x(解压归档) |
-z(使用 gzip) |
xargs |
将输入转为参数 | -0(以空字符分隔) | -d(将指定的字符作为定界符) | -a file(从指定的文件读取输入) |
更多指令的帮助,可加入参数--help或者使用指令man看查手册
也可以安装社区手册tldr进行查询
常见指令模式¶
-
会造成不可撤回操作的工具一般会提供“空运行”(dry run)标志参数以确认操作,或者“交互式”(interactive)标志参数以确认每个操作。
-
基本所有的工具支持使用
--verbose或者-v标志参数来输出详细的运行信息。多次使用这个标志参数,比如-vvv,可以让工具输出更详细的信息(经常用于调试)。同样,很多工具支持--quiet标志参数来抑制除错误提示之外的其他输出。 -
--version或者-V标志参数可以让工具显示它的版本信息(对于提交软件问题报告非常重要)。 -
会造成破坏性结果的工具一般默认进行非递归的操作,但是支持使用“递归”(recursive)标志函数(通常是
-r)。 -
大多数工具中,使用
-代替输入或者输出文件名意味着工具将从标准输入(standard input)获取所需内容,或者向标准输出(standard output)输出结果。 -
可以使用特殊参数
--让某个程序 停止处理--后面出现的标志参数以及选项(以-开头的内容)(视为正常参数),如
ssh machine --for-ssh -- foo --for-foo
其中 -- 会让 ssh 知道 --for-foo 不是 ssh 的标志参数,而是foo的。
Shell编程初步¶
程序间的链接¶
shell中有三个流:标准输入流,标准输出流,标准错误流(对应编号0,1,2)
>与<:¶
最简单的重定向,可以将输出流定向到文件。
可使用>>来向文件内追加内容。
mising:~$ cat null >output 2>error
如上,2>可以重定向标准错误流;此外,>&2可以输入到错误流;&>则可以同时捕捉输出流和错误流
|管道:¶
使用管道( pipes ),允许我们将一个程序的输出和另外一个程序的输入连接起来
此外还可以用xargs将输入转为参数
missing:~$ curl --head --silent google.com | grep last-modified
特殊变量¶
| 符号 | 解释 |
|---|---|
$0 |
脚本名 |
$1 到 $9 |
脚本的参数。 $1 是第一个参数,依此类推 |
$@ |
所有参数 |
$# |
参数个数 |
$? |
前一个命令的返回值 |
$$ |
当前脚本的进程识别码 |
!! |
完整的上一条命令,包括参数 |
| $( CMD ) | 以变量的形式获取一个命令的输出 |
| <( CMD ) | 执行 CMD 并将结果输出到临时文件中,并将 <( CMD ) 替换成临时文件名 |
控制语句¶
条件判断
if [[ $num -gt 5 ]]; then #建议采用双方格
echo "num 大于 5"
else
echo "num 小于或等于 5"
>&2 echo "erro"
exit 1
fi
循环语句
for i in 1 2 3 4 5; do
echo "数字: $i"
done
while [[ $counter -le 5 ]]; do
echo "计数器: $counter"
counter=$((counter + 1))
done #break和continue使用正常
函数与脚本¶
函数示例:(可以被source写入)
mcd () {
mkdir -p "$1"
cd "$1"}
脚本示例:
#!/bin/sh #shebang
curl --head --silent https://missing.csail.mit.edu
认识与区别
- 函数只能与shell使用相同的语言,脚本可以使用任意语言。因此在脚本中包含
shebang是很重要的。 - 函数仅在定义时被加载,脚本会在每次被执行时加载。这让函数的加载比脚本略快一些,但每次修改函数定义,都要重新加载一次。
- 函数会在当前的shell环境中执行,脚本会在单独的进程中执行。因此,函数可以对环境变量进行更改。脚本需要使用
export将环境变量导出,并将值传递给环境变量。
任务控制¶
常用信号¶
Shell 会使用 UNIX 提供的信号机制执行进程间通信。
当一个进程接收到信号时,它会停止执行、处理该信号并基于信号传递的信息来改变其执行。
| 信号名称 | 编号 | 描述 | 常见快捷键 |
|---|---|---|---|
SIGHUP |
1 | 挂起信号,通常在终端关闭时发送。 | |
SIGINT |
2 | 中断信号,通常在按下 Ctrl+C 时发送。 |
Ctrl+C |
SIGQUIT |
3 | 退出信号,通常在按下 Ctrl+\ 时发送。 |
Ctrl+\ |
SIGKILL |
9 | 杀死信号,强制终止进程。 | |
SIGTERM |
15 | 终止信号,通常用于请求程序正常终止。 | kill默认 |
SIGSTOP |
19 | 停止信号,暂停进程的执行。 | Ctrl+Z |
SIGTSTP |
20 | 终端停止信号,通常在按下 Ctrl+Z 时发送。 |
Ctrl+Z |
SIGCONT |
18 | 继续信号,恢复一个被 SIGSTOP 暂停的进程。 |
进程管理¶
jobs: 列出当前会话中未完成的任务,-l可以输出完整的pid号ps: 用于显示当前正在运行的进程信息,-ef显示详细的格式化进程列表,pstree命令以树状结构显示所有进程kill/pkill: 发送信号给进程,默认为SIGTERM。输入分别为进程号/进程内容fg/bg: 回复暂停的工作,分别在前台/后台继续工作pgrep: 寻找相关内容的进程号
终端拓展¶
多路复用¶
终端多路复用器(如tmux)可以允许我们基于面板和标签分割出多个终端窗口,这样您便可以同时与多个 shell 会话进行交互。
tmux 的快捷键需要我们掌握,它们都是类似 <C-b> x 这样的组合,即需要先按下Ctrl+b,松开后再按下 x。
常用指令如下:
会话¶
每个会话都是一个独立的工作区,其中包含一个或多个窗口
-
tmux开始一个新的会话 -
tmux new -s NAME以指定名称开始一个新的会话 -
tmux ls列出当前所有会话 tmux a重新连接最后一个会话。您也可以通过-t来指定具体的会话
窗口¶
相当于编辑器或是浏览器中的标签页,从视觉上将一个会话分割为多个部分
<C-b> c创建一个新的窗口,使用<C-d>关闭<C-b> N跳转到第 N 个窗口,注意每个窗口都是有编号的<C-b> p/n切换到前/后一个窗口<C-b> w列出当前所有窗口
更多后续学习可以参考 tmux入门教程
远程设备¶
登陆¶
使用远程服务器来部署后端软件,可以使用安全 shell(SSH),如
ssh foo@bar.mit.edu ls
即以用户名 foo 登录服务器 bar.mit.edu, 执行ls并返回内容。
ssh可以通过密钥的方式登入,需要分别持有公钥和私钥
ssh-keygen -o -a 100 -t ed25519 -f ~/.ssh/id_ed25519 #生成密钥
cat .ssh/id_ed25519.pub | ssh foobar@remote 'cat >> ~/.ssh/authorized_keys' #加入公钥
文件拷贝¶
ssh+tee, 利用标准输入实现,如cat localfile | ssh remote_server tee serverfile。scp:当需要拷贝大量的文件或目录时,使用scp命令则更加方便,因为它可以方便的遍历相关路径。如:scp path/to/local_file remote_host:path/to/remote_file;
端口转发¶
通过本地端口监听远程端口,可以通过端口转发形式,如:
ssh -L 9999:localhost:8888 foobar@remote_server
就可以通过本地的 localhost:9999监听远程服务器的8888端口
远端文件管理¶
FUSE(用户空间文件系统)允许运行在用户空间上的程序实现文件系统调用,并将这些调用与内核接口联系起来。
FUSE经常被用于实现通过ssh进行远端文件管理,使得文件虽然存储在远程主机,对于本地计算机上的软件而言和存储在本地别无二致。
常见的FUSE文件系统有:
- sshfs:使用 SSH 连接在本地打开远程主机上的文件
- rclone:将 Dropbox、Google Drive、Amazon S3、或者 Google Cloud Storage 一类的云存储服务挂载为本地文件系统
- kbfs:分布式端到端加密文件系统。在这个文件系统里有私密(private),共享(shared),以及公开(public)三种类型的文件夹
SSH 配置¶
在~/.ssh/config可以方便地进行文件配置,记录下链接信息。
服务器侧的配置通常放在 /etc/ssh/sshd_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
内容拓展¶
SHELL工具¶
当你需要实现更丰富的功能,最好的方式是寻找替代方案——找到合适的替代程序即可
ripgrep (rg)¶
丰富grep的功能,并通过多线程提高速度
# 查找所有使用了 requests 库的文件
rg -t py 'import requests'
# 查找所有没有写 shebang 的文件(包含隐藏文件)
rg -u --files-without-match "^#!"
# 查找所有的foo字符串,并打印其之后的5行
rg foo -A 5
# 打印匹配的统计信息(匹配的行和文件的数量)
rg --stats PATTERN
fasd¶
能通过频率和时效排序,自动找到最常访问的目录和文件
v def conf => vim /some/awkward/path/to/type/default.conf
j abc => cd /hell/of/a/awkward/path/to/get/to/abcdef
f exa => ls /home/bony/example.tar
优先注意点*¶
- 多去使用键盘,少使用鼠标。这一目标可以通过多加利用快捷键,更换界面等来实现。
- 学好编辑器。作为程序员你大部分时间都是在编辑文件,因此值得学好这些技能。
- 学习怎样去自动化或简化工作流程中的重复任务。因为这会节省大量的时间。
- 学习像 Git 之类的版本控制工具并且知道如何与 GitHub 结合,以便在现代的软件项目中协同工作。