关于trap ERR的一个bash shell set 参数之二:shopt -s extdebug

本文是之前一篇文章的后续,关于trap ERR在函数调用,命令替换,命令列表()里的应用。

等等,一个trap ERR涉及的太多,以至于经常会片面地去理解并由此产生疑惑 

 

前文提及一个朋友想将trap ERR继续到函数调用里去,并由此引出shell的-e参数(等效于shopt的errtrace)

然后另一个朋友提出了疑问,为何在()产生的子进程里,即使加了errtrace也无法继承trac ERR

 

为此重新查询了man ,bash文档,并且为此纠结了subshell与child process好长时间,

终于发现了问题答案所在:涉及到需要了解的知识点包括

1:bash shell 的trap ERR机制

2:subshell机制

3:shopt的 "errtrace" "extdebug"参数

4:bash的版本更新

等等,下边从这四点慢慢展开说明

 

首先,关于bash shell的trap ERR机制。trap本身是用于捕获信号的,

在信号列表里(kill -l ,或trap -l)里并没有ERR信号,

那么trap ERR是做什么用的,又是从什么时候开始的呢?

man bash和info bash文档里是这么描述trap ERR的:

 

If a SIGSPEC is `ERR', the command ARG is
     executed whenever a simple command has a non-zero exit status,
     subject to the following conditions.

 

联想到shell做为解释器的执行机制,再从trap做为bash的一个builtin来看,

ERR并不是传统的trap信号,而是bash shell一种特殊trap机制,

了解到这点并不能满足我们的好奇,并且带来了更多的疑惑:

 

紧接着问题便是,那trap ERR是否是bash特有的,继续查询文档:

从bash的更新文档(/usr/share/doc/bash-ver/NEWS)里可以看到这么一段:

 

the new features added to bash-2.05a since
the release of bash-2.05.

 

l.  The ksh-like `ERR' trap has been added.  The `ERR' trap will be run
    whenever the shell would have exited if the -e option were enabled.
    It is not inherited by shell functions.

 

说明,bash-2.05a正式采用了ksh的 trap ERR.这个版本的trap ERR是不具有函数继承的

 

 

但是在2.17版本bash下,man 文档与info 文档已经注意了,bash -E参数的作用为:

              -E      If  set,  any  trap  on ERR is inherited by shell functions, command substitutions, and commands
                      executed in a subshell environment.  The ERR trap is normally not inherited in such cases.

使trap ERR可继承进函数与命令替换之中,包括subshell环境下

 

再看在apue第十章<信号>里的提及:

当一个进程调用f o r k时,其子进程继承父进程的信号处理方式。

相关的进程环境资料在info bash文档的3.7.3 Command Execution Environment 一章里有提及

The shell has an EXECUTION ENVIRONMENT, which consists of the following:

  * current traps set by `trap'
并在接下来的一段中,提及subshell里的子进程在继承父进程时,对trap进行了如下的处理:

   * traps caught by the shell are reset to the values inherited from
     the shell's parent, and traps ignored by the shell are ignored

 

看来,默认的trap处理,包括trap ERR是不继承到子shell里的,-E的参数便是为了使shell不使用默认的处理方式

在bash的更新文档里也提到这么一点:

new features added to bash-3.0 since the release of bash-2.05b.

 

m.  New `functrace' and `errtrace' options to `set -o' cause DEBUG and ERR
    traps, respectively, to be inherited by shell functions.  Equivalent to
    `set -T' and `set -E' respectively.  The `functrace' option also controls
    whether or not the DEBUG trap is inherited by sourced scripts.

 

这便是上文的留言里一个朋友提到的疑惑,的确,我在bash3.1.17环境测试下,无法通过-E得到subshell环境下的trap ERR继承

 

程序如下:

trap 'echo ***trap erro*** >&2 ' ERR; trap; nocmd0 ( echo -e "/nuse ()" #subshell #出错的命令,测试trap ERR trap nocmd1 nocmd2 : ) echo -e "/nuse cmd substitude===" $(trap >&2;nocmd3; nocmd4;:); echo -e "/nuse tunnel" echo | while read line do trap; nocmd5; nocmd6; : done echo -e "/nuse fun call" sub() { trap; nocmd7; nocmd8; : } sub

 

运行结果:

[root@rac2 trap]# bash --version GNU bash, version 3.1.17(1)-release (i686-redhat-linux-gnu) Copyright (C) 2005 Free Software Foundation, Inc. [root@rac2 trap]# bash -E a.sh trap -- 'echo ***trap erro*** >&2 ' ERR a.sh: line 5: nocmd0: command not found ***trap erro*** use () trap -- 'echo ***trap erro*** >&2 ' ERR a.sh: line 12: nocmd1: command not found a.sh: line 13: nocmd2: command not found use cmd substitude=== trap -- 'echo ***trap erro*** >&2 ' ERR a.sh: line 18: nocmd3: command not found a.sh: line 18: nocmd4: command not found use tunnel trap -- 'echo ***trap erro*** >&2 ' ERR a.sh: line 24: nocmd5: command not found a.sh: line 25: nocmd6: command not found use fun call trap -- 'echo ***trap erro*** >&2 ' ERR a.sh: line 33: nocmd7: command not found ***trap erro*** a.sh: line 34: nocmd8: command not found ***trap erro*** [root@rac2 trap]#

 

结果显示,-E只对函数调用产生效果。

命令替换,(),通道等产生subshell的方式里,尽管trap显示信息已经继承进subshell

但却没有实际产生作用。

 

问题在哪里?

至此开始产生疑惑,甚至于怀疑是bash的bug?

 

于是到官网上去bug说明文档,愣是没发现相关的问题。

最后想去下载个bash4,看看新版本的是否还有这样的问题。

 

升级bash4时顺带升级了一下bash3,从3.17升级到3.2.25

 

运行一下,结局是令人迷惑和兴奋的:

[root@rac1 trap]# sh -E c.sh trap -- 'echo ***trap erro*** >&2 ' ERR c.sh: line 5: nocmd0: command not found ***trap erro*** use () trap -- 'echo ***trap erro*** >&2 ' ERR c.sh: line 12: nocmd1: command not found ***trap erro*** c.sh: line 13: nocmd2: command not found ***trap erro*** use cmd substitude=== trap -- 'echo ***trap erro*** >&2 ' ERR c.sh: line 18: nocmd3: command not found ***trap erro*** c.sh: line 18: nocmd4: command not found ***trap erro*** use tunnel trap -- 'echo ***trap erro*** >&2 ' ERR c.sh: line 24: nocmd5.0: command not found ***trap erro*** c.sh: line 25: nocmd6.0: command not found ***trap erro*** use fun call trap -- 'echo ***trap erro*** >&2 ' ERR c.sh: line 33: nocmd7: command not found ***trap erro*** c.sh: line 34: nocmd8: command not found ***trap erro*** [root@rac1 trap]#

 

这说明在bash 3.2和3.1中,肯定更改了一些关于trap ERR的机制

于是,继续查看bash文档

终于在bash3.2的更新文档(/usr/share/doc/bash-3.2/CHANGES)上找着了这么一段:

This document details the changes between this version, bash-3.2-alpha,
and the previous version, bash-3.1-release.

 

z.  The inheritence of the DEBUG, RETURN, and ERR traps is now dependent only
    on the settings of the `functrace' and `errtrace' shell options, rather
    than whether or not the shell is in debugging mode.

 

果然,在3.2之前的bash要对trap ERR进行继承,不仅需要-E参数,更需要使shell进入debuggin mode

 

啥是debugging模式呢?形式上讲,就是调用时用了--debug参数(或设置了shopt里的extdebug)使shell进入的一种模式。

 

为了验证上边这一点,我们在3.1.17上采debug模式调用脚本:

[root@rac2 trap]# bash --debugger -E a.sh trap -- 'echo ***trap erro*** >&2 ' ERR a.sh: line 5: nocmd0: command not found ***trap erro*** use () trap -- 'echo ***trap erro*** >&2 ' ERR a.sh: line 12: nocmd1: command not found ***trap erro*** a.sh: line 13: nocmd2: command not found ***trap erro*** use cmd substitude=== trap -- 'echo ***trap erro*** >&2 ' ERR a.sh: line 18: nocmd3: command not found ***trap erro*** a.sh: line 18: nocmd4: command not found ***trap erro*** use tunnel trap -- 'echo ***trap erro*** >&2 ' ERR a.sh: line 24: nocmd5: command not found ***trap erro*** a.sh: line 25: nocmd6: command not found ***trap erro*** use fun call trap -- 'echo ***trap erro*** >&2 ' ERR a.sh: line 33: nocmd7: command not found ***trap erro*** a.sh: line 34: nocmd8: command not found ***trap erro*** [root@rac2 trap]#

 

终于看到了期望的 trap erro

 

到此,答案揭晓

 

做个简单的总结:

 

1:ERR不是传统的信号,只是shell的一种处理机制(同类机制可以查看DEBUG,EXIT等trap)

2:bash从2.0bate版本开始,(参考的ksh)开始采用了trap ERR

3:一开始,bash里的trap ERR是不继承进函数的

4:-E参数是可以使bash 的trap ERR继承进函数,同样也继承进了子进程(subshell),

5:3.2版本之前的bash,虽然-E可以使subshell继承了trap ERR,但并不起作用,需要在调试模式下才能使trap ERR在subshell里起作用

6:3.2版本后,只需要-E,就可以使trap ERR继承进subshell,并起作用

 

 

 

 

你可能感兴趣的:(shell,command,bash,文档,features,debugging)