Bash脚本进阶指南
Repo
  • 正文
    • 第一部分 初见shell
      • 1. 为什么使用shell编程
      • 2. 和Sha-Bang(#!)一起出发
        • 2.1 调用一个脚本
        • 2.2 牛刀小试
    • 第二部分 shell基础
      • 3. 特殊字符
      • 4. 变量与参数
        • 4.1 变量替换
        • 4.2 变量赋值
        • 4.3 Bash弱类型变量
        • 4.4 特殊变量类型
      • 5. 引用
        • 5.1 引用变量
        • 5.2 转义
      • 6. 退出与退出状态
      • 7. 测试
        • 7.1 测试结构
        • 7.2 文件测试操作
        • 7.3 其他比较操作
        • 7.4 嵌套 if/then 条件测试
        • 7.5 牛刀小试
      • 8. 运算符相关话题
        • 8.1 运算符
        • 8.2 数字常量
        • 8.3 双圆括号结构
        • 8.4 运算符优先级
    • 第三部分 shell进阶
      • 9. 换个角度看变量
        • 9.1 内部变量
        • 9.2 变量类型标注:declare 与 typeset
          • 9.2.1 declare 的另类用法
        • 9.3 $RANDOM:生成随机数
      • 10. 变量处理
        • 10.1 字符串处理
          • 10.1.1 使用 awk 处理字符串
          • 10.1.2 参考资料
        • 10.2 参数替换
      • 11. 循环与分支
        • 11.1 循环
        • 11.2 嵌套循环
        • 11.3 循环控制
        • 11.4 测试与分支
      • 12. 命令替换
      • 13. 算术扩展
      • 14. 休息时间
    • 第四部分 命令
      • 15. 内建命令
        • 15.1 任务控制命令
      • 16. 外部筛选器,任务及命令
        • 16.1 基础命令
        • 16.2 复杂命令
        • 16.3 时间/日期命令
        • 16.4 文本处理命令
        • 16.5 文件与归档命令
        • 16.6 通信命令
        • 16.7 终端控制命令
        • 16.8 数学命令
        • 16.9 杂项命令
      • 17. 系统与管理命令
        • 17.1 分析一个系统脚本
    • 第五部分 高级话题
      • 18.正则表达式
        • 18.1正则表达式简介
        • 18.2文件名替换
      • 19. 嵌入文档
      • 20. I/O 重定向
        • 20.1 使用 exec
        • 20.2 重定向代码块
        • 20.3 应用程序
      • 21. 子shell
      • 22. 限制模式的Shell
      • 23. 进程替换
      • 24. 函数
        • 24.1 复杂函数和函数复杂性
        • 24.2 局部变量
        • 24.3 不适用局部变量的递归
      • 25. 别名
      • 26. 列表结构
      • 27. 数组
      • 28. 间接引用
      • 29. /dev 和 /proc
        • 29.1 /dev
        • 29.2 /proc
      • 30. 网络编程
      • 32. 调试
      • 33. 选项
      • 34. 陷阱
      • 36. 杂项
        • 36.1 交互和非交互shell以及脚本
        • 36.2 shell wrappers
        • 36.3 测试和比较的其他方法
        • 36.4 递归:调用自己的脚本
        • 36.5 “彩色”的脚本
        • 36.6 优化
        • 36.7 其他技巧
        • 36.8 安全问题
        • 36.9 可移植性问题
        • 36.10 Windows系统下的脚本
    • 38. 后记
      • 38.1 作者后记
      • 38.2 关于作者
      • 38.3 从哪里可以获得帮助
      • 38.4 用来制作这本书的工具
      • 38.5 致谢
      • 38.6 免责声明
  • 附录及索引
    • 参考文献
    • 附录
    • 索引
由 GitBook 提供支持
在本页
  • jobs
  • disown
  • fg, bg
  • wait
  • suspend
  • logout
  • times
  • kill
  • killall
  • builtin
  • enable
  • autoload
  • 表格 15-1. 作业标识符
  • 注记

这有帮助吗?

  1. 正文
  2. 第四部分 命令
  3. 15. 内建命令

15.1 任务控制命令

上一页15. 内建命令下一页16. 外部筛选器,任务及命令

最后更新于1年前

这有帮助吗?

以下某些作业控制命令将作业标识符作为参数。您可以参阅本章末尾的。

jobs

列出在后台运行的作业,并给出该作业ID。在实际应用中,没有有用。

非常容易将作业和进程二者混淆。某些 (例如kill,disown和wait) 既接受作业ID,又接受进程ID作为参数。、和jobs命令仅接受一个作业编号。

bash$ sleep 100 &
[1] 1384

bash $ jobs
[1]+  Running                 sleep 100 &

“1” 是作业ID (作业由当前shell维护)。“1384” 是或进程ID号 (进程由系统维护)。如果要杀死这个作业/进程,可以使用kill % 1或kill 1384。

感谢 S.C.

disown

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

fg, bg

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

wait

样例 15-26. 等待一个进程结束后再继续

#!/bin/bash

ROOT_UID=0   # 只有UID是0的用户拥有root权限。
E_NOTROOT=65
E_NOPARAMS=66

if [ "$UID" -ne "$ROOT_UID" ]
then
  echo "Must be root to run this script."
  # “快跑吧,孩子,已经过了你的就寝时间了。”
  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 &     # 必须使用root权限运行。

wait
# 直到"updatedb"运行结束,不要运行这个脚本剩下部分的代码。
# 你希望在查找文件名之前更新数据库。

locate $1

# 没有"wait"命令,在更加糟糕的情况下,
# 这个脚本将会在"updatedb"仍在运行的情况下退出,
# 并且将它作为一个孤立进程。

exit 0

在脚本中,在后台运行带有 & 符号的命令可能会导致脚本挂起,直到命中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输出提示。(译者注:即输出Done)

  4. 后台命令继续运行并向控制台写入文本。(译者注:即ls -l命令的输出信息写入标准输出(stdout))

  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

suspend

该命令与Control-Z具有类似的效果,但它会挂起shell (shell的父进程应在适当的时间恢复它)。

logout

times

以以下形式展现执行命令时经过的系统时间的统计信息:

0m0.020s 0m0.020s

此功能的价值相对有限,因为它在配置文件和基准测试shell脚本中并不常见。

kill

样例 15-27. 一个杀死自己的脚本

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

kill $$  # 这里,脚本杀死自己的进程。
         # 回想一下,"$$"指的是当前脚本的PID。

echo "This line will not echo."
# 相反,shell会将"终止"信息传递给标准输出(stdout)。

exit 0   # 正常地退出?非也!

#  在这脚本过早终止后,
#  它返回了一个怎样的退出状态?
#
# sh self-destruct.sh
# echo $?
# 143
#
# 143 = 128 + 15
#             终止信号

killall

builtin

enable

autoload

请注意,autoload不是核心Bash安装的一部分。它需要用enable -f加载 (见上文)。

表格 15-1. 作业标识符

符号表示
意义

%N

作业编号 [N]

%S

以字符串S开始的作业调用(命令行)

%?S

包含字符串S的作业调用(命令行)

%%

“当前”作业(指最后一个在前台停止或在后台启动的作业)

%+

“当前”作业(指最后一个在前台停止或在后台启动的作业)

%-

最后一个作业

$!

最后一个后台进程

注记

暂停脚本执行,直到在后台运行的所有作业都终止,或者直到以作业ID或进程ID标识的指定后台作业终止。返回wait-for命令的。

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

或者,wait可以将作业标识符作为一个参数,例如,wait % 1或wait $ PPID。 请参阅。

将命令的输出到文件甚至是/dev/null也可以解决此问题。

退出登录的shell,可以有选择性地指定它的。

通过向进程发送适当的终止信号来强制终止进程 (参见)。

kill -l列出了所有(与文件/usr/include/asm/signal.h一样)。kill -9是一个有把握的kill,通常会终止那些顽固地拒绝以简单的kill终止的进程。有些情况下,kill -15是生效的。僵尸进程是指子进程已经被终止,而还没有(已经)被杀死,僵尸进程无法被登录用户杀死 -- 你不能杀死任何已经死去的东西 -- 但是,通常init会迟早清理它。

killall命令通过名称来杀死一个运行中的程序,而不是通过。如果某个特定命令的多个实例正在运行,则执行killall将终止所有实例。

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

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

该命令可以启用或禁用shell内建命令。例如,enable -n kill会禁用shell内建命令,因此当Bash随后遇到kill命令时,它会调用外部命令/bin/kill。

enable命令的-a选项列出了所有的shell内建命令,并提示它们是否已启用。enable命令的-f 文件名选项可以从正确编译的对象文件中加载共享库 (DLL) 模块作为。 。

这是ksh自动加载器的Bash入口。当autoload到位的情况下,带有autoload声明的函数将在第一次调用时从外部文件加载。 这节省了系统资源。

当然,这仅适用于子进程。

通常能够在/usr/share/doc/bash-?.??/functions目录下找到许多可加载的内建命令的C源码。

注意,enable命令的-f选项并非到所有系统。

使用可以达到与autoload相同的效果。

退出状态
孤立进程
[1]
作业id表
重定向
退出状态
样例 17-6
进程ID
内建命令
kill
内建命令
[2]
[3]
[1]
[2]
可移植
[3]
typeset -fu
ps
内建命令
fg
bg
PID
表格
信号
父进程
builtin
enable
note
note
note