您的位置:首页 > 运维架构 > Shell

13 子Shell与进程处理

2015-03-13 14:47 225 查看
13.1 子Shell

Shell本身也是一个程序,也可以启动自己的子进程,这些子进程称为子Shell。作为初学者,必须搞清楚子Shell与其父Shell的区别与联系以及Shell命令与子Shell的关系。本节将对子Shell的基础知识进行介绍。

13.1.1 什么是子Shell

所谓子Shell,实际上是父Shell的一个子进程。子Shell本身也可以创建自己的子进程,从而成为其子进程的父Shell。从定义可以看出,父Shell和子Shell都是相对的。某个Shell可以成为一个Shell的父Shell,也可以同时成为另外一个Shell的子Shell,反之亦然。在环境变量以及标准输入、标准输出和标准错误等方面,父Shell和子Shell是相同的。

#! /bin/bash

cd /var/log

pwd

13.1.2 内部命令、保留字和外部命令

Shell命令分为内部命令和外部命令。所谓内部命令,是指包含在Shell工具包中的命令,内部命令是Shell本身的重要组成部分。内部命令嵌入在Shell程序中,并不单独以磁盘文件的形式存在于磁盘上。例如cd、bg以及fg等命令都是bash Shell的内部命令。

bash常用的内部命令

. 读取shell脚本,并在当前脚本中执行

alias 设置命令别名

bg 将作业置于后台运行

cd 改变当前工作目录

echo 打印指定的文本

eval 将参数作为shell命令执行

exec 以特定的程序取代shel或者改变当前shell的输出输入

exit 退出shell

export 将变量声明为环境变量

fc 与命令历史一起运行

fg 将作业置于前台运行

getopts 处理命令行选项

history 显示命令历史

jobs 显示在后台运行的作业

kill 向进程发信号

logout 从shell中注销

pwd 显示当前工作目录

set 设置(显示)shell环境变量

shift 变换命令行参数

#! /bin/bash

ps -ef|grep ps

echo $SHLVL

pidof -x ex13-2.sh

exit 0

13.1.3 在子Shell中执行命令

1.圆括号结构

当一组命令放在圆括号中时,该组命令会在一个子Shell环境中执行,其语法如下:

(command1;command2;command3;...)

在上面的语法中,command1、command2以及command3等都是Shell命令,这些命令些在一行中,它们之间用分号隔开。

#!/bin/bash

echo

echo "Subshell level OUTSIDE subshell = $BASH_SUBSHELL"

echo

outer_variable=Outer

(

echo "Subshell level INSIDE subshell = $BASH_SUBSHELL"

inner_variable=Inner

echo "From subshell, \"inner_variable\" = $inner_variable"

echo "From subshell, \"outer\" = $outer_variable"

)

echo

echo "Subshell level OUTSIDE subshell = $BASH_SUBSHELL"

echo

if [ -z "$inner_variable" ] ;then

echo "inner_variable undefined in main body of shell"

else

echo "inner_variable defined in main body of shell"

fi

echo "From main body of shell, \"inner_variable\" = $inner_variable"

echo

exit 0

#!/bin/bash

echo "Before starting subshell"

(

count=1

while [ $count -le 10 ]

do

echo "$count"

sleep 1

(( count++ ))

done

) &

echo "Finished"

2.后台执行或异步执行

在某些情况下,Shell命令需要较长的时间来执行,尤其是在处理大量的数据的时候。在这种情况下,用户可以将命令置于后台执行,而不必等待命令执行结束。

将命令置于后台执行的语法如下:

command &

#! /bin/bash

echo "generating a background child process"

for ((i=9; i>=0; i--))

do

sleep 1

echo -e "\rsleeping ${i}s ...\c"

done &

## 创建后台进程

## 获取最近创建的后台进程的PID

BG_PID=$!

echo "child process's PID is ${BG_PID}"

3.命令替换

命令替换的语法如下:

`command`

或者

$(command)

其中,command表示要执行的命令。command会在一个子Shell中执行,不会影响到当前的Shell环境。

#! /bin/bash

(cd /;ls;echo "current working directory is ";pwd)

echo "current working directory is"

pwd

13.1.4 把子Shell中的变量值传回父Shell

在子Shell中,代码可以访问父Shell的变量;反之,在父Shell中,却无法访问到子Shell中的变量的值。但是,用户可以通过一些变通的技巧来取得子Shell中的变量的值。下面分别进行介绍。

1.通过临时文件

在Linux中,通过临时文件传递数据是一个非常重要的技巧,许多地方都使用到。对于磁盘文件来说,只要拥有足够的权限,任何进程都可以访问到。另外,通过临时文件,用户可以在进程之间传递大量的数据,不会受到内存空间的限制。

#! /bin/bash

(

x=500

echo "$x" >tmp

)

echo "$x"

read b <tmp

echo "$b"

2.使用命名管道

命名管道是Linux以及UNIX系统中的最古老的进程间通信的方式,同时也是一个相对比较简单的通信机制。

#! /bin/bash

if [ ! -e fifo ];then

mkfifo fifo

fi

(

x=500

echo "$x" > fifo

)&

read y <fifo

echo "$y"

3.不使用子Shell

之所以出现以上变量传递问题,是因为使用了子Shell。如果不使用子Shell,则以上问题就不存在。当用户在某个Shell脚本中调用另外一个脚本时,被调用的脚本会在子Shell中执行。但是,用户可以通过圆点命令和source命令来执行脚本,使得被调用的脚本在当前Shell进程中执行。

#! /bin/bash

echo "$message"

#! /bin/bash

message="Hello world."

source ./output.sh

13.2 进程处理

在进行系统维护的过程中,经常会遇到进程和作业的处理问题。通过Shell编程,用户可以对进程和作业进行有效地管理。本节介绍如何通过Shell进行进程的相关操作。

13.2.1 什么是进程

进程是指在自身的虚拟地址空间运行的一个单独的程序,是程序执行的基本单元。进程会利用处理器资源、内存资源,并且进行各种I/O操作,从而完成某项指定的任务。因此,进程是一个动态的概念。

13.2.2 通过脚本监控进程

通常情况下,通过脚本来监控进程可以收到事半功倍的效果。例如,在绝大部分的Web服务器都是运行在Linux上面。但是在某些情况下,Web服务器的进程httpd会由于某些错误而退出,导致用户的网站不能访问。而系统管理员则不可能会24小时都在监控Web服务器的运行状态。

#! /bin/bash

RESTART="/sbin/service httpd restart"

PGREP="/usr/bin/pgrep"

HTTPD="httpd"

$PGREP ${HTTPD} &>/dev/null

if [ $? -ne 0 ] ;then

$RESTART

fi

13.2.3 作业控制

作业控制指的是用户控制正在运行的组成作业的进程的行为。在前面已经介绍过,用户可以在命令的后面附加&操作符,使得该命令在后台执行。另外,用户还可以将作业中的某个进程挂起,暂停其执行,然后在某个时刻再继续执行该进程。

#! /bin/bash

sleep 10

13.2.4 信号与trap命令

信号在Linux系统中非常重要的一种通信机制。信号在软件层次上模拟了硬件中断机制。因此,简单地讲,信号即软件中断。在Linux系统中,用户可以通过kill命令给某个进程发送一个特定的信号,也可以通过键盘发送一些信号,比如组合键CTRL+C可能触发 SIGINT信号,而组合键CTRL+\可能触发SIGQUIT信号等。

kill [-s signal|-p] [--] pid...

trap [[arg] sigspec ...]

#! /bin/bash

function signal_handler {

echo "Good bye."

}

trap signal_handler 0
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: