命令行环境
- 如何同时执行多个不同的进程并追踪它们的状态
- 如何停止或暂停某个进程
- 如何使进程在后台运行
- 改善shell及其他工具的工作流的方法
- 如何使用SSH操作远端机器
任务控制
结束进程
shell会使用UNIX提供的信号机制执行进程间通信。当一个进程接收到信号时,它会停止执行、处理该信号并基于信号传递的信息来改变其执行。
当我们输入Ctrl-C时,shell会发送一个SIGINT
信号到进程
下面这个python程序展示了捕获信号SIGINT
并忽略它的基本操作,它并不会让程序停止。为了停止这个程序,需要使用SIGQUIT
信号,通过输入Ctrl-\
可以发送该信号
#!/user/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
都常常用来发出和终止程序相关的请求。
SIGTERM
则是一个更加通用的、也更加优雅地退出信号。为了发出这个信号我们需要使用kill
命令
kill -TERM <PID>
暂停和后台执行进程
SIGSTOP
会让进程暂停。在终端中,键入Ctrl-Z
会让Shell发送SIGTSTP
信号
我们可以使用fg
或bg
命令恢复暂停地工作。它们分别表示在前台继续或在后台继续。
jobs
命令会列出当前终端会话中尚未完成地全部任务。
命令中的&
后缀可以让命令在直接在后台运行,这使得可以直接在shell中继续做其他操作。
让已经在运行的进程转到后台运行,可以键入Ctrl-Z
,然后紧接着再输入bg
。**后台的进程仍然是终端进程的子进程,一旦关闭终端(会发送另外一个信号SIGHUP
),这些后台的进程也会终止。**为了防止这种情况发生,可以使用nohup
来运行程序。针对已经运行的程序可以使用disown
SIGKILL
是一个特殊的信号,它不能被进程捕获并且它会马上结束该进程。不过这样做有一些副作用,例如留下孤儿进程。
终端多路复用
在使用命令行接口时,通常会希望同时执行多个任务。
像tmux
这类的终端多路复用器可以允许我们基于面板和标签分割出多个终端窗口,这样可以同时与多个shell会话进行交互。
tmux
中对象的继承结构:
- 会话:每个会话都是一个独立的工作区,其中包含一个或多个窗口
- 窗口:相当于编辑器或是浏览器中的标签页,从视觉上将一个会话分割为多个部分
- 面板:像vim中的分屏一样,面板使我们可以在一个屏幕里显示多个shell
别名
大多数shell都支持设置别名。shell的别名相当于一个长命令的缩写,shell会自动将其替换成原本的命令。
在默认情况下,shell并不会保存别名。为了让别名持续生效,需要将配置放进shell的启动文件里,像是.bashrc
或.zshrc
配置文件(Dotfiles)
很多程序的配置都是通过纯文本格式的被称作点文件(文件名以.开头)的配置文件来完成的
shell的配置也是通过这类文件完成的
对于bash
来说,在大多数系统下,可以通过编辑.bashrc
或.bash_profile
来进行配置。在文件中可以添加需要在启动时执行的命令。
如何管理这些配置文件:它们应该在它们的文件夹下,并使用版本控制系统进行管理,然后通过脚本将其符号链接到需要的地方,这样做的好处:
- 安装简单
- 可以执行
- 同步
- 变更追踪
可移植性
配置文件的一个常见的痛点是它可能并不能在多种设备上生效。可以利用配置文件if
语句针对不同设备编写不同的配置,如果配置文件支持include
功能,也可以多加利用
远端设备
通过如下命令,可以使用ssh
连接到其他服务器
ssh foo@bar.mit.edu
尝试以用户名foo
登录服务器bar.mit.edu
。服务器可以通过URL
指定,也可以使用IP
指定
执行命令
ssh
的一个特性是可以直接远程执行命令
ssh foobar@server ls
可以直接在用foobar
命令下执行ls
命令
ssh foobar@server ls | grep PATHERN
会在本地查询远端ls
的输出
LS | ssh foobar@server grep PATHERN
会在远端对本地ls
输出结果进行查询。
SSH密钥
基于密钥的验证机制使用了密码学中的公钥,我们只需要向服务器证明客户端持有对应的私钥,而不需要公开其私钥。
密钥生成
使用ssh-keygen
命令可以生成一对密钥。
可以为密钥设置密码,防止有人持有您的私钥并使用它访问您的服务器。可以使用ssh-agent
或gpg-agent
,这样就不需要每次都输入该密码了。
基于密钥的认证机制
ssh
会查询.ssh/authorized_keys
来确认那些用户可以被允许登录
通过SSH复制文件
ssh
+tee
:最简单的方法是执行ssh
命令,然后通过这样的方法利用标准输入实现cat localfile | ssh remote_server tee serverfile
。tee
命令会将标准输出写入到一个文件scp
:当需要拷贝大量的文件或目录时,使用scp
命令则更加方便,因为可以方便的遍历相关路径tsync
对scp
进行改进,它可以检测本地和远端的文件以防止重复拷贝。
端口转发
监听特定设备的端口。如果是在您的本机,可以使用localhost:PORT
或127.0.0.1:PORT
但远端的端口并不会直接通过网络暴露,此时就需要进行端口转发:
- 本地端口转发
- 远程端口转发
常见的情景是使用本地端口转发,即在远端设备上的服务监听一个端口,而希望在本地设备上的一个端口建立连接并转发到远程端口上。
例如,在远端服务器上运行Jupyter notebook并监听8888端口。然后,建立从本地端口9999的转发,使用ssh -L 9999:localhost 8888 foobar@remote_server
。这样只需要访问本地的localhost:9999
即可
SSH配置
为它们创建一个别名是个好想法。
使用~/.ssh/config
文件来创建别名,类似scp
、rsync
和mosh
的这些命令都可以读取这个配置并将设置转换为对应的命令行选项。
杂项
mosh
对ssh
进行了改进,它允许连接漫游、间歇连接及智能本地回显。
sshfs
可以将远端服务器上的一个文件夹挂载到本地,这样就可以使用本地的编辑器了。
Shell&框架
框架也可以改进shell。比较流行的通用框架包括prezto
和oh-my-zsh
终端模拟器
从以下方面配置终端:
- 字体选择
- 彩色主题
- 快捷键
- 标签页/面板支持
- 回退配置
- 性能