13、Unix系统进程管理与Shell相关知识详解(上)

Unix系统进程管理与Shell相关知识详解(上)

1. /proc文件系统

在许多Unix系统中,借鉴了贝尔实验室开发的一个概念——/proc文件系统。与通过大量需要不断更新的系统调用提供对内核数据的访问不同,内核数据通过一个特殊的设备驱动程序提供,该驱动程序在 /proc 目录中实现了标准的文件系统接口。每个正在运行的进程在该目录下都有一个以进程号命名的子目录,子目录内包含各种存储内核数据的小文件。该文件系统的详细内容可在大多数系统的 proc(4) 或GNU/Linux系统的 proc(5) 手册页中查看。

GNU/Linux在这方面的发展比其他大多数Unix系统更深入,其 ps 命令通过读取 /proc 目录下的文件来获取所需的所有进程信息。你可以使用 strace -e TRace=file ps aux 命令进行系统调用跟踪来验证这一点。

以下是一个文本编辑器会话的进程文件示例:

$ ls /proc/16521                           # 列出进程16521的proc文件
cmdline  environ  fd    mem     root  statm
cwd      exe      maps  mounts  stat  status
$ ls -l /proc/16521                        # 详细列出这些文件
total 0
-r--r--r--    1 jones    devel  0 Oct 28 11:38 cmdline
lrwxrwxrwx    1 jones    devel  0 Oct 28 11:38 cwd -> /home/jones
-r--------    1 jones    devel  0 Oct 28 11:38 environ
lrwxrwxrwx    1 jones    devel  0 Oct 28 11:38 exe -> /usr/bin/vi
dr-x------    2 jones    devel  0 Oct 28 11:38 fd
-r--r--r--    1 jones    devel  0 Oct 28 11:38 maps
-rw-------    1 jones    devel  0 Oct 28 11:38 mem
-r--r--r--    1 jones    devel  0 Oct 28 11:38 mounts
lrwxrwxrwx    1 jones    devel  0 Oct 28 11:38 root -> /
-r--r--r--    1 jones    devel  0 Oct 28 11:38 stat
-r--r--r--    1 jones    devel  0 Oct 28 11:38 statm
-r--r--r--    1 jones    devel  0 Oct 28 11:38 status

需要注意的是,这些文件看起来似乎都是空的,但实际上,当读取它们时,设备驱动程序会提供相应的数据,它们并不真正存在于存储设备上。它们的时间戳也有些特殊:在GNU/Linux和OSF/1系统中,时间戳反映的是当前时间;而在IRIX和Solaris系统中,显示的是每个进程启动的时间。

/proc 文件的大小为零会让一些实用工具(如 scp tar )产生混淆。你可能需要先使用 cp 命令将它们复制到其他地方,转换为普通文件。

让我们查看其中一个文件的内容:

$ cat -v /proc/16521/cmdline               # 显示进程的命令行
vi^@+273^@ch13.xml^@
2. 进程管理总结

在进程管理方面,我们可以创建、列出、控制、调度和删除进程,还能向进程发送信号并跟踪它们的系统调用。由于进程在私有地址空间中运行,它们不会相互干扰,因此编写可以同时运行的程序时无需特别努力。

进程可以捕获除两个信号之外的几十个信号,并可以选择忽略这些信号或采取任何所需的操作进行响应。这两个无法捕获的信号是 KILL STOP ,它们确保即使是行为恶劣的进程也能被终止或暂停。需要执行清理操作(如保存活动文件、重置终端模式或移除锁)的程序通常会捕获常见信号;否则,大多数未捕获的信号会导致进程终止。 trap 命令让在shell脚本中添加简单的信号处理变得容易。

此外,还有几种不同的机制可用于延迟或控制进程执行。其中, sleep 命令在shell脚本编写中最为有用,不过其他机制也各有其用途。

3. Shell语言概述

POSIX定义的shell语言比原始的V7 Bourne shell大得多,但比ksh93和bash这两种最常用的Bourne shell扩展版本所实现的语言要小得多。如果你要进行大量利用shell语言扩展的脚本编写,很可能会使用这两种shell中的一种或两种。因此,熟悉它们的共同特性和差异是很有价值的。

随着时间的推移,bash已经获得了ksh93的许多扩展,但并非全部。因此,它们之间有相当多的功能重叠,但也存在许多差异。下面我们将详细探讨这些方面。

4. Shell使用中的注意事项

在使用shell时,有一些需要特别注意的地方:
- 保存shell状态 :在POSIX标准中,没有明确的方法来保存函数定义以供后续恢复。以下是保存bash和ksh93 shell状态(包括函数)的示例代码:

{
  set +o                     # 选项设置
  (shopt -p) 2>/dev/null     # bash特定选项,子shell使ksh静音
  set                        # 变量和值
  export -p                  # 导出的变量
  readonly -p                # 只读变量
  trap                       # 陷阱设置
  typeset -f                 # 函数定义(非POSIX)
} > /tmp/shell.state

需要注意的是,bash和ksh93在定义函数时可能使用不同的语法,因此如果你想从一个shell中导出状态并在另一个shell中恢复,需要格外小心。
- echo命令的可移植性问题 echo 命令仅可在最简单的用途中实现可移植性,各种选项和/或转义序列可能可用也可能不可用(尽管有POSIX标准)。在ksh93中,内置的 echo 命令会尝试模拟 $PATH 中找到的外部 echo 命令的行为,目的是为了兼容;而在bash中,内置的 echo 命令在不同的Unix系统上行为一致,目的是为了保持一致性。因此,为了实现完全的可移植性,应避免使用 echo 命令, printf 仍然是最佳选择。
- OPTIND作为局部变量 :在ksh93中,使用 function 关键字定义的函数会有一个局部的 OPTIND 副本。这样,函数可以像独立的脚本一样使用 getopts 处理其参数,而不会影响父进程的选项处理。

5. bash的shopt命令

bash shell除了使用带有长、短选项的 set 命令外,还有一个单独的 shopt 命令用于启用和禁用选项。以下是 shopt 命令的详细信息:

选项 说明
-o 将选项限制为可以使用 set -o 设置的选项
-p 以适合重新读取的形式打印输出
-q 安静模式。退出状态表示选项是否已设置。如果有多个选项,当所有选项都启用时,状态为零;否则为非零
-s 设置(启用)给定的选项
-u 取消设置(禁用)给定的选项

对于 -s -u 选项,如果没有指定选项名称,则分别显示已设置或未设置的选项列表。

其使用语法为:

shopt [ -pqsu ] [ -o ] [ option-name ... ]

该命令的目的是集中控制bash中添加的shell选项,而不是增加 set 选项或shell变量的数量。

6. bash和ksh93的共同扩展 - select循环

bash和ksh都支持 select 循环,它可以轻松生成简单的菜单。其语法简洁,但功能强大,语法如下:

select name [in list]
do
    statements that can use $name ...
done

这与常规的 for 循环语法相同,只是将关键字 for 替换为 select 。并且和 for 循环一样,你可以省略 in list 部分,此时它将默认使用 "$@" ,即带引号的命令行参数列表。

select 循环的工作流程如下:
1. 为列表中的每个项目生成一个菜单,每个选项用数字编号。
2. 打印 PS3 的值作为提示信息,并等待用户输入一个数字。
3. 将所选的选项存储在变量 name 中,将所选的数字存储在内置变量 REPLY 中。
4. 执行循环体中的语句。
5. 无限重复这个过程(后续会介绍如何退出)

以下是一个示例,假设在一个分时系统中,需要根据不同的视频显示终端正确设置 TERM 变量。用户通过终端服务器进行通信,终端服务器无法传递 TERM 环境变量,因此需要在用户登录时提示他们选择终端类型。可以将以下代码放在 /etc/profile 文件中(假设已知一组固定的终端类型):

PS3='terminal? '
select term in gl35a t2000 s531 vt99
do
    if [ -n "$term" ]
    then
        TERM=$term
        echo TERM is $TERM
    fi
done

下面是 select 循环的mermaid流程图:

graph TD;
    A[开始] --> B[生成菜单];
    B --> C[打印提示,等待输入];
    C --> D[存储选择到变量];
    D --> E[执行循环体语句];
    E --> C;
7. 下载bash和ksh93的源代码

如果需要获取bash和ksh93的源代码并进行编译,可以按照以下步骤操作:
- bash :bash可以从自由软件基金会GNU项目的FTP服务器下载。截至目前,当前版本是3.0。可以使用 wget (如果已安装)来获取发行版的tar文件:

$ wget ftp://ftp.gnu.org/gnu/bash/bash-3.0.tar.gz
--17:49:21--  ftp://ftp.gnu.org/gnu/bash/bash-3.0.tar.gz
           => `bash-3.0.tar.gz'

或者使用传统的匿名FTP方式获取文件:

$ ftp ftp.gnu.org                                      # 连接到服务器
Connected to ftp.gnu.org (199.232.41.7).
220 GNU FTP server ready.
Name (ftp.gnu.org:tolstoy): anonymous                  # 匿名登录
230 Login successful.
230-Due to U.S. Export Regulations, all cryptographic software on this
230-site is subject to the following legal notice:
...
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> cd /gnu/bash                                      # 切换到bash目录
250 Directory successfully changed.
ftp> binary                                            # 确保使用二进制模式
200 Switching to Binary mode.
ftp> hash                                              # 打印#标记以显示进度
Hash mark printing on (1024 bytes/hash mark).
ftp> get bash-3.0.tar.gz                               # 下载文件
local: bash-3.0.tar.gz remote: bash-3.0.tar.gz
227 Entering Passive Mode (199,232,41,7,149,247)
150 Opening BINARY mode data connection for bash-3.0.tar.gz (2418293 bytes).

Unix系统进程管理与Shell相关知识详解(下)

8. 其他扩展Bourne风格的Shell

除了bash和ksh93,还有另外两种流行且值得关注的Shell:
- 公共领域Korn Shell(pdksh) :许多开源类Unix系统(如GNU/Linux)都附带了公共领域Korn Shell,即pdksh。它以源代码形式提供,可从其主页http://web.cs.mun.ca/~michael/pdksh/ 开始获取。它附带了在各种Unix平台上进行编译和安装的说明。pdksh最初由Eric Gisin编写,基于Charles Forsyth的公共领域版本7 Bourne Shell克隆版。它大多与1988年的Korn Shell和POSIX兼容,并带有自身的一些扩展。
- Z-Shell(zsh) :zsh是一个强大的交互式Shell和脚本语言,具有许多在ksh、bash和tcsh中能找到的特性,以及一些独特的特性。zsh拥有ksh88的大部分特性,但ksh93的特性较少。它可以免费获取,并且几乎可以在任何现代Unix版本上进行编译和运行,也有针对其他操作系统的移植版本。zsh的主页是http://www.zsh.org/ 。

这两种Shell在《Learning the Korn Shell》(O’Reilly出版)中有更详细的描述。

9. 查看Shell版本

在使用不同的Shell时,有时需要知道它们的版本号,以下是查看几种常见Shell版本的方法:
| Shell名称 | 查看版本命令 | 示例输出 |
| ---- | ---- | ---- |
| bash | bash --version | GNU bash, version 3.00.16(1)-release (i686-pc-linux-gnu) |
| ksh(新版ksh93) | ksh --version | version sh (AT&T Labs Research) 1993 - 12 - 28 p |
| ksh(旧版) | 先输入 ksh ,再输入 ^V | Version 11/16/88f |
| pdksh | echo 'echo $KSH_VERSION' | pdksh | @(#)PD KSH v5.2.14 99/07/13.2 |
| zsh | echo 'echo $ZSH_VERSION' | zsh | 4.1.1 |

似乎没有办法从 /bin/sh 获取版本号,这并不奇怪。大多数商业Unix系统上的真正Bourne Shell都源自System V Release 3(1987年)或Release 4(1989年)的Bourne Shell,从那时起几乎没有变化。希望提供符合POSIX标准Shell的商业供应商通常会通过改编某个版本的Korn Shell来实现这一目的。

10. Shell的初始化和终止

为了支持用户自定义,Shell在启动时会读取某些指定的文件,对于某些Shell,在终止时也会读取。每个Shell都有不同的约定,下面分别进行讨论。

如果编写供他人使用的Shell脚本,不能依赖于启动时的自定义设置。本文中开发的所有Shell脚本都会自行设置环境(例如 $PATH 的值),以便任何人都能运行它们。

Shell的行为取决于它是否是登录Shell。当坐在终端前,响应计算机的提示输入用户名和密码时,会得到一个登录Shell。同样,使用 ssh hostname 时也会得到一个登录Shell。但是,如果通过名称运行Shell,或者作为脚本初始 #! 行中指定的命令解释器隐式运行,或者创建一个新的工作站终端窗口,或者在远程Shell中运行命令(例如 ssh hostname command ),那么这个Shell就不是登录Shell。

Shell通过检查 $0 的值来确定它是否是登录Shell。如果该值以连字符开头,则该Shell是登录Shell;否则不是。可以通过以下简单实验来判断是否为登录Shell:

$ echo $0                                  # 显示Shell名称
-ksh                                      # 是的,这是一个登录Shell

这个连字符并不意味着存在一个名为 /bin/-ksh 的文件,它只是表示父进程在运行 exec() 系统调用启动Shell时将第零个参数设置成了这样。

如果通常只使用单个Shell,那么以下各节中描述的初始化和终止文件不会有太大问题:一旦将它们进行了适当的自定义,可能多年都不需要再进行修改。但是,如果使用多个Shell,则需要更仔细地考虑如何设置自定义,以避免重复和维护麻烦。 . (点)和 test 命令会很有帮助:在自定义脚本中使用它们来读取一小部分精心编写的、适合所有Bourne系列Shell以及所有可访问主机的文件。系统管理员还需要确保 /etc 中的系统范围自定义脚本适用于所有用户。

10.1 Bourne Shell(sh)启动

当Bourne Shell(sh)作为登录Shell时,它会执行以下操作:

test -r /etc/profile && . /etc/profile      # 尝试读取 /etc/profile
test -r $HOME/.profile && . $HOME/.profile  # 尝试读取 $HOME/.profile

也就是说,它可能会在当前Shell的上下文中读取两个启动文件,但不要求这两个文件都存在。注意,主目录下的文件是点文件,而 /etc 中的系统范围文件不是。

本地管理员创建的系统Shell启动文件可能如下所示:

$ cat /etc/profile                         # 显示系统Shell启动文件
PATH=/usr/local/bin:$PATH                 # 将 /usr/local/bin 添加到系统路径开头
export PATH                               # 使其对子进程可见
umask 022                                 # 移除组和其他用户的写权限

一个典型的 $HOME/.profile 文件可以使用如下命令修改本地系统的默认登录环境:

$ cat $HOME/.profile                       # 显示个人Shell启动文件
PATH=$PATH:$HOME/bin                      # 将个人bin目录添加到系统路径末尾
export PATH                               # 使其对子进程可见
11. 总结

POSIX标准为实现可移植的Shell脚本编写做出了很大努力。如果在其定义的范围内进行编写,就有机会编写出可移植的脚本。然而,现实世界仍然比较复杂。虽然bash和ksh93在POSIX的基础上提供了许多扩展,但这两个Shell之间并不总是100%兼容。即使在像 set 选项或保存Shell完整状态这样简单的领域,也有很多小细节需要注意。

shopt 命令可以控制bash的行为,特别推荐在交互式使用时启用 extglob 选项。

bash和ksh93有许多共同的扩展,这些扩展对Shell编程非常有用,如 select 循环、 [[...]] 扩展测试工具、扩展模式匹配、花括号扩展、进程替换和索引数组等。此外,还介绍了一些小而有用的杂项扩展,其中算术 for 循环和 ((...)) 算术命令可能最为显著。

可以从互联网上下载bash和ksh93的源代码,并展示了如何编译这两个Shell。还提到了另外两种流行的扩展Bourne风格的Shell,即pdksh和zsh。

展示了如何确定常用扩展Bourne风格Shell的版本,这在需要确切知道正在使用的程序时非常重要。

最后,不同的Bourne Shell语言实现有不同的启动和终止自定义功能及文件。供一般使用的Shell脚本不应依赖于每个用户设置的功能或变量,而应自行完成所有必要的初始化。

下面是一个总结整个流程的mermaid流程图:

graph LR;
    A[进程管理] --> B[Shell语言];
    B --> C[Shell使用注意事项];
    C --> D[bash shopt命令];
    D --> E[共同扩展select循环];
    E --> F[下载源代码];
    F --> G[其他扩展Shell];
    G --> H[查看Shell版本];
    H --> I[Shell初始化和终止];
    I --> J[总结];
课程设计报告:总体方案设计说明 一、软件开发环境配置 本系统采用C++作为核心编程语言,结合Qt 5.12.7框架进行图形用户界面开发。数据库管理系统选用MySQL,用于存储用户数据小精灵信息。集成开发环境为Qt Creator,操作系统平台为Windows 10。 二、窗口界面架构设计 系统界面由多个功能模块构成,各模块职责明确,具体如下: 1. 起始界面模块(Widget) 作为应用程序的入口界面,提供初始导航功能。 2. 身份验证模块(Login) 负责处理用户登录账户注册流程,实现身份认证机制。 3. 游戏主大厅模块(Lobby) 作为用户登录后的核心交互区域,集成各项功能入口。 4. 资源管理模块(BagWidget) 展示用户持有的全部小精灵资产,提供可视化资源管理界面。 5. 精灵详情模块(SpiritInfo) 呈现选定小精灵的完整属性数据状态信息。 6. 用户名录模块(UserList) 系统内所有注册用户的基本信息列表展示界面。 7. 个人资料模块(UserInfo) 显示当前用户的详细账户资料历史数据统计。 8. 服务器精灵选择模块(Choose) 对战准备阶段,从服务器可用精灵池中选取参战单位的专用界面。 9. 玩家精灵选择模块(Choose2) 对战准备阶段,从玩家自有精灵库中筛选参战单位的操作界面。 10. 对战演算模块(FightWidget) 实时模拟精灵对战过程,动态呈现战斗动画状态变化。 11. 对战结算模块(ResultWidget) 对战结束后,系统生成并展示战斗结果报告数据统计。 各模块通过统一的事件驱动机制实现数据通信状态同步,确保系统功能的连贯性数据一致性。界面布局遵循模块化设计原则,采用响应式视觉方案适配不同显示环境。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值