Linux Luminarium-进程与任务模块

“进程与任务” (Processes and Jobs) 模块

在 Linux 的学习旅程中,你经常会遇到需要管理程序运行的情况。计算机通过执行软件来完成各项工作。在现代计算领域,这些软件主要分为两大类:操作系统内核(我们将在后续课程中深入学习)和进程(Processes),后者正是本模块讨论的核心

当 Linux 系统启动时,它会首先启动一个名为 **init**(初始化进程的缩写)的进程。随后,init 会启动一系列其他进程,这些进程又会进一步产生更多的子进程。这一链式反应持续进行,直到最终呈现出我所使用的命令行 Shell —— 实际上,Shell 本身也是一个进程。

当然,当我输入命令时,Shell 也会启动相应的进程来响应我的指令。在本模块中,将学习如何通过多种方式查看并与这些进程进行交互。

利用ps命令列出正在运行的进程

基础知识:什么是 PID 和 ps?

  • PID (Process ID):每一个运行中的进程都有一个唯一的数字标识符,称为进程 ID。
  • **默认 ****ps**:如果只输入 ps,它仅显示当前终端窗口(TTY)中启动的进程。通常只能看到 bash(Shell 本身)和 ps 命令。

由于 ps 是一个历史悠久的工具,它支持两套略有不同的参数语法,这两套命令在实际工作中最为常用:

语法类型 常用命令 参数解析 侧重点
标准语法 (Standard) ps -ef -e: 所有进程

-f: 完整格式显示
PPID (父进程 ID),方便追踪谁启动了谁。
BSD 语法 ps aux a: 所有用户进程
x: 包含无终端进程
u: 用户易读格式
CPU 和内存占用百分比
hacker@dojo:~$ ps
    PID TTY          TIME CMD
    329 pts/0    00:00:00 bash
    349 pts/0    00:00:00 ps
hacker@dojo:~$

在上面的例子中,我们有 shell(bash)和 ps 进程本身,这就是在该特定终端上运行的全部。我们还看到每个进程都有一个数字标识符(Process ID,或 PID),这是一个唯一标识 Linux 环境中所有运行进程的数字。我们还可以看到执行命令的终端(这里是 pts/0 的指定),以及进程迄今为止消耗的 CPU 总时间

hacker@dojo:~$ ps -ef
UID          PID    PPID  C STIME TTY          TIME CMD
hacker         1       0  0 05:34 ?        00:00:00 /sbin/docker-init -- /bin/sleep 6h
hacker         7       1  0 05:34 ?        00:00:00 /bin/sleep 6h
hacker       102       1  1 05:34 ?        00:00:00 /usr/lib/code-server/lib/node /usr/lib/code-server --auth=none -
hacker       138     102 11 05:34 ?        00:00:07 /usr/lib/code-server/lib/node /usr/lib/code-server/out/node/entr
hacker       287     138  0 05:34 ?        00:00:00 /usr/lib/code-server/lib/node /usr/lib/code-server/lib/vscode/ou
hacker       318     138  6 05:34 ?        00:00:03 /usr/lib/code-server/lib/node --dns-result-order=ipv4first /usr/
hacker       554     138  3 05:35 ?        00:00:00 /usr/lib/code-server/lib/node /usr/lib/code-server/lib/vscode/ou
hacker       571     554  0 05:35 pts/0    00:00:00 /usr/bin/bash --init-file /usr/lib/code-server/lib/vscode/out/vs
hacker       695     571  0 05:35 pts/0    00:00:00 ps -ef
hacker@dojo:~$

可以看到,有进程用于初始化挑战环境(<font style="color:rgb(31, 31, 31);">docker-init</font>)、自动终止前的超时以保留计算资源(6 小时后睡眠到超时)、VSCode 环境(多个代码服务器辅助进程)、<font style="color:rgb(31, 31, 31);">shell</font>(bash)以及我的 <font style="color:rgb(31, 31, 31);">ps -ef </font>命令。<font style="color:rgb(31, 31, 31);">ps aux </font>基本上也是一样的道理:

hacker@dojo:~$ ps aux
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
hacker         1  0.0  0.0   1128     4 ?        Ss   05:34   0:00 /sbin/docker-init -- /bin/sleep 6h
hacker         7  0.0  0.0   2736   580 ?        S    05:34   0:00 /bin/sleep 6h
hacker       102  0.4  0.0 723944 64660 ?        Sl   05:34   0:00 /usr/lib/code-server/lib/node /usr/lib/code-serve
hacker       138  3.3  0.0 968792 106272 ?       Sl   05:34   0:07 /usr/lib/code-server/lib/node /usr/lib/code-serve
hacker       287  0.0  0.0 717648 53136 ?        Sl   05:34   0:00 /usr/lib/code-server/lib/node /usr/lib/code-serve
hacker       318  3.3  0.0 977472 98256 ?        Sl   05:34   0:06 /usr/lib/code-server/lib/node --dns-result-order=
hacker       554  0.4  0.0 650560 55360 ?        Rl   05:35   0:00 /usr/lib/code-server/lib/node /usr/lib/code-serve
hacker       571  0.0  0.0   4600  4032 pts/0    Ss   05:35   0:00 /usr/bin/bash --init-file /usr/lib/code-server/li
hacker      1172  0.0  0.0   5892  2924 pts/0    R+   05:38   0:00 ps aux
hacker@dojo:~$

<font style="color:#000000;background-color:rgba(255, 255, 255, 0.03);">ps -ef</font><font style="color:#000000;background-color:rgba(255, 255, 255, 0.03);">ps aux</font> 有许多共通点:两者都显示用户(<font style="color:#000000;background-color:rgba(255, 255, 255, 0.03);">USER</font> 列)、PID、TTY、进程的启动时间(<font style="color:#000000;background-color:rgba(255, 255, 255, 0.03);">STIME</font>/<font style="color:#000000;background-color:rgba(255, 255, 255, 0.03);">START</font>)、总使用的 CPU 时间(<font style="color:#000000;background-color:rgba(255, 255, 255, 0.03);">TIME)</font> 和命令(<font style="color:#000000;background-color:rgba(255, 255, 255, 0.03);">CMD</font>/<font style="color:#000000;background-color:rgba(255, 255, 255, 0.03);">COMMAND</font>)。 <font style="color:#000000;background-color:rgba(255, 255, 255, 0.03);">ps-ef</font> 还输出父进程 ID<font style="color:#000000;background-color:rgba(255, 255, 255, 0.03);">PPID),</font> 即启动该进程的 PID,而 <font style="color:#000000;background-color:rgba(255, 255, 255, 0.03);">ps aux</font> 输出进程在系统 CPU 和内存中所占比例。另外,还有很多其他内容


题目将 /challenge/run 重命名为了一个随机文件名,并且禁止你查看 /challenge 目录的内容。但因为这个程序正在运行,你可以通过进程列表找到它。

操作步骤:

利用kill命令终止进程

在 Linux 系统中,终止进程是通过 kill 命令实现的。尽管其名称显得激进,但其本质是向进程发送信号(Signals)

信号机制与 PID

默认情况下,执行 kill 命令会发送一个名为 SIGTERM 的信号。这相当于给进程发送一个“请关闭”的正式请求,允许进程在退出前保存数据或清理临时文件。

与许多文本处理命令不同,kill 不直接接受进程名称作为参数,它必须配合 PID(进程标识符) 使用。

hacker@dojo:~$ sleep 1337
hacker@dojo:~$ ps -e | grep sleep
 342 pts/0    00:00:00 sleep
hacker@dojo:~$ kill 342
hacker@dojo:~$ ps -e | grep sleep
hacker@dojo:~$

现在有一个进程(/challenge/run)无法被运行,需要你先终止它再运行

利用Ctrl+C中断

有时只是想摆脱占用终端资源的进程,可以使用快捷键(按住CTRL并按下C)会向任何正在等待终端输入的应用程序发送“中断”,通常情况下,这个会导致应用程序的正常退出

比如:

资源占用问题

命名管道和进程竞争

命名管道(FIFO)在 Linux 中就像一根物理管道,通常一次只能由一个进程进行有效的写入管理。如果一个“诱饵”进程(Decoy)已经打开并持续向管道内灌入垃圾数据,/challenge/run 就无法顺利完成它的任务。

首先先识别这个命名管道找到/challenge/decoy 的进程PID 使用ps -ef | grep decoy

找到PID之后使用kill强制结束这个进程

等待缓冲区清空

由于 Linux 的管道具有”缓冲(Buffered)"机制,即使进程被杀掉,管道里可能还残存着一些已经发出的“垃圾数据”。

  • 可以运行 cat /tmp/flag_fifo 来观察。
  • 如果屏幕上还在跳动干扰信息,稍等几秒钟,直到数据流停止。

当管道清空的时候且没有进程干扰,就运行主程序:

/challenge/run

然后读取cat /tmp/flag_file

使用CTRL+Z暂停进程

将后台进程挂起

当你按下 Ctrl-Z 时,终端会向当前前台进程发送一个 SIGSTOP 信号。

  • 状态切换:进程并没有消失,而是进入了“停止(Stopped)”状态。它会释放对终端控制权的占用,但依然驻留在内存中。
  • 恢复可能:挂起的进程就像被按下了暂停键的电影,随时可以被恢复运行(我们将在下一关学习如何恢复)。

利用fg恢复进程

当挂起进程后,要怎么做才可以恢复它,一个内置命令fg可以获取挂起的命令

先创建一个进程挂起然后用命令fg恢复

利用命令bg将进程转入后台

Linux 终端中,如果你希望一个程序在运行的同时不占用你的命令行界面,你可以使用 **bg** 命令(Background 的缩写)将其转入后台运行

前台、挂起与后台的状态切换

  • 前台 (Foreground):程序正在运行并占据你的屏幕,你无法输入其他命令。
  • 挂起 (Suspended/Stopped):通过 Ctrl-Z 实现,程序暂停所有动作,像“断电”一样停留在内存中。
  • 后台 (Background):程序正在持续运行,但不占用终端。你可以继续输入命令,而它在“幕后”工作。

如何观察状态差异(Arcanum) :

可以通过 ps 命令配合 -o 选项来观察进程状态(STAT)的细微变化

首先,我们挂起一个 sleep 进程:

hacker@dojo:~$ sleep 1337
^Z
[1]+  Stopped                 sleep 1337

此时 sleep 进程在后台处于挂起(suspended)状态。我们可以通过启用 stat 列来查看:

hacker@dojo:~$ ps -o user,pid,stat,cmd
USER         PID STAT CMD
hacker       702 Ss   bash
hacker       762 T    sleep 1337
hacker       782 R+   ps -o user,pid,stat,cmd
  • **T**:代表该进程因我们按下了 Ctrl-Z 而被挂起/停止
  • **S**(在 bash 行):代表 bash 正在睡眠并等待输入。
  • **R**(在 ps 行):代表它正在活跃运行
  • **+** 符号:代表该进程处于前台

现在,让我们在后台恢复这个 sleep 进程:

hacker@dojo:~$ bg
[1]+ sleep 1337 &
hacker@dojo:~$ ps -o user,pid,stat,cmd
USER         PID STAT CMD
hacker       702 Ss   bash
hacker       762 S    sleep 1337
hacker      1224 R+   ps -o user,pid,stat,cmd

看!sleep 进程的状态现在变成了 **S**。它虽然是在“睡眠”,但它不再是挂起状态了!同时,因为它在后台运行,所以它的状态码后面没有 **+** 符号

按照上述“启动 -> 挂起 -> 后台化 -> 再次启动”的流程操作,即可通过检测并获取 Flag。

挂起、后台化、再恢复

直接启动后台进程

之前的关卡中,你学会了如何将正在运行的进程“推”到后台。但实际上,你并不需要先启动再挂起,可以在命令开始时就直接让它在后台运行。

使用 & 符号直接启动

在 Linux 命令的末尾添加一个 **&** 符号,shell 就会在后台启动该程序,并立即把控制权还给你,让你能继续输入其他命令。

  • 即时反馈:启动后,终端会显示类似 [1] 1771 的信息。
    • [1]作业号 (Job ID)
    • 1771 是该进程的 PID
hacker@dojo:~$ sleep 1337 &
[1] 1771
hacker@dojo:~$ ps -o user,pid,stat,cmd
USER         PID STAT CMD
hacker      1709 Ss   bash
hacker      1771 S    sleep 1337
hacker      1782 R+   ps -o user,pid,stat,cmd
hacker@dojo:~$ 

现在尝试一下/challenge/run

退出码

在 Linux 中,每一个命令在运行结束时都会向系统报告一个退出码(Exit Code)。这个数值用于告知用户或 Shell 该程序是圆满完成了任务,还是中途遇到了错误。

退出码的基本规律

  • **0**:代表成功。程序按预期运行并顺利结束。
  • **0**(通常是 **1****255** 之间的整数):代表失败。不同的数字有时代表特定的错误类型(例如权限不足、找不到文件等)。

如何读取退出码:$? 变量

Shell 提供了一个特殊的变量 **$?** 来存储最近一次执行完的命令的退出码。要查看它的值,你需要使用 echo 命令并在变量名前加上 $ 符号。

让我们看原文中的例子:

成功案例

hacker@dojo:~$ touch test-file
hacker@dojo:~$ echo $?
0

因为 touch 成功创建了文件,退出码为 0

失败案例

hacker@dojo:~$ touch /test-file
touch: cannot touch '/test-file': Permission denied
hacker@dojo:~$ echo $?
1

由于没有权限在根目录下创建文件,touch 报错,退出码变为了 1


时效性$? 永远只保留紧接着的前一个命令的退出码。如果你在运行 /challenge/get-code 之后不小心运行了 ls,那么 echo $? 显示的就是 ls 的结果了。若发生这种情况,请重新运行一次 /challenge/get-code

本练习: 获取一个程序的退出码,并将其作为另一个程序的参数。

posted on 2026-05-12 13:54  shuyaoyyy  阅读(3)  评论(0)    收藏  举报