任务控制 链接到标题
信号与终止进程 链接到标题
shell 会使用 unix 提供的信号机制来进行进程之间的通信,当一个进程接收到信号时,它会停止执行原来的任务、处理该信号、并基于该信号传递的信息来改变任务的执行,可以认为信号是一种 软件中断。
下面这个 python 程序演示了捕获 SIGINT
信号并忽略该信号,即这个程序在收到 SIGINT
信号时,不会终止程序,我们需要使用 SIGQUIT
信号来停止这个程序,可以通过 <C-\>
来发送该信号。
#!/usr/bin/env python
import signal, time
def handler(signum, time):
print("\nI got a SIGINT, but I am not stopping")
signal.signal(signal.SIGINT, handler)
i = 0
while True:
time.sleep(.1)
print("\r{}".format(i), end="")
i += 1
运行该程序,向该程序发送两次 SIGINT
,然后发送一次 SIGQUIT
,程序反应如下:
zwyyy in 🌐 d3855u in ~/missing-semester 13s
❯ python3 sig.py
28^C
I got a SIGINT, but I am not stopping
53^C
I got a SIGINT, but I am not stopping
63^\zsh: quit python3 sig.py
注意
^
是我们在终端输入Ctrl
时的表现形式。
暂停与后台执行进程 链接到标题
信号除了终止进程之外,也可以让进程做其他事情,例如 SIGSTOP
会让进程暂停,在终端中,键入 <C-z>
会让 shell 发送 SIGTSTP
信号(terminal
版本的 SIGSTOP)。
我们可以使用 fg
或者 bg
来恢复暂停的工作,它们分别表示在前台继续或者在后台继续。
jobs
命令会列出当前终端会话中尚未完成的全部任务,可以使用 pid
来引用这些任务(也可以使用 pgrep
来找出 pid)。一种更符合直觉的操作是使用百分号 + 任务编号(jobs
会打印出任务编号)来选取该任务,可以用 $!
来选择最近一个任务。
在命令中添加 &
后缀可以让命令直接在后台运行,这样就能在 shell 中继续执行其他操作,但是该命令仍会使用 shell 的标准输出,例如 sleep 1000 &
。
对于正在运行的前台进程,我们输入 <C-z>
,该进程就会被暂停,再输入 bg %<任务编号>
就能让该进程在后台运行。要注意的是,后台运行的进程仍然是当前 shell 的子进程,一旦关闭当前终端(会发送 SIGHUP
信号),这些后台的进程也会被终止,可以使用 nohup
运行进程来防止这种情况(忽略 SIGHUP
)。
以下这个简单的会话中展示了上面这些概念的应用:
$ sleep 1000
^Z
[1] + 18653 suspended sleep 1000
$ nohup sleep 2000 &
[2] 18745
appending output to nohup.out
$ jobs
[1] + suspended sleep 1000
[2] - running nohup sleep 2000
$ bg %1
[1] - 18653 continued sleep 1000
$ jobs
[1] - running sleep 1000
[2] + running nohup sleep 2000
$ kill -STOP %1
[1] + 18653 suspended (signal) sleep 1000
$ jobs
[1] + suspended (signal) sleep 1000
[2] - running nohup sleep 2000
$ kill -SIGHUP %1
[1] + 18653 hangup sleep 1000
$ jobs
[2] + running nohup sleep 2000
$ kill -SIGHUP %2
$ jobs
[2] + running nohup sleep 2000
$ kill %2
[2] + 18745 terminated nohup sleep 2000
$ jobs
SIGKILL
是一个特殊的信号,它不能被进程捕获并且它会马上结束该进程。不过这样做会有一些副作用,例如留下孤儿进程
终端复用器:tmux 链接到标题
tmux
这类的终端多路复用器可以允许我们基于 panes 和 tabs 分割出多个终端窗口(即打开一个 terminal 窗口相当于打开了多个),这样您便可以同时与多个 shell 会话进行交互。
tmux 也允许我们分离当前 session 并在将来重新连接,被分离的 session 内的 shell 不会收到 SIGHUP
信号。
tmux 有三个核心概念:
- sessions
- windows
- panes
- windows
这三个概念的层级如上所示。windows 可以理解为浏览器中的 tabs。
tmux
的快捷键需要我们掌握,它们都是类似 <C-b> x
这样的组合,即需要先按下Ctrl+b
,松开后再按下 x
。tmux
中对象的继承结构如下:
-
会话 - 每个会话都是一个独立的工作区,其中包含一个或多个窗口
tmux
开始一个新的会话tmux new -s NAME
以指定名称开始一个新的会话tmux ls
列出当前所有会话- 在
tmux
中输入<C-b> d
,将当前会话分离 tmux a
重新连接最后一个会话。您也可以通过-t
来指定具体的会话
-
窗口 - 相当于编辑器或是浏览器中的标签页,从视觉上将一个会话分割为多个部分
<C-b> c
创建一个新的窗口,使用<C-d>
关闭<C-b> N
跳转到第 N 个窗口,注意每个窗口都是有编号的<C-b> p
切换到前一个窗口<C-b> n
切换到下一个窗口<C-b> ,
重命名当前窗口<C-b> w
列出当前所有窗口
-
面板 - 像 vim 中的分屏一样,面板使我们可以在一个屏幕里显示多个 shell
<C-b> "
水平分割<C-b> %
垂直分割<C-b> <方向>
切换到指定方向的面板,<方向> 指的是键盘上的方向键<C-b> z
切换当前面板的缩放<C-b> [
开始往回卷动屏幕。您可以按下空格键来开始选择,回车键复制选中的部分<C-b> <空格>
在不同的面板排布间切换
扩展阅读:
这里 是一份 tmux
快速入门教程。
别名与配置文件 链接到标题
别名 链接到标题
当我们在 shell 中执行 alias ll="ls -lh"
后,执行 ll
命令就相当于执行 ls -lh
。
zwyyy in 🌐 d3855u in ~/missing-semester
❯ ls
nohup.out sig.py words.txt
zwyyy in 🌐 d3855u in ~/missing-semester
❯ ls -lh
total 968K
-rw------- 1 zwyyy zwyyy 0 Jun 15 15:29 nohup.out
-rw-r--r-- 1 zwyyy zwyyy 246 Jun 15 15:39 sig.py
-rw-r--r-- 1 zwyyy zwyyy 962K Jun 15 14:55 words.txt
zwyyy in 🌐 d3855u in ~/missing-semester
❯ alias ll="ls -lh"
zwyyy in 🌐 d3855u in ~/missing-semester
❯ ll
total 968K
-rw------- 1 zwyyy zwyyy 0 Jun 15 15:29 nohup.out
-rw-r--r-- 1 zwyyy zwyyy 246 Jun 15 15:39 sig.py
-rw-r--r-- 1 zwyyy zwyyy 962K Jun 15 14:55 words.txt
当我们关闭这个 shell 或者切换到另一个 shell 后,别名就不再生效,为了让别名对所有 shell 生效,需要将它写入 shell 的配置文件中,以我这里使用的 zsh 为例,在 ~/.zshrc
中追加 alias ll="ls -lh"
,再执行 source ~/.zshrc
后,别名就将一直生效。
配置文件 链接到标题
很多程序的配置都是通过纯文本格式的被称作 dotfile 的配置文件来完成的(之所以称为 dotfile,是因为它们的文件名以 .
开头,例如 ~/.vimrc
。也正因为此,它们默认是隐藏文件,ls
并不会显示它们)。
shell 的配置也是通过这类文件完成的。在启动时,您的 shell 程序会读取很多文件以加载其配置项。根据 shell 本身的不同,您从登录开始还是以交互的方式完成这一过程可能会有很大的不同。关于这一话题,这里 有非常好的资源
对于 bash
来说,在大多数系统下,您可以通过编辑 .bashrc
或 .bash_profile
来进行配置。在文件中您可以添加需要在启动时执行的命令,例如上文我们讲到过的别名,或者是您的环境变量。
实际上,很多程序都要求您在 shell 的配置文件中包含一行类似 export PATH="$PATH:/path/to/program/bin"
的命令,这样才能确保这些程序能够被 shell 找到。
还有一些其他的工具也可以通过 dotfile 进行配置:
bash
-~/.bashrc
,~/.bash_profile
git
-~/.gitconfig
vim
-~/.vimrc
和~/.vim
目录ssh
-~/.ssh/config
tmux
-~/.tmux.conf
此外,也有一些工具,其配置文件位于 ~/.config/xxx/
目录下:
fish
-~/.config/fish/config.fish
gdb
-~/.config/gdb/gdbinit
lazygit
-~/.config/lazygit/config.yaml
我们应该如何管理这些配置文件呢,它们应该在它们的文件夹下(例如统一放在 ~/.config
),并使用版本控制系统进行管理,然后通过脚本将其 符号链接 到需要的地方。这么做有如下好处:
- 安装简单: 如果您登录了一台新的设备,在这台设备上应用您的配置只需要几分钟的时间;
- 可移植性: 您的工具在任何地方都以相同的配置工作
- 同步: 在一处更新配置文件,可以同步到其他所有地方
- 变更追踪: 您可能要在整个程序员生涯中持续维护这些配置文件,而对于长期项目而言,版本历史是非常重要的
连接远程设备 链接到标题
参见 ssh 简单教程