15.1. 作业控制命令

以下某些作业控制命令接受作业标识符作为参数。 请参阅本章末尾的表格

jobs

列出在后台运行的作业,并给出作业号。 不如 ps 命令有用。

Note

很容易混淆作业进程。 某些内建命令,例如 killdisownwait,接受作业号或进程号作为参数。fgbgjobs 命令仅接受作业号。

bash$ sleep 100 &
[1] 1384

bash $ jobs
[1]+  Running                 sleep 100 &

"1" 是作业号(作业由当前 shell 维护)。 "1384"PID进程 ID 号(进程由系统维护)。 要终止此作业/进程,kill %1kill 1384 都可以。

谢谢,S.C.

disown

从 shell 的活动作业表中移除作业。

fg, bg

fg 命令将后台运行的作业切换到前台。 bg 命令重新启动挂起的作业,并在后台运行。 如果未指定作业号,则 fgbg 命令作用于当前正在运行的作业。

wait

暂停脚本执行,直到后台运行的所有作业都终止,或者直到指定为选项的作业号或进程 ID 终止。 返回等待命令的退出状态

您可以使用 wait 命令来防止脚本在后台作业完成执行之前退出(这将创建一个可怕的孤儿进程)。

示例 15-26. 等待进程完成再继续

#!/bin/bash

ROOT_UID=0   # Only users with $UID 0 have root privileges.
E_NOTROOT=65
E_NOPARAMS=66

if [ "$UID" -ne "$ROOT_UID" ]
then
  echo "Must be root to run this script."
  # "Run along kid, it's past your bedtime."
  exit $E_NOTROOT
fi  

if [ -z "$1" ]
then
  echo "Usage: `basename $0` find-string"
  exit $E_NOPARAMS
fi


echo "Updating 'locate' database..."
echo "This may take a while."
updatedb /usr &     # Must be run as root.

wait
# Don't run the rest of the script until 'updatedb' finished.
# You want the the database updated before looking up the file name.

locate $1

#  Without the 'wait' command, in the worse case scenario,
#+ the script would exit while 'updatedb' was still running,
#+ leaving it as an orphan process.

exit 0

可选地,wait 可以接受作业标识符作为参数,例如,wait%1wait $PPID. [1] 请参阅作业 ID 表

Tip

在脚本中,使用 & 在后台运行命令可能会导致脚本挂起,直到按下 ENTER 键。 这似乎发生在写入stdout的命令中。 这可能是一个主要的烦恼。

#!/bin/bash
# test.sh		  

ls -l &
echo "Done."
bash$ ./test.sh
Done.
 [bozo@localhost test-scripts]$ total 1
 -rwxr-xr-x    1 bozo     bozo           34 Oct 11 15:09 test.sh
 _
               

    正如 Walter Brameld IV 解释的那样

    据我所知,此类脚本实际上并没有挂起。 它只是
    看起来像挂起,因为后台命令在提示符后将文本写入
    控制台。 用户得到的印象是
    提示符从未显示。 这是事件的顺序

    1. 脚本启动后台命令。
    2. 脚本退出。
    3. Shell 显示提示符。
    4. 后台命令继续运行并将文本写入
       控制台。
    5. 后台命令完成。
    6. 用户在输出的底部看不到提示符,认为脚本
       挂起了。

在后台命令后放置 wait 似乎可以解决这个问题。

#!/bin/bash
# test.sh		  

ls -l &
echo "Done."
wait
bash$ ./test.sh
Done.
 [bozo@localhost test-scripts]$ total 1
 -rwxr-xr-x    1 bozo     bozo           34 Oct 11 15:09 test.sh
               
重定向命令的输出到文件,甚至到/dev/null也可以解决这个问题。

suspend

这具有类似于 Control-Z 的效果,但它会挂起 shell(shell 的父进程应在适当的时候恢复它)。

logout

退出登录 shell,可以选择指定退出状态

times

给出执行命令时系统经过时间的统计信息,格式如下

0m0.020s 0m0.020s

此功能价值相对有限,因为对 shell 脚本进行性能分析和基准测试并不常见。

kill

通过向进程发送适当的终止信号来强制终止进程(请参阅示例 17-6)。

示例 15-27. 一个杀死自身的脚本

#!/bin/bash
# self-destruct.sh

kill $$  # Script kills its own process here.
         # Recall that "$$" is the script's PID.

echo "This line will not echo."
# Instead, the shell sends a "Terminated" message to stdout.

exit 0   # Normal exit? No!

#  After this script terminates prematurely,
#+ what exit status does it return?
#
# sh self-destruct.sh
# echo $?
# 143
#
# 143 = 128 + 15
#             TERM signal

Note

kill -l列出所有信号(文件/usr/include/asm/signal.h也是如此)。kill -9是一个确定杀死,通常会终止一个顽固地拒绝使用普通的 kill 命令终止的进程。 有时,kill -15有效。僵尸进程,即已终止的子进程,但 父进程 尚未(还)杀死,无法被已登录的用户杀死 -- 你不能杀死已经死的东西 -- 但 init 通常会迟早清理它。

killall

killall 命令通过名称而不是进程 ID 杀死正在运行的进程。 如果有特定命令的多个实例正在运行,则对该命令执行 killall 将终止所有实例。

Note

这是指/usr/bin中的 killall 命令,而不是/etc/rc.d/init.d.

中的 killall 脚本

command

bash$ command ls
              

Note

command 指令禁用紧随其后的命令的别名和函数。

这是影响脚本命令处理的三个 shell 指令之一。 其他的是 builtinenable

builtin调用 builtin BUILTIN_COMMAND 将命令BUILTIN_COMMAND

作为 shell 内建命令 运行,暂时禁用具有相同名称的函数和外部系统命令。

enable这启用或禁用 shell 内建命令。 例如,enable -n kill禁用 shell 内建命令 kill,以便当 Bash 随后遇到 kill 时,它会调用外部命令.

/bin/killenable-a选项列出所有 shell 内建命令,指示它们是否已启用。-f filename

选项允许 enable 从正确编译的目标文件加载 内建命令 作为共享库 (DLL) 模块。 [2]

autoload

这是 ksh 自动加载器的 Bash 端口。 使用 autoload,具有 autoload 声明的函数将在首次调用时从外部文件加载。 [3] 这节省了系统资源。请注意,autoload 不是核心 Bash 安装的一部分。 它需要使用enable -f

加载(见上文)。

表 15-1. 作业标识符符号
含义%N
作业号 [N]%S
作业的调用(命令行)以字符串 S 开头%?S
%%作业的调用(命令行)在其内部包含字符串 S
%+作业的调用(命令行)在其内部包含字符串 S
%-"current" 作业(在前台停止或在后台启动的最后一个作业)
$!最后一个作业

最后一个后台进程

[1]

注释

[2]

这当然仅适用于子进程许多可加载的内建命令的 C 源代码通常可以在/usr/share/doc/bash-?.??/functions

目录中找到。请注意,enable-f

[3]

选项并非可移植到所有系统。