转自: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. 转载文档:Storm实战常见问题及解决方案

    该文档为实实在在的原创文档,转载请注明: http://blog.sina.com.cn/s/blog_8c243ea30101k0k1.html 类型 详细 备注 该文档是群里几个朋友在storm实 ...

  2. webapp开发调试环境--weinre配置

    用谷歌调试工具中的手机模拟器模拟手机进行webapp的开发,与真机上的效果还是有些偏差,opera手机模拟器的效果亦不佳.有时在pc上开发出来的webapp效果良好,在部分真机上就出现了偏差,这时候就 ...

  3. sublime text2 bracketHighLighter 配置

    一.BracketHighlighter能为ST提供括号,引号这类高亮功能,但安装此插件后,默认没有高亮,只有下划线表示,不是很醒目,需要如下配置1. 在ST中用package control安装Br ...

  4. TCP首部解析

    TCP首部: TCP数据被封装在一个IP数据报中,如下: TCP首部数据格式: 16位源都口号,16为目的端口号用于寻找发送端和接收端的应用进程,加上IP首部的源端IP及终端IP,唯一的确认一个TCP ...

  5. sql monitor生成不了报告& FFS hint不生效两个问题思考

    事情的发生就是这么偶然,一步步的深入才能汲取到更深入的知识~~ -------------------START------------------------------------------- ...

  6. iptables一次性封多个ip,使用ipset 工具

    ipset是什么? ipset是iptables的扩展,它允许你创建 匹配整个地址集合的规则.而不像普通的iptables链只能单IP匹配, ip集合存储在带索引的数据结构中,这种结构即时集合比较大也 ...

  7. 用python pickle库来存储数据对象

    pickling有一个更常用的叫法是serialization,它是指把python对象转化成字节流byte stream, unpickling就是把byte stream转换成对象.python的 ...

  8. WEB开发中的字符集和编码

    html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,bi ...

  9. BOOST.Asio——扫盲

    以下内容来自互联网. 鉴于版权之类的东西,我只贴出标题和URL. (无法考证下述资料是否原创.) asio串口编程                                            ...

  10. 使用 python 获取 httpd 程序所占用物理内存

    #!/usr/bin/env python #encoding: utf-8 ''' 思路: /proc/xx_pid/status 文件中的关键字段 VmRSS 来获取某个进程占用的物理内存 步骤: ...