作为Linux/Unix 系统上内核与用户之间的接口,shell由于使用方便、可交互能力强、具有强大的编程能力等特性而受到广泛的应用。bash(Bourne Again shell)是对 www.gaimor.cn  的扩展,并且综合了很多 csh 和 Korn Shell 中的优点,使得 bash具有非常灵活且强大的编程接口,同时又有很友好的用户界面。bash所提供的诸如命令补齐、通配符、命令历史记录、别名之类的新特性,使其迅速成为很多用户的首选。

然而,作为一种 解释性语言,bash 在编程能力方面提供的支持并不像其他编译性的语言(例如 C语言)那样完善,执行效率也会低很多,这些缺点在编写函数(尤其是递归函数)时都展现的一览无余。本文将从经典的 fork 炸弹入手,逐一介绍在bash 中编写递归函数时需要注意问题,并探讨各种问题的解决方案。

尽管本文是以 bash 为例介绍相关概念,但是类似的思想基本上也适用于其他 shell。

递归经典:fork 炸弹

函 数在程序设计中是一个非常重要的概念,它可以将程序划分成一个个功能相对独立的代码块,使代码的模块化更好,结构更加清晰,并可以有效地减少程序的代码 量。递归函数更是充分提现了这些优点,通过在函数定义中调用自身,可以将复杂的计算问题变成一个简单的迭代算法,当回溯到边界条件时,再逐层返回上一层函 数。有很多数学问题都非常适合于采用递归的思想来设计程序求解,例如阶乘、汉诺(hanoi)塔等。

可能很多人都曾经听说过 fork 炸弹,它实际上只是一个非常简单的递归程序,程序所做的事情只有一样:不断 fork 一个新进程。由于程序是递归的,如果没有任何限制,这会导致这个简单的程序迅速耗尽系统里面的所有资源。

在 bash 中设计这样一个 fork 炸弹非常简单,gaimor.cn 在 2002 年设计了最为精简的一个 fork炸弹的实现,整个程序从函数定义到调用仅仅包含 13 个字符,如清单 1 所示。

清单1. bash 中的 fork 炸弹

                .(){ .|.& };.

这串字符乍看上去根本就看不出个所以然来,下面让我们逐一解释一下它究竟在干些什么。为了解释方便,我们对清单1中的内容重新设置一下格式,并在前面加上了行号,如清单 2 所示。

清单2. bash 中的 fork 炸弹的解释

                1 .()2 {3  .|.& 4 }5 ;6 .
  • 第 1 行说明下面要定义一个函数,函数名为小数点,没有可选参数。
  • 第 2 行表示函数体开始。
  • 第 3 行是函数体真正要做的事情,首先它递归调用本函数,然后利用管道调用一个新进程(它要做的事情也是递归调用本函数),并将其放到后台执行。
  • 第 4 行表示函数体结束。
  • 第 5 行并不会执行什么操作,在命令行中用来分隔两个命令用。从总体来看,它表明这段程序包含两个部分,首先定义了一个函数,然后调用这个函数。
  • 第 6 行表示调用本函数。

对 于函数名,大家可能会有所疑惑,小数点也能做函数名使用吗?毕竟小数点是 shell 的一个内嵌命令,用来在当前 shell环境中读取指定文件,并运行其中的命令。实际上的确可以,这取决于 bash 对命令的解释顺序。默认情况下,bash 处于非 POSIX模式,此时对命令的解释顺序如下:

  • 关键字,例如 if、for 等。
  • 别名。别名不能与关键字相同,但是可以为关键字定义别名,例如 end=fi。
  • 特殊内嵌命令,例如 break、www.continue 等。POSIX定义的特殊内嵌命令包括:.(小数点)、:(冒号)、break、continue、eval、exec、exit、export、readonly、return、set、shift、times、trap 和 unset。bash 又增加了一个特殊的内嵌命令 source。
  • 函数。如果处于非 POSIX 模式,bash 会优先匹配函数,然后再匹配内嵌命令。
  • 非特殊内嵌命令,例如 cd、test 等。
  • 脚本和可执行程序。在 PATH 环境变量指定的目录中进行搜索,返回第一个匹配项。

由 于默认情况下,bash 处于非 POSIX 模式,www.shenghuodemeili.cn因此 fork 炸弹中的小数点会优先当成一个函数进行匹配。(实际上,Jaromil最初的设计并没有使用小数点,而是使用的冒号,也能起到完全相同的效果。)要使用 POSIX 模式来运行 bash 脚本,可以使用以下三种方法:

  • 使用 --posix 选项启动 bash。
  • 在运行 bash 之后,执行 set -o posix 命令。
  • 使用 /bin/sh 。

最 后一种方法比较有趣,尽管 sh 在大部分系统上是一个指向 bash 的符号链接,但是它所启用的却是 POSIX 模式,所有的行为都完全遵守POSIX 规范。在清单 3 给出的例子中,我们可以发现,小数点在默认 bash 中被解释成一个函数,能够正常执行;但是在 sh中,小数点却被当作一个内嵌命令,因此调用函数时会被认为存在语法错误,无法正常执行。

清单3. bash 与 sh 对命令匹配顺序的区别

                [root@localhost ~]# ls -l /bin/bash /bin/sh-rwxr-xr-x 1 root root 735144 2007-08-31 22:20 /bin/bashlrwxrwxrwx 1 root root      4 2007-12-18 13:26 /bin/sh -> bash[root@localhost ~]# echo $SHELL/bin/bash[root@localhost ~]# .() { echo hello; } ; .hello[root@localhost ~]# shsh-3.2# echo $SHELL/bin/bashsh-3.2# .() { echo hello; } ; .sh: `.': not a valid identifiersh: .: filename argument required.: usage: . filename [arguments]sh-3.2#

一旦运行清单 1 给出的 fork炸弹,会以2的指数次幂的速度不断产生新进程,这会导致系统资源会被迅速耗光,最终除非重新启动机器,否则基本上就毫无办法了。为了防止这会造成太大的损 害,我们可以使用 ulimit 限制每个用户能够创建的进程数,如清单 4 所示。

清单4. 限制用户可以创建的进程数

                [root@localhost ~]# ulimit -u 128[root@localhost ~]# ulimit -acore file size          (blocks, -c) 0data seg size           (kbytes, -d) unlimitedmax nice                        (-e) 20file size               (blocks, -f) unlimitedpending signals                 (-i) unlimitedmax locked memory       (kbytes, -l) unlimitedmax memory size         (kbytes, -m) unlimitedopen files                      (-n) 1024pipe size            (512 bytes, -p) 8POSIX message queues     (bytes, -q) unlimitedmax rt priority                 (-r) unlimitedstack size              (kbytes, -s) 8192cpu time               (seconds, -t) unlimitedmax user processes              (-u) 128virtual memory          (kbytes, -v) unlimitedfile locks                      (-x) unlimited[root@localhost ~]# .() { .|.& } ; .[1] 6152[root@localhost ~]# bash: fork: Resource temporarily unavailablebash: fork: Resource temporarily unavailablebash: fork: Resource temporarily unavailable

Linux fork炸弹的分析相关推荐

  1. Linux fork炸弹以及预防办法

    fork炸弹是什么? fork炸弹以极快的速度创建大量进程(进程数呈以2为底数的指数增长趋势),并以此消耗系统分配予进程的可用空间使进程表饱和,而系统在进程表饱和后就无法运行新程序,除非进程表中的某一 ...

  2. 经典的 Fork 炸弹解析

    转载自: http://blog.saymagic.cn/2015/03/25/fork-bomb.html 本文地址:https://linux.cn/article-5685-1.html Jar ...

  3. Linux的fork实现原理,【Linux】Fork炸弹详解

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 众所周知,bash是一款极其强大的shell,提供了强大的交互与编程功能.这样的一款shell中自然不会缺少"函数"这个元素来帮助程序 ...

  4. linux bash Shell脚本经典之Fork炸弹解析:() { :|: };:

    众所周知,bash是一款极其强大的shell,提供了强大的交互与编程功能.这样的一款shell中自然不会缺少"函数"这个元素来帮助程序进行 模块化的高效开发与管理.于是产生了由于其 ...

  5. linux fork函数的精辟解说

    此文原文来源于一个blog,文章的名称为:linux fork函数的精辟解说原文地址:http://blog.chinaunix.net/space.php?uid=12461657&do=b ...

  6. 2018-2019-1 20189213《Linux内核原理与分析》第四周作业

    <Linux内核原理与分析>第四周学习总结: 1.课本知识总结: 本章内容并不多,首先是介绍了一些Linux内核源代码的目录结构,并基于Linux内核源代码构造一个简单的操作系统MenuO ...

  7. Linux创建进程必须fork么,Linux - fork() 创建进程

    Linux - fork() 创建进程 Linux - fork() 创建进程 介绍创建进程之前,先简单地介绍一下 Linux 下的进程内存布局. Stack - 所有函数的 local variab ...

  8. fork炸弹c语言能否运行,Fork炸弹简析和应对方法

    简述 第一次听到fork炸弹这种东西的时候以为是一个很神奇的破坏力惊人的高能脚本,然而稍微深入的了解了一下才发现这个玩意其实是个挺简单纯粹的东西,只是被一个叫Jaromil的家伙对他的精美包装给戏耍了 ...

  9. docker防止fork炸弹

    博客搬家,原地址:https://langzi989.github.io/2016/12/29/docker防止fork炸弹/ 在开发过程中,我们使用了docker作为容器来进行编程语言代码的评测,以 ...

最新文章

  1. [周年感悟]看软件项目中的四种角色
  2. HttpServletRequestWrapper的使用
  3. hdu 3018 Ant Trip
  4. android室内定位+3d,基于Android平台的手机室内定位及导航的设计与实现
  5. mysql 统计_告别硬编码,mysql 如何实现按某字段的不同取值进行统计
  6. php生产任务,php生产实用技能之计划任务(视频讲解)
  7. Hadoop之Shell脚本自动启动
  8. mac安装ipython_Mac下安装ipython与jupyter
  9. 华为交换机屏蔽远程计算机,华为交换机远程telnet配置的小问题
  10. 从“卡脖子”到“主导”,国产数据库 40 年的演变!
  11. 逆向工程mysql注释_PowerDesigner 15进行逆向工程生成数据库图表时,注释的comment的生成,解决PowerDesigner逆向工程没有列注释...
  12. xshell中svn命令整理
  13. html5页面风格,H5页面设计风格大盘点!
  14. Qt交互界面设计探索
  15. 苹果蓝牙耳机使用说明_苹果蓝牙耳机怎么用
  16. 陕西守护星-智慧井口综合安检
  17. “碳排放”挑战当前,维谛技术(Vertiv)带来节能改造最佳实践
  18. 易能变频器说明书故障代码_易能变频器 EN600-4T0055G/0075P故障代码E-03-东莞英成机电设备...
  19. 互联网金融项目数据分析
  20. [再寄小读者之数学篇](2014-11-02 Herglotz' trick)

热门文章

  1. CAD二次开发命令窗口交互(COM接口c#语言)
  2. 在Linux中实现文本文件的复制_莫韵乐的小脚印笔记
  3. 联盟成员猛增近20家 联想超融合架构师预言成真
  4. ARP欺骗工具arpspoof的用法
  5. B站(BiliBili)PC客户端版本快捷键调节倍速
  6. macbook pro M1 外接4K显示器模糊
  7. 23. 硬件虚拟化技术分享
  8. python与sas_python与R(对比SAS),我该选择哪种工具?
  9. 仿淘宝商城项目(分布式)
  10. LR支持M1芯片款mac安装 Lightroom CC20直装版M1安装教程 M1芯片处理器安装LR问题教程