(该系列文章大部分内容来源于MIT课程笔记,加入了个人的理解、原笔记中没有的细节和其他的需要理解的内容,公开课地址:https://www.bilibili.com/video/BV14E411J7n2?p=1)
目录
我们将学习一些能够改善您的 shell 及其他工具的工作流的方法,这主要是通过定义别名或基于配置文件对其进行配置来实现的。这些方法都可以帮您节省大量的时间。例如,仅需要执行一些简单的命令,我们就可以在所有的主机上使用相同的配置。我们还会学习如何使用 SSH 操作远端机器。
用户更改密码
passwd [user]
passwd 命令将会试着强迫你使用“强”密码。这意味着它会拒绝接受太短的密码、与先前 相似的密码、字典中的单词作为密码或者是太容易猜到的密码:(macOS上并不会提示)
[me@linuxbox ~]$ passwd
(current) UNIX password:
New UNIX password:
BAD PASSWORD: is too similar to the old one New UNIX password:
BAD PASSWORD: it is WAY too short
New UNIX password:
BAD PASSWORD: it is based on a dictionary word
进程控制
当系统启动的时候,内核先把一些它自己的活动初始化为进程,然后运行一个叫做 init
的程序,再运行一系列的称为 init
脚本的 shell
脚本(位于/etc
),它们可以启动所有的系统服务。系统分配给每个进程一个数字,这 个数字叫做进程 (process) ID 或 PID
。PID
号按升序分配,init
进程的 PID 总是 1。内核也对分配给每个进程的内存和就绪状态进行跟踪以便继续执行这个进程。
查看进程(ps)
ps
(process status)有许多选项,它最简单地使用形式是这样的:
➜ Downloads ps
PID TTY TIME CMD
7959 ttys000 0:09.23 -zsh
默认情况下,ps 不会显示很多进程信息,只是列出与当前终端会话相关的进程。TTY
是 “Teletype”(直译电传打字机) 的简写,是指进程的控制终端。TTY 足足显示了 Unix 的年代久远。TIME
字段表示进程所消耗的 CPU 时间数量。
加上 x
选项(注意没有开头的-
字符),告诉 ps 命令,展示所有进程,不管它们由什么终端(如果有的话)控制:
➜ Downloads ps x
PID TT STAT TIME COMMAND
316 ?? S 0:00.37 /System/Library/Frameworks/Lo
317 ?? S 0:16.85 /usr/sbin/cfprefsd agent
322 ?? S 0:15.84 /usr/libexec/UserEventAgent
324 ?? S 0:00.99 /System/Library/PrivateFramew
输出结果中,新添加了一栏 STAT
。STAT
是 “state” 的简写,它揭示了进程当前状态:
状态 | 含义 |
---|---|
R | 运行中。这意味着,进程正在运行或准备运行。 |
S | 正在睡眠。进程没有运行,而是,正在等待一个事件,比如 说,一个按键或者网络分组。 |
D | 不可中断睡眠。进程正在等待 I/O,比方说,一个磁盘驱动 器的 I/O。 |
T | 已停止. 已经指示进程停止运行。稍后介绍更多。 |
Z | 一个死进程或“僵尸”进程。这是一个已经终止的子进程, 但是它的父进程还没有清空它。(父进程没有把子进程从进程表中删除) |
< | 一个高优先级进程。这可能会授予一个进程更多重要的资 源,给它更多的 CPU 时间。进程的这种属性叫做 niceness。 具有高优先级的进程据说是不好的(less nice),因为它占用了比较多的 CPU 时间,这样就给其它进程留下很少时间。 |
N | 低优先级进程。一个低优先级进程(一个“nice”进程)只有 当其它高优先级进程被服务了之后,才会得到处理器时间。 |
动态查看进程(top)
top
以进程活动顺序显示连续更新的系统进程列表(默认情况下,每三秒钟更新一次),top
显示结果由两部分组成:最上面是系统概要,下面是进程列表,以 CPU 的使用率排序。
结束进程
您的 shell 会使用 UNIX 提供的信号机制执行进程间通信。当一个进程接收到信号时,它会停止执行、处理该信号并基于信号传递的信息来改变其执行。就这一点而言,信号是一种软件中断。在上面的例子中,当我们输入 Ctrl-C 时,shell 会发送一个SIGINT(signal interrupt)信号到进程。(可以通过man signal
查看其他所有信号)
下面这个 Python 程序向您展示了捕获信号SIGINT
并忽略它的基本操作,它并不会让程序停止。为了停止这个程序,我们需要使用SIGQUIT
信号,通过输入Ctrl-\
可以发送该信号。
#!/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
运行结果:
lilhoe@LilHoedeMacBook-Pro Downloads % python test.py
42^C
I got a SIGINT, but I am not stopping
66^\zsh: quit /Library/Frameworks/Python.framework/Versions/3.8/bin/python3.8 test.py
lilhoe@LilHoedeMacBook-Pro Downloads %
如果我们向这个程序发送两次 SIGINT ,然后再发送一次 SIGQUIT,程序会有什么反应?注意 ^ 是我们在终端输入Ctrl 时的表示形式:
$ python test.py
24^C
I got a SIGINT, but I am not stopping
26^C
I got a SIGINT, but I am not stopping
30^\[1] 39913 quit python test.py
尽管 SIGINT 和 SIGQUIT 都常常用来发出和终止程序相关的请求。SIGTERM 则是一个更加通用的、也更加优雅地退出信号。为了发出这个信号我们需要使用 kill 命令, 它的语法是: kill -TERM <PID>
(输入kill -l
查看kill命令详细参数)。
暂停和后台执行进程
信号可以让进程做其他的事情,而不仅仅是终止它们。例如,SIGSTOP
会让进程暂停。在终端中,键入 Ctrl-Z
会让 shell 发送 SIGTSTP
信号。
我们可以使用 fg
(返回前台继续运行,重新连接标准输出)或 bg
(移到后台继续运行)命令恢复暂停的工作。它们分别表示在前台继续或在后台继续。
jobs
命令会列出当前终端会话中尚未完成的全部任务。您可以使用 pid 引用这些任务(也可以用 pgrep
找出 pid)。更加符合直觉的操作是您可以使%
+ 任务编号(jobs 会打印任务编号)来选取该任务。如果要选择最近的一个任务,可以使用 $!
这一特殊参数。
命令中的 &
后缀可以让命令在直接在后台运行,这使得您可以直接在 shell 中继续做其他操作,不过它此时还是会使用 shell 的标准输出,这一点有时会比较恼人(这种情况可以使用 shell 重定向处理)。
让已经在运行的进程转到后台运行,您可以键入Ctrl-Z
,然后紧接着再输入bg
。注意,后台的进程仍然是您的终端进程的子进程,一旦您关闭终端(会发送另外一个信号SIGHUP
),这些后台的进程也会终止。为了防止这种情况发生,您可以使用 nohup
(一个用来忽略 SIGHUP
的封装) 来运行程序。针对已经运行的程序,可以使用disown
。除此之外,您可以使用