转自:http://blog.csdn.net/taiyang1987912/article/details/39529291

版权声明:本文为博主原创文章,未经博主允许不得转载。

目录(?)[+]

一、简介

Linux是一种用户控制的多作业操作系统,系统允许多个系统用户同时提交作业,而一个系统用户又可能用多个shell登录,每个系统用户可以用一个shell提交多个作业。了解Bash Shell在多作业管理和进程处理方面的命名和机制有助于理解多用户、多作业的系统。

二、详解

1、子Shell

(1)父子Shell是相对的,它描述了两个Shell进程的fork关系,父Shell指在控制终端或xterm窗口给出提示符的进程,子Shell是由父Shell创建的进程。父Shell创建子Shell调用的是fork函数。

Shell命令可以分为内建命令(Shell本身执行的命令)和外部命令(fork创建出来的子shell执行的命名),内建命令不创建子Shell而外部命令创建子Shell。

(2) 内建命令是包含在Shell工具包中的命令,其中保留字对Shell有特殊含义,保留字本身不是一个命令而是命令结构的一部分。

冒号是Shell中一个特殊的符号,首先冒号可以表示永真(相当于TRUE关键字)如while
:;do...done(while循环的条件始终为真);其次冒号可以清空一个文件,:>log将冒号重定向到文件,log文件内容被清空,所
以:>命名是常用的清空文件的命令;接着冒号最重要的用法是:不做任何事,只做参数展开。

(3)圆括号结构,能强制将其中的命令运行在子shell中,bash3后定义了内部变量BASH_SUBSHELL记录子shell的层次。

  1. #圆括号结构用法
  2. #!/bin/bash
  3. echo "Father Shell is: $BASH_SUBSHELL"      #打印父shell的层次,为0
  4. outervar=OUTER                              #父shell的变量outervar
  5. (                                           #利用圆括号结构创建子shell
  6. echo "SubShell is: $BASH_SUBSHELL"        #子shell的层次为1
  7. (
  8. echo "GrandSubShell is: $BASH_SUBSHELL" #孙shell的层次为2
  9. )
  10. innervar=INNER                            #子shell的变量
  11. echo "innervar=$innervar"
  12. echo "outervar=$outervar"                 #outervar继承了符shell所赋给它的值
  13. )                                           #回到父shell
  14. echo "Father Shell is: $BASH_SUBSHELL"
  15. if [ -z "$innervar" ]                      #子shell中定义变量为空,则说明
  16. then
  17. echo "The \$innervar is not defined in main body."
  18. else
  19. echo "The \$innervar is defined in main body."
  20. fi



      innervar为空值,说明子shell中变量的作用域不能在父Shell中生效。在子shell中将变量export成环境变量,子shell对变量的更改仍然对父shell不可见。

子shell是允许嵌套调用的,可以在函数或圆括号结构内再次调用圆括号结构创建子shell。

子shell只能继承父shell的一些属性,而子shell不可能反过来改变父shell的属性。子shell能够从父shell继承得来的属性有:当
前的工作目录、环境变量、标准输入输出和错误输出、所有已打开的文件描述符、忽略的信号。子shell不能从父shell继承得来的属性是:除了环境变量
和.bashrc文件中定义变量之外的shell变量、未被忽略的信号处理。

利用子shell测试变量是否已经定义的例子:

  1. #!/bin/bash
  2. if (set -u; : $var)  #冒号与$间有空格
  3. then
  4. echo "Variable is set."
  5. fi

其中set -u命令用于设置shell选项,u是nounset表示当使用未定义的变量时,输出错误信息并强制退出。:
$var中冒号是不做任何事只是参数展开,若没有冒号则$var被解释成shell命令,shell试图去执行var变量的值。加上冒号,shell试图
将var变量进行参数展开但不会试图去执行var变量的值。

子shell还可以接收到父shell从管道传送过来的数据,例:cat /etc/passwd | (grep 'root'),使用管道符向子shell发送数据,符shell将cat的结果通过管道发送给子shell,子shell执行grep命令。

shell应用将一个计算量较大的任务分成若干个小任务并行执行。

  1. #子shell用于并行计算的用法
  2. #!/bin/bash
  3. #用圆括号结构创建三个子shell同时执行
  4. (grep -r "root" /etc/* | sort > part1)       &       #与root关键字匹配的行,排序后输出到某文件
  5. (grep -r "root" /usr/local/* | sort > part2) &
  6. (grep -r "root" /lib/* | sort > part3)       &
  7. wait                                                 #等待后台执行的作业全部完成
  8. cat part1 part2 part3 | sort > parttotal
  9. echo "Run time of this script is:$SECONDS"           #输出该脚本执行时间

grep
-r递归搜索,搜索时的计算量比较大,对每个目录创建一个子shell进行并行处理,然后合并。每个圆括号之外有一个&符号,表示此命令放在后台
执行,继续执行下一条命令;若无&符号则需要一条命令执行完毕后再执行下一条命令,就没真正实现并行计算。wait是一个内建命令,用于等待后台
执行的作业全部完成后再执行下面的命令;若没有wait,脚本将三个子shell放在后台执行后直接执行合并临时文件的命令,三个子shell可能并未执
行完毕,此时临时文件中的结果不完整,合并后也将产生不完整的结果。

2、Shell的限制模式

处于限制模式下的shell运行一个脚本或脚本片段,将会禁用一些命令或操作。shell的限制模式是Linux系统基于安全方面的考虑,目的为了限制脚本用户的权限,并尽可能地减小脚本所带来的危害。

Shell的限制模式限制的操作有:用cd命令更改当前工作目录、更改重要的环境变量的值($PATH、$SHELL、$BASH_ENV、$ENV
和$SHELLOPTS)、输出重定向符号(>、>>、>|、>&、<>和&>)、调
用含有一个或多个斜杠的命令名称、使用内建命令exec、使用set+r等命令关闭限制模式。

  1. #正常模式和限制模式的区别
  2. #!/bin/bash
  3. echo "Changing current work directory"
  4. cd /etc                                    #正常模式下改变当前工作目录
  5. echo "Now in $PWD"
  6. set -r                                     #shell选项使代码运行在限制模式下(r是restricted)
  7. echo "------IN RESTRICTED MODE---------"   #开始运行在限制模式下
  8. echo "Trying to change directory"
  9. cd /usr/local                              #cd命令出错,被限制了
  10. echo "\$SHELLOPTS=$SHELLOPTS"              #可以读取$SHELLOPTS变量的值
  11. echo "Now in `pwd`"                        #还是/etc为当前目录
  12. echo
  13. echo "Trying to change \$SHELL"
  14. SHELL="/bin/sh"                            #$SHELL变量在限制模式下只读
  15. echo "\$SHELL=$SHELL"
  16. echo
  17. echo "Trying to redirect output to a file"
  18. who > outputnull                          #输出重定向失败,被限制了
  19. ls -l outputnull                          #outputnull没有被创建

set -r开启shell的restricted选项进入限制模式,还有一种以限制模式运行脚本的方式,就是#!/bin/bash -r,-r表示在限制模式下运行该脚本。

3、进程处理

(1)进程角度看shell执行

内建命令是由shell本身执行的命令,而外部命令则需要创建新的进程来执行。从进程角度归纳shell执行内建命令和外部命令的过程。

当shell命令不是内建命令时,linux利用fork对一个子进程执行该命令,父进程处于等待状态。若该命令或脚本中包含编译过的可执行文件,则内核
将新程序装载到内存,并覆盖子进程,执行结束退出子进程,父进程被重新激活开始读取shell的后一条命令。

fork是系统调用,fork创建的子进程是父进程的副本,两个进程具有同样的环境、打开的文件、用户标志符、当前工作目录和信号等。

(2)进程和作业

作业是用户层面的概念,而进程是操作系统层面的概念。其区别:一个正在执行的进程称为作业,一个作业可以包含多个进程,用户提交作业到操作系统,作业的完成可能依赖于启动多个进程。

进程的三种基本状态:

作业号标识的是在该shell下运行的所有进程,而进程号就标识整个系统下正在运行的所有进程。

其中[1]是作业号,7574是进程号。

(3)作业控制

作业是针对shell而言的,有前台运行和后台运行。内建命令fg可将后台运行的作业放到前台,而&符号使得作业在后台运行。

fg可以指定作业的方法(Ctrl+Z组合键可将正在运行的作业阻塞):

bg命令可将阻塞状态的作业转入后台运行。jobs查看作业列表。disown用于从shell的作业表中删除作业。wait命令用与等待后台作业完成。

(4)信号

信号是在软件层次上对中断机制的一种模拟,原理上一个进程收到一个信号与处理器收到一个中断请求是一样的。信号事件的来源:硬件来源(比如按下键盘或其他
硬件故障)、软件来源(比如系统函数kill、raise、alarm、setitimer和sigqueue函数)。信号是进程间通信机制中唯一的异步通信机制。

shell向进程发送信号大多通过Ctrl键加上一些功能键来实现。

除了利用组合键发送信号外,内建命令kill可用于向进程发送TERM(即terminal)信号,功能和INT信号类似用于停止进程。kill可以通过进程号、作业号(kill  %n)或进程命令名想任何作业发送信号。kill

杀掉自己本身的进程(

记录了运行该脚本的进程号),其中大于128的退出码表示脚本是被系统强行结束的。kill
-l可看出,kill命令一共能发出64种信号。

(5)trap命令

trap是Linux的内建命令,用于捕捉信号,trap命令可以指定收到某种信号时所执行的命令。trap命令的格式如下:trap command sig1 sig2 ... sigN,当接收到sinN中任意一个信号时,执行command命令,command命令完成后继续接收到信号前的操作,直到脚本结束。

  1. #!/bin/bash
  2. trap "echo 'You hit Ctrl+c!'" INT
  3. while :; do
  4. let count=count+1
  5. echo "This is the $count sleep"
  6. sleep 5
  7. done

利用trap命令捕捉INT信号(即与Ctrl+c绑定的中断信号)。trap还可以忽略某些信号,将command用空字符串代替即可,如trap "" TERM INT,忽略kill %n和Ctrl+c发送的信号(kill发送的是TERM信号)。LInux更强劲的杀死进程的命令:kill
-9 进程号(或kill -9 %n作业号)等价与kill -KILL 进程号。

(6)子shell的信号

子shell能继承父shell所忽略的信号,但是不能继承父shell未忽略的信号。

  1. #!/bin/bash
  2. trap "" QUIT            #忽略kill -3信号,并且子shell能继承父shell所忽略的信号
  3. trap "echo 'You want to kill me'" TERM    #父shell处理的信号,子shell不能继承
  4. (                       #子shell,子进程号比父进程号大1
  5. while :; do
  6. let count=count+1
  7. echo "This is the $count sleep"
  8. sleep 5
  9. done
  10. )

父shell忽略QUIT信号但不忽略TERM信号,9987为父
shell进程号9988为子shell进程号,kill -3 9987向父shell发送3信号和kill -3
9988向子shell发送3信号,均未退出,可以看出子shell对QUIT的忽略是从父shell继承而来的。

kill
9987向父shell发送TERM信号,父shell仍存活(因处理了TERM信号),kill
9988向子shell发送TERM信号,子shell退出,随后父shell执行完毕结束。TERM信号能杀掉子shell,说明子shell不能继承
父shel未忽略的信号。

最后出现父shell响应TERM信号的输出,是因为子shell执行fork一个子进程后父shell处于等待状态,只有子shell退出后父shell才会被激活执行输出。

三、总结

(1)理解shell在多作业管理和进程处理方面的命名和机制,有助于控制和管理Linux中的进程和作业。

(2)父shell和子shell的继承特性因充分了解,以及shell的限制模式。

(3)有很多的细节问题还需不断的总结归纳。

(3)在shell编程中不断强化其中的概念,进一步消化

shell浅谈之九子shell与进程处理的更多相关文章

  1. 浅谈自底向上的Shell脚本编程及效率优化

    作者:沐星晨 出处:http://blog.csdn.net/sosodream/article/details/6276758 浅谈自底向上的Shell脚本编程及效率优化 小论文,大家多批评指导:) ...

  2. 浅谈linux中shell变量$#,$@,$0,$1,$2,$?的含义解释

    浅谈linux中shell变量$#,$@,$0,$1,$2,$?的含义解释 下面小编就为大家带来一篇浅谈linux中shell变量$#,$@,$0,$1,$2的含义解释.小编觉得挺不错的,现在就分享给 ...

  3. shell浅谈之十函数

    转自:http://blog.csdn.net/taiyang1987912/article/details/39583179 一.简介 Linux Shell编 程中也会使用到函数,函数可以把大的命 ...

  4. shell浅谈之三for、while、until循环【转】

    转自:http://blog.csdn.net/taiyang1987912/article/details/38929069 版权声明:本文为博主原创文章,未经博主允许不得转载.   目录(?)[- ...

  5. c#Winform程序调用app.config文件配置数据库连接字符串 SQL Server文章目录 浅谈SQL Server中统计对于查询的影响 有关索引的DMV SQL Server中的执行引擎入门 【译】表变量和临时表的比较 对于表列数据类型选择的一点思考 SQL Server复制入门(一)----复制简介 操作系统中的进程与线程

    c#Winform程序调用app.config文件配置数据库连接字符串 你新建winform项目的时候,会有一个app.config的配置文件,写在里面的<connectionStrings n ...

  6. Struts2漏洞导致的反弹shell——青藤云安全使用的是agent进程采集器进行检测

    安全老司机 | Struts2漏洞爆发后,与黑客的一次正面交锋 from:https://zhuanlan.zhihu.com/p/66122521  备注: 青藤云安全:——用的是进程信息采集器 通 ...

  7. centos下shell脚本kill掉mysql锁表进程【笔记】

    前几天发现服务器上的mysql出现锁表了,show processlist后发现好多都是因为写进session才锁表的,看到这个想起了会不会是硬盘空间不够了,马上查看了服务器硬盘空间,发现都100%了 ...

  8. 浅谈Android应用性能之内存

    本文来自http://blog.csdn.net/liuxian13183/ ,引用必须注明出处! 文/ jaunty [博主导读]在Android开发中,不免会遇到许多OOM现象,一方面可能是由于开 ...

  9. 浅谈PHP代码设计结构

    浅谈PHP代码设计结构 您的评价:       还行  收藏该经验       coding多年,各种代码日夜相伴,如何跟代码友好的相处,不光成为职业生涯的一种回应,也是编写者功力的直接显露. 如何看 ...

随机推荐

  1. web开发技术-过滤器

    纪录自己的学习过程,帮助记忆 1.简介 过滤器是服务器端的一个组件,可以接收用户端的请求和响应信息,并且对这些信息进行过滤 过滤器不处理结果,只做一些辅助性操作 2.过滤器的工作原理 3.过滤器的生命 ...

  2. #研发解决方案#discache-分布式缓存查询与管理系统

    郑昀 基于马海元和闫小波的文档 关键词:memcached.redis.分布式缓存.控制台.反序列化.Java 本文档适用人员:研发和运维员工 提纲: 如何查看缓存里的序列化数据? 批量删除来一个 监 ...

  3. ORA-27125: unable to create shared memory segment

    平台环境   :  Oracle Linux Server release 5.7 x86_64 数据库版本 :  Oracle Database 10g Enterprise Edition Rel ...

  4. MS SQL 日常维护管理常用脚本(二)

    监控数据库运行 下面是整理.收集监控数据库运行的一些常用脚本,也是MS SQL 日常维护管理常用脚本(一)的续集,欢迎大家补充.提意见. 查看数据库登录名信息   Code Snippet SELEC ...

  5. 初探ansible安装

    一.ansible介绍常用的自动化运维工具 Puppet —基于 Ruby 开发,采用 C/S 架构,扩展性强,基于 SSL,远程命令执行相对较弱SaltStack —基于 Python 开发,采用 ...

  6. jQuery操作select控件取值和设值

    1.级联select的操作,后一个select的值随着前一个select选中值变化 $(".select_A").change(function(){ $(".selec ...

  7. 基于Ajax+div的“左边菜单、右边内容”页面效果实现

    效果演示: ①默认页面(index.jsp): ②:点击左侧 用户管理 标签下的 用户列表 选项后,右边默认页面内容更新为用户列表页(userList.jsp)的内容 : ③:同理,点击 产品管理.订 ...

  8. W3School-CSS 分类 (Classification) 实例

    CSS 分类 (Classification) 实例 CSS 实例 CSS 背景实例 CSS 文本实例 CSS 字体(font)实例 CSS 边框(border)实例 CSS 外边距 (margin) ...

  9. oracle树形查询 start with connect by

    一.简介 在oracle中start with connect by (prior) 用来对树形结构的数据进行查询.其中start with conditon 给出的是数据搜索范围, connect ...

  10. The superclass "javax.servlet.http.HttpServlet" was not found on the Java Build Path。问题

    JSP页面顶端出现“红色”的报错信息:The superclass "javax.servlet.http.HttpServlet" was not found on the Ja ...