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

bash参考手册之三(基本的Shell特性)续九

2013-02-04 17:03 267 查看
3.7 执行命令

•简单命令扩展:bash如何在执行前扩展简单命令。

•命令搜索和执行:bash如何找到命令和运行。

•命令执行环境:bash执行非shell内建命令的环境。

•环境:命令的环境。

•退出状态:命令返回的状态以及bash如何解释它。

•信号:bash或运行的命令接收到信号时,会发生什么。

 

3.7.1 简单命令扩展

当一个简单命令执行时,shell由左到右执行以下的扩展,赋值和重定向。

1.那些已经被解析器标记为变量赋值(位于命令前面)和重定向的单词,被保存供以后处理。

2.那些不是变量赋值或重定向的单词被扩展(Shell扩展)。如果扩展的结果包含单词的话,第一个单词是命令的名称,余下的是参数。

3.如上所述,执行重定向(见重定向)。

4.对于每个变量赋值,先对'='后的文本进行波浪线扩展,参数扩展,命令替换,算术扩展和引号移除,然后再赋值给变量。

如果扩展结果中没有命令名,变量赋值影响当前的shell环境。否则,这些变量被添加到该命令的环境,不影响当前的shell环境。如果尝试赋值到一个只读变量,会发生错误,并且命令退出时返回一个非零的状态。

如果扩展结果中没有命令名,则执行重定向,但不影响当前的shell环境。重定向错误将导致该命令退出,并返回一个非零的状态。

如果扩展结果中有一个命令名,按下述进行命令的执行。否则,该命令将退出。如果扩展中包含了一个命令替换,命令的退出状态是最后执行的命令替换的退出状态。如果没有命令替换,命令退出状态为0。

 

3.7.2 命令搜索和执行

在命令已经分解成单词后,如果结果是一个简单的命令和一个可选的参数列表,将采取如下动作。

1.如果命令名称中没有包含斜杠,shell试图定位该命令。如果存在同名的shell函数,该函数被调用(见shell函数)。

2.如果名称和函数不匹配,shell在内建命令列表中搜索。如果找到一个匹配项,则该内建命令被调用。

3.如果名字既不是shell函数,也不是内建命令,并且命令名字不包含斜线,bash搜索$PATH中的每一个成员,试图寻找包含该名称的可执行文件的目录。 bash使用一个哈希表来记住可执行文件的全路径名,以避免重复的PATH搜索(见Bourne shell的内建命令中hash的描述)。只有当命令在哈希表中没有找到时,才对$PATH中的目录进行完整的搜索。如果搜索不成功,shell试图搜索一个预定义的shell函数command_not_found_handle。如果该函数存在,它被最初的命令调用,最初的命令的参数作为它的参数,函数的退出状态成为shell的退出状态。如果该函数没有被定义,shell输出错误消息并返回一个退出状态127。

4.如果搜索是成功的,或如果该命令名中包含一个或多个斜杠,shell将在单独的执行环境中执行指定的程序。参数0被设置为给定的名称,该命令的其余参数(如果有的话),被设置为该程序支持的参数。

5.如果因为文件不是可执行格式而执行失败,并且该文件不是一个目录,则它被认为是一个shell脚本,shell将执行它(见shell脚本)。

6.如果该命令不是异步命令,shell等待命令完成并收集它的退出状态。

 

3.7.3 命令执行环境

shell的执行环境,由以下部分组成:

·在调用时,打开的文件被shell继承,同时,被exec内建命令提供的重定向修改

·当前工作目录被cd,pushd或者popd设置,或在调用时被shell继承

·文件创建模式掩码由umask设置,或继承自这个shell的父shell

·当前的陷阱由trap设置

·shell参数被变量赋值,或者set命令设置,或者继承自父shell

·shell函数在执行被定义,或者继承自所在环境中的父shell

·在调用时(通过缺省值,或者命令行参数)被启用,或通过set启用的选项

·shopt启用的选项(见内建命令shopt)

·通过alias定义的别名(见别名)

·不同的进程ID,包括后台作业(见列表),$$的值,$PPID的值

当执行一个简单命令,而不是内建命令或者shell函数时,它将在一个单独的执行环境中被调用,该环境由下面这些组成。除非另有说明,否则,值将继承自shell。

·shell打开的文件,以及通过重定向传给命令的修改和附加的内容

·当前的工作目录

·文件创建模式掩码

·被标记为导出的shell变量和函数,以及为命令导出的变量,和在环境中传递的变量(见环境)

·被shell捕获的陷阱,被重新设置成继承自父shell的值,被shell忽略的陷阱将被忽略

在独立的环境中调用的命令,不会影响shell的执行环境。

命令替换,通过括号分组的命令,在子shell环境中调用的异步命令,其环境是shell环境的复制品,除了shell捕获的陷阱在调用时,被重设为继承自父shell的值。作为管道的一部分而被调用的内置命令,也是在一个子shell环境中执行的。在子shell环境中所做的更改不会影响shell的执行环境。
子shell在执行命令替换时,继承父shell的-e选项的值。在非POSIX模式时,bash清除该子shell中的-e选项。

如果命令的结尾是一个'&',并且作业控制未激活时,该命令的默认标准输入是空文件/dev/null。否则,被调用的命令继承调用它的shell的文件描述符。

3.7.4 环境

当一个程序被调用时,它被赋予一个字符串数组,这个数组称为环境。这是一个名-值对列表,形式为name=value。

Bash提供了几种方法来操作环境。在调用时,shell扫描自己的环境,并为每个找到的名字创建一个参数,自动将其标记为导出到子进程。被执行的命令继承该环境。export 和'declare -x'命令允许在环境中,增加和删除参数和函数。如果该环境中的某个参数值被修改,则新的值取代旧的成为环境的一部分。任何被执行的命令继承的环境中,包括shell的初始环境,其值可能在shell中被修改:通过unset和‘export -n’命令移除,通过export和‘declare
-x’增加。

对于任何简单命令或函数的环境,可能会通过前缀参数赋值,被临时参数化。见shell参数中的描述。这些赋值语句只影响该命令所能看到的环境。

如果-k选项被设置(参见内建命令set),那么,对于命令来说,所有的参数赋值被置于环境中,而不仅仅位于命令名前。

当bash调用外部命令时,变量‘$ _'被设置为命令的完整路径名,并被传递到该命令的环境中。

 

3.7.5 退出状态

被执行命令的退出状态,是通过waitpid系统调用返回的值或等效的函数的返回值。退出状态介于0和255之间,但是,正如下文所述,shell专门使用大于125的值。来自shell的内建命令和复合命令的退出状态,也被限于这个范围内。在某些情况下,shell将使用特殊的值来表示特定的故障模式。

对shell来说,返回状态为0的命令意味着成功。而一个非零的退出状态表示失败。使用这种看起来似乎是反直觉的模式,导致以一个良好定义的方式来表示成功,以多种方式来指示各种故障的模式。当一个命令因一个致命信号N而终止时,bash使用值128+ N作为退出状态。

如果未找到命令,被创建以执行它的子进程返回状态127。如果命令被找到,但不是可执行文件,返回状态是126。

如果一个命令在扩展或重定向时失败,则退出状态大于零。

退出状态可以用于bash的条件命令(请参阅条件结构)和一些列表结构(见列表)。

所有的Bash内建命令,如果他们成功则返回退出状态零,失败则非零,所以可用于条件和列表结构。所有的内建命令返回退出状态为2,以表示用法不正确。

3.7.6 信号

当Bash在交互状态时,没有任何陷阱,它忽略SIGTERM(这样“kill 0”不杀交互式shell),SIGINT被捕获并处理(这样内建命令wait可中断)。当Bash收到一个SIGINT信号,它跳出任何正在执行的循环。在所有情况下,Bash会忽略SIGQUIT。如果作业控制有效(见作业控制),Bash会忽略SIGTTIN,SIGTTOU,SIGTSTP。

Bash启动的非内建命令,信号处理操作被设置成从其父shell继承的值。当作业控制无效时,异步命令忽略SIGINT和SIGQUIT,除非他们继承了操作。命令替换的结果中的命令,忽略键盘产生的作业控制信号SIGTTIN,SIGTTOU,和SIGTSTP。

默认情况下,在收到一个SIGHUP时,shell退出。在退出之前,一个交互式shell重新发送SIGHUP到所有作业——运行或停止状态。停止的作业,发送SIGCONT以确保他们收到SIGHUP。为了防止shell发送SIGHUP信号到一个特定的作业,应使用内建命令disown(见作业控制内建命令)把该作业从作业表中删除,或使用disown -h标记为不接收SIGHUP。

如果shell选项huponexit已被设置命令shopt(见内建命令shopt)设置,Bash会在一个交互登录shell退出时,发送一个SIGHUP到所有作业。

如果bash正在等待一个命令的完成,并且收到陷阱被设置的信号,陷阱将在命令完成后执行。当Bash正在通过wait内建命令等待异步命令时,收到陷阱已设置的信号,会导致内置命令wait立即返回,并且退出状态大于128,其后立即执行陷阱。

 

3.8  Shell脚本

shell脚本是一个文本文件,其中包含shell命令。当调用bash时,把这样的文件用作第一个非选项参数时,并且没有指定-c或-s选项(见调用Bash),则Bash读取和执行文件中的命令,然后退出。这种操作模式,创建了一个非交互的shell。 shell首先在当前目录中搜索该文件,如果没有找到,会在$PATH中的目录搜索。

当bash运行一个shell脚本,它设置特殊参数0为文件名,而不是shell的名称,位置参数设置为剩余的参数,如果有的话。如果没有提供额外的参数,位置参数则是未设定状态。

可以使用chmod命令来打开执行位,以使一个shell脚本变成可执行文件。当Bash在$PATH中搜索命令时,找到这样的文件时,它会产生一个子shell来执行它。换句话说,执行

filename arguments

相当于执行

bash filename arguments

如果filename 是可执行的shell脚本。子shell重新初始化它自己,达到这样的效果:就像一个新的shell被调用来解释该脚本,除了由父shell记录的(见Bourne shell的内建命令中hash的描述)命令的位置,由子shell保持。

大多数的Unix版本,把这作为操作系统命令执行机制的一部分。如果脚本的第一行开始的两个字符是'#!',这就是表示该行是指定程序的解释器。因此,您可以指定bash,awk,Perl或一些其他的解释器,并使用该语言编写脚本文件的其余部分。

在脚本文件的第一行,解释器的参数包括一个跟在解释器后的可选的参数,后面是脚本文件的名称,然后是其余的参数。 Bash在操作系统上将不处理它自己。需要注意的是,一些老版本的Unix的解释器名称和参数被限制到最多32个字符。

Bash脚本通常以 #!/bin/bash(假设bash已经安装在/bin),因为这样能确保Bash将被用来解释脚本,哪怕是另一个shell下执行该脚本。

原文链接:http://www.gnu.org/software/bash/manual/bash.html#Executing-Commands
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: