一般状况 zsh 脚本是在一个进程中(而且单线程)执行的,但有时咱们须要并行执行一些代码,由于如今的 CPU 基本都是多核的,这样能够加快运行速度。这就涉及到进程与做业控制。这里不讲进程的概念。git
以前咱们提到过,小括号中的代码是在子进程中执行的:github
% (sleep 1000 && echo good) # 而后再另外一个 zsh 里查看进程 % pstree | grep sleep `-tmux: server-+-zsh---zsh---sleep
里边有两个 zsh 进程。若是不加小括号的话:shell
% sleep 1000 && echo good # 而后再另外一个 zsh 里查看进程 % pstree | grep sleep `-tmux: server-+-zsh---sleep
就只有一个 zsh 进程。这说明使用小括号时,里边的代码是在子进程(一个新的 zsh 进程)执行的。但须要注意的时,若是括号里只有一个命令(好比 sleep 1000),那么并不会再开一个子进程来执行了。vim
那么在子进程里执行代码有什么意义呢?若是像上边那样放着前台运行,是没有什么意义。但咱们能够把它放后台运行。微信
首先咱们先看下怎么把单个程序放后台运行。网络
% sleep 1000 & [1] 850
在 sleep 1000 后边加一个 &,就会把它放后台运行。而后会输出一行内容,[1] 是进程的做业(job)号,850 是进程号(PID)。咱们能够继续运行别的命令,不须要等待 sleep 结束了。socket
jobs 命令能够查看当前在后台运行的全部做业:tcp
% jobs [1] + running sleep 1000 # -l 会输出进程号 % jobs -l [1] + 850 running sleep 1000
fg 命令能够把后台的做业切换回前台:ide
# 而后会继续等待 sleep 运行 % fg [1] + running sleep 1000
若是进程已经运行起来了,咱们想再把它放到后台,能够这样:ui
# 回车后按 ctrl + z % sleep 1000 ^Z zsh: suspended sleep 1000 # 这时能够运行 jobs 看一下,sleep 是处于挂起状态的 % jobs [1] + suspended sleep 1000 # 能够用 bg 让 sleep 恢复运行 % bg [1] + continued sleep 1000 # 这样 sleep 就运行在后台了 % jobs [1] + running sleep 1000
其实 jobs、fg、bg 这些命令并不经常使用,大概了解下用法便可。好比如今在用 vim 编辑文件,文件尚未保存,但我想退到终端运行个命令,而后再回到 vim。能够按 ctrl + z 让 vim 挂起,而后运行命令,最后再运行 fg 让 vim 恢复。但一般咱们能够启动多个终端模拟器,或者开一个新终端模拟器标签,或者用 tmux,不必在一个 shell 里这么折腾。
那么回答以前的场景,要在后台进程里执行 sleep 1000 && echo good:
% {sleep 1000 && echo aa} &
这样大括号里的代码都会在后台进程里执行,脚本里能够继续写别的。若是作完了后须要再等大括号里边的代码运行。
#!/bin/zsh {sleep 5 && echo p1} & # $! 是上一个运行的后台进程的进程号 pid=$! {sleep 10 && echo p2} & echo aaa # 要作的其余事情先作完 sleep 2 echo bbb # wait 加进程号用来等待进程结束,相似 fg,但脚本中不能用 fg wait $pid echo ccc
结果:
% ./test.zsh aaa bbb p1 ccc # p2 是脚本运行完过几秒才输出的 % p2
这样咱们就能够同时操做多个进程来为本身服务了。而进程之间的通讯,能够用命名管道或者普通文件来作,也可使用 socket 文件(Zsh 中有 zsh/net/socket 模块,使用它能够经过 socket 文件来通讯。管道是单向的,而 socket 双向的,更灵活一些,后续咱们会了解它的用法),或者使用网络通讯(若是脚本分布在不一样的机器,zsh 中有 zsh/net/tcp 模块,这样无需外部命令就可进行 tcp 通讯,后续也会讲到它)。
运行中的进程能够接受信号而后对信号作出响应。kill 命令用来给进程发送信号。
15(SIGTERM)是最经常使用的信号,也是 kill 不加参数的默认信号,用于终止一个进程。kill num 便可终止进程号是 num 的进程。但 15 信号能够被进程捕获,而后并不退出。若是要强行杀掉一个进程,能够用 9 信号(SIGKILL),它是进程没法捕获的,但这样的话进程正在作的事情会忽然中断,可能会有严重的影响,因此一般状况不要使用 9 信号杀进程。
在脚本中捕获信号:
#!/bin/zsh # SIGINT 是 2 信号,ctrl + c 会触发 TRAPINT() { # 处理一些退出前的善后工做 sleep 333 } sleep 1000
而后运行这个脚本,而后 ctrl + c,脚本没有退出,由于在执行 sleep 333,要再按一次才会退出。
在脚本中使用信号,一般是给其余进程发(主要是 15),而不是给本身发。在脚本中也不多须要捕获信号处理。信号相关的更多内容,之后可能会补充。
本文大概讲了进程与做业控制相关内容,主要用于在脚本里使用多进程执行代码,而不是在终端里进行做业控制(由于不多须要这样作)。关于脚本中的多个进程如何配合的内容还须要继续完善。
本文再也不更新,全系列文章在此更新维护:github.com/goreliu/zshguide
付费解决 Windows、Linux、Shell、C、C++、AHK、Python、JavaScript、Lua 等领域相关问题,灵活订价,欢迎咨询,微信 ly50247。