ERR trap 的返回代码为 1;为什么我找不到语句“(( kIdx++ ))”的 stderr 文本?

ERR trap 的返回代码为 1;为什么我找不到语句“(( kIdx++ ))”的 stderr 文本?

我的代码如下:

错误语句移至 fxSETprintf 调用之前,因此 kIdx 将与函数调用中的 ${kIdx} 参数编号匹配。还删除并修改了注释。功能上没有任何变化。

错误语句是第 432 行——其之前有调试语句和注释。

陷阱代码从第 466 行开始

如果代码运行时没有陷阱,它似乎可以完美运行(注意 kIdx 在循环中按预期递增)

如果你

  1. 将此文件保存为 demo3.sh
  2. 从终端窗口运行“source demo3.sh“demo3”“--test”
  3. 函数已加载
  4. demo3.sh 底部附近
  5. 调用“fxBASHdump “${BASH_SUBSHELL}” “${LINENO}” “${BASH_COMMAND}”
  6. 创建显示的输出
#!/bin/bash

###########
#
#   My coding standards for scripted code
#       1)  I tend to use tabs instead of spaces between items
#           A)  I have learned this is undesurable when cutting and pasting code into a terminal window.
#               1)  I have chosen to live with that quirk.
#           B)  I set tabs to be 4 spaces
#               1) the gnome bash terminal window appears to have fixed tab width of 8 spaces.
#                   a)  I have chosen to live with that quirk.
#       2)  I quote just about everything
#           A)  for items where substitution is not desired or not needed use single quotes (')
#           b)  for items requiring substitution use double quotes (")
#           c)  GOTCHA: the following results in a string the length of 2 containing two single quotes
#                       (using Ubuntu 20.04 on 3/15/2022 hardware RasPi 4B 8GB)
#                   local lVar="${5:-''}"
#                       the same thing with double quotes generates a set (vs unset) string length of 0
#                   local lVar="${5:-""}"
#                       so I use double quotes, in this case, that produce the desired results.
#       3)  I put braces around most, if not all, variables
#           A)  I used many array references early in my coding and was leaving them out
#               1)  including them at all times seems to have no negative effect
#       4)  when using single or double parens I tend to provide either a space or tab immediately inside both parens
#           A)  largely because I like the readability and it appears to be acceptable
#
#
#
#       A)  some statements have specific formats
#           1)  trap statements
#               a)  in order to extract bash source statements (not reported by the system based on current observation)
#                       trap\t'[statement]'\t[trapname]
#               b)  I believe "$( cut -d '\t' -f2 <<< "$( trap -p [trapname] )"
#                   1)  will return the trap source statement
#
###########
#
#   WARNING THIS CODE CONTAINS TRAPS
#       modifications to the PS4 system variable
#       and potentialy other items that can affect your system
#
#       to the best of my knowledge ending and restarting the terminal window
#           should eliminate the changes to the system.
#
#
###########


set     +o  xtrace


shopt   -s  checkhash
shopt   -s  expand_aliases
shopt   -s  extdebug

set     -o  errtrace
set     -o  functrace


vxScr="${1:-""}"        #   {name}
vxOpt="${2:-""}"        #   "--test" or ""


##########
#
#   axPS
#       output line prefixes
#
#           axPS    -   references the current line
#
#       Usage in fxOUT
#
#           if      [[  -z  "${lRc}"    ]]; then
#               lPS:-"$( axPS "${lId}" )"
#           else
#               lPS:-"$( axPS "${lId}" "${lRc}" )"
#           fi
#
#       Arguments   (see fxOUT for argument details)
#
##########

alias   axPS='printf %c:%u:' 

fxOUT()
{
    case    "$1"    in
        (-h | --help)
            fxOUT   'M'
            fxOUT   'M' ''  '###########'
            fxOUT   'M' ''  '#'
            fxOUT   'M' ''  '#  fxOUT'
            fxOUT   'M' ''  '#'
            fxOUT   'M' ''  '#      ex: fxOUT   [Id]    {Rc}    {Text}'
            fxOUT   'M' ''  '#'
            fxOUT   'M' ''  '#      Arguments'
            fxOUT   'M' ''  '#'
            fxOUT   'M' ''  '#          Id      With Rc values  (see fxRcID --help)'
            fxOUT   'M' ''  '#                      E   -   error       Flg=7'
            fxOUT   'M' ''  '#                      W   -   warning     Flg-7'
            fxOUT   'M' ''  '#                      0   -   Rc=0        Flg=4'
            fxOUT   'M' ''  '#                      R   -   fxTrapERR   Flg=4'
            fxOUT   'M' ''  '#                  Without Rc values'
            fxOUT   'M' ''  '#                      M   - manual        Flg=3'
            fxOUT   'M' ''  '#                      D   - stdout        Flg=3'
            fxOUT   'M' ''  '#                      ?   - read/select   Flg=3'
            fxOUT   'M' ''  '#                      d   - debug display Flg={2 4 6}'
            fxOUT   'M' ''  '#                      T   - trap          Flg=4'
            fxOUT   'M' ''  '#                      X   - BASH_COMMAND  Flg=4'
            fxOUT   'M' ''  '#                      x   - xtrace        Flg=4'
            fxOUT   'M' ''  '#'
            fxOUT   'M' ''  '#          Rc      -   BASH Return/Exit Codes'
            fxOUT   'M' ''  '#              NOTE: A webpage identified the probable known system range'
            fxOUT   'M' ''  '#                      system codes        1-63'
            fxOUT   'M' ''  '#                      user error tbd      64-79'
            fxOUT   'M' ''  '#                      user error codes    80-87'
            fxOUT   'M' ''  '#                      fxTrapDEBUG (skip)  88'
            fxOUT   'M' ''  '#                      user warning codes  89-96'
            fxOUT   'M' ''  '#                      user warning tbd    97-113'
            fxOUT   'M' ''  '#                      system codes        114-255'
            fxOUT   'M' ''  '#'
            fxOUT   'M' ''  '#          Text    -   Text to display'
            fxOUT   'M' ''  '#                          cannot contain escaped characters'
            fxOUT   'M' ''  '#                          fxOUT without text prints blank line'
            fxOUT   'M' ''  '#                          use actual tab instead of '\''\t'
            fxOUT   'M' ''  '#'
            fxOUT   'M' ''  '###########'
            fxOUT   'M'
            ;;

        (*)
            local   lId="${1:-""}"
            local   lRc="${2:-""}"
            local   lText="${3:-""}"

            local   lPS=''

            if      [[  -z  "${lRc}"    ]]; then
                lPS="$( axPS "${lId}" )"
            else
                lPS="$( axPS "${lId}" "${lRc}" )"
            fi

            printf      '%s\t%s\n'  "${lPS}"    "${lText}"
            ;;
    esac

    return  '0'
}


##########
#
#   fxSETprintf
#
##########

fxSETprintf()
{
    case    "$1"    in
        (-h | --help)
            fxOUT   'M'
            fxOUT   'M' ''  '###########'
            fxOUT   'M' ''  '#'
            fxOUT   'M' ''  '#  fxSETprintf'
            fxOUT   'M' ''  '#      Displays the set status and value of the reference variable'
            fxOUT   'M' ''  '#'
            fxOUT   'M' ''  '#          fxSET[printf    [VarName] [RefName] [AdjName]'
            fxOUT   'M' ''  '#'
            fxOUT   'M' ''  '#      Arguments'
            fxOUT   'M' ''  '#'
            fxOUT   'M' ''  '#          VarName -   display name for variable'
            fxOUT   'M' ''  '#                      (max 20 char)'
            fxOUT   'M' ''  '#'
            fxOUT   'M' ''  '#          RefName -   actual name for variable'
            fxOUT   'M' ''  '#                      (max 20 char)'
            fxOUT   'M' ''  '#                      ex: '\''FUNCNAME[0]'\'''
            fxOUT   'M' ''  '#'
            fxOUT   'M' ''  '#          AdjName -   adjusted name for variable'
            fxOUT   'M' ''  '#                          The adjustment is for the extra level or three arguments'
            fxOUT   'M' ''  '#                              created by this function call when printing the BASH variables'
            fxOUT   'M' ''  '#'
            fxOUT   'M' ''  '###########'
            fxOUT   'M'
            ;;

        (*)
            local   lVarName="${1:-""}"     #   display name of variable
            local   lRefName="${2:-""}"     #   reference name of variable
            local   lAdjName="${3:-""}"     #   adjusted name for  variable

            local   lSet=''

            #
            #           explanation testing for an unset variable requires two steps
            #       Step 1      [[ -x '${var}" ]]
            #                       True    is empty string (set) and unset (not initialized)
            #                       False   is set the string contains characters
            #
            #       Step 2          after step one we only have zero length items
            #                           the dash (-) above says
            #                               to set an unset variable with what follows (_)
            #                   [[ -n "${var-_}" ]]
            #                       True    is an unset variable it contains '_' length 1
            #                       False   is a set variable with a zero length string ""
            #
            #       GOTCHA
            #           coding the test as follows yields an ALWAYS set variable
            #   v="${FUNCNAME[0]}"
            #   if [[ -z "${v}" && -n "${v-_}" ]]; then
            #
            #       The following works for a hard coded variable
            #   if [[ -z "${FUNCNAME[0]}" && -n "${FUNCNAME[0]-_}" ]]; then
            #
            #       or
            #
            #       The code below works if lAdjName is set as follows
            #           NOTE:   no dollar sign ($) or braces {}
            #   lAdjName='FUNCNAME[0]'
            #

            if [[ -z "${!lAdjName}" && -n "${!lAdjName-_}" ]]; then
                lSet='unset'
            else
                lSet='set'
            fi

            local   lText=''
            lText="$( printf '%-20s%-8s%s=%s' "${lVarName}" "${lSet}" "${lRefName}" "${!lAdjName}" )"


            fxOUT   'd' ''  "${lText}"
            ;;
    esac

    return  "0"
}


##########
#
#   fxBASHdump
#
##########

fxBASHdump ()
{
    case    "$1"    in
        (-h | --help)
            fxOUT   'M'
            fxOUT   'M' ''  '###########'
            fxOUT   'M' ''  '#'
            fxOUT   'M' ''  '#  fxBASHdump'
            fxOUT   'M' ''  '#      Dumps the  BASH Execution Stack'
            fxOUT   'M' ''  '#'
            fxOUT   'M' ''  '#      fxBASHdump  "${BASH_SUBSHELL}"  "${LINENO}" "${BASH_COMMAND}"'
            fxOUT   'M' ''  '#'
            fxOUT   'M' ''  '#                  "${BASH_SUBSHELL}"  - the subshell level number'
            fxOUT   'M' ''  '#                                            0 is main shell'
            fxOUT   'M' ''  '#                                          > 0 is sub shell'
            fxOUT   'M' ''  '#'
            fxOUT   'M' ''  '#                  "${LINENO}"         - in this case the line number'
            fxOUT   'M' ''  '#                                          from the console (terminal command line)'
            fxOUT   'M' ''  '#                                              or'
            fxOUT   'M' ''  '#                                          source code'
            fxOUT   'M' ''  '#'
            fxOUT   'M' ''  '#                  "${BASH_SUBSHELL}"  - the bash command'
            fxOUT   'M' ''  '#                                          in this case the call to fxBASHdump'
            fxOUT   'M' ''  '#'
            fxOUT   'M' ''  '###########'
            fxOUT   'M'
            ;;

        (*)
            local   lSub="${1:-"${BASH_SUBSHELL}"}"
            local   lLNo="${2:-"${LINENO}"}"
            local   lCmd="${3:-"${BASH_COMMAND}"}"

            local   l='0'
            local   lMax="${#BASH_ARGC[@]}"

            local   k='0'
            local   kIdx='0'
            local   kRef='0'
            local   kAdj='0'
            local   kCum='0'


            fxOUT       'd'
            fxOUT       'd' ''  '#      The first three variables point to an instruction in fxSETprintf'
            fxOUT       'd' ''  '#          if used directly in the function.'
            fxOUT       'd' ''  '#          This was both expected and undesired.'
            fxOUT       'd'

            fxSETprintf 'BASH_SUBSHELL' 'BASH_SUBSHELL' 'BASH_SUBSHELL'
            fxSETprintf 'LINENO'        'LINENO'        'LINENO'
            fxSETprintf "BASH_COMMAND"  "BASH_COMMAND"  'BASH_COMMAND'

            fxOUT       'd'
            fxOUT       'd' ''  '#  The following three items were passed as arguments to preserve their state'
            fxOUT       'd' ''  '#      when tested with all traps disabled'
            fxOUT       'd'
            fxOUT       'd' ''  '#          fxBASHdump'
            fxOUT       'd' ''  '#              allowing the values to default inside the function'
            fxOUT       'd' ''  '#              also yields expected and undesired results'
            fxOUT       'd' ''  '#                  where LINENO points to one command in fxBASHdump'
            fxOUT       'd' ''  '#                  where BASH_COMMAND references the following command'
            fxOUT       'd'
            fxOUT       'd' ''  '#          fxBASHdump "${BASH_SUBSHELL}" "${LINENO}" "${BASH_COMMAND}"'
            fxOUT       'd' ''  '#              The results reflect the fxBASHdump command, the desired result'
            fxOUT       'd'

            fxOUT       'd'
            fxOUT       'd' ''  '#  Based on the next two commands I believe'
            fxOUT       'd' ''  '#      if BASH_COMMAND is passed as lSub; it returns'
            fxOUT       'd' ''  '#          the valid subshell for the fxBASHdump command.'
            fxOUT       'd'

            fxSETprintf 'BASH_SUBSHELL' 'BASH_SUBSHELL' 'lSub'

            fxOUT       'd'
            fxOUT       'd' ''  '#  This is the LINENO'
            fxOUT       'd' ''  '#      If LINENO is passed as lLNo; it returns'
            fxOUT       'd' ''  '#          the console line number'
            fxOUT       'd' ''  '#              of the fxBASHdump command, as desired'
            fxOUT       'd'

            fxSETprintf 'LINENO'        'LINENO'        'lLNo'

            fxOUT       'd'
            fxOUT       'd' ''  '#  This is the source command (statement)'
            fxOUT       'd' ''  '#      If BASH_COMMAND is passed as lCmd; it returns '
            fxOUT       'd' ''  '#          the fxBASHdump command, as desired'
            fxOUT       'd'

            fxSETprintf "BASH_COMMAND"  "BASH_COMMAND"  'lCmd'

            fxOUT       'd'
            fxOUT       'd' ''  '#  This is the name of the script interpreter'
            fxOUT       'd'

            fxSETprintf "BASH_ARGV0"    "BASH_ARGV0d"   "BASH_ARGV0"

            fxOUT       'd'
            fxOUT       'd' ''  '##########'
            fxOUT       'd' ''  '#  The following items are a backtrace of functions, scripts, and commands'
            fxOUT       'd' ''  '##########'
            fxOUT       'd'

            for ((l=0; l<lMax; l++))
            do
                case    "$l"    in
                    (0)
                        fxOUT   'd'
                        fxOUT   'd' ''  '#  This entry is for fxBASHdump \(the function printing this\).'
                        fxOUT   'd' ''  '#      BASH_LINENO[0] is the LINENO of the call to fXtrapBASH.'
                        fxOUT   'd' ''  '#      That line number is found in BASH_SOURCE[1] \(see below\).'
                        fxOUT   'd'

                        ;;

                    ( $(( lMax - 2)) )
                        fxOUT   'd'
                        fxOUT   'd' ''  '#  This is probably the command line entry that started this execution.'
                        fxOUT   'd' ''  '#      BASH_LINENO['"$(( lMax - 2))"'] is the LINENO of the initial command.'
                        fxOUT   'd' ''  '#      The unset entry in BASH_SOURCE['"$(( lMax - 1))"'] \(see below\).'
                        fxOUT   'd' ''  '#          I believe indicates a console command.'
                        fxOUT   'd'
                        ;;

                    ( $(( lMax - 1)) )
                        fxOUT   'd'
                        fxOUT   'd' ''  '#  This is probably an entry for an idle BASH interpreter.'
                        fxOUT   'd'
                        ;;

                    (*)
                        fxOUT   'd'
                        fxOUT   'd' ''  '#  This entry represents the parent call that created the'
                        fxOUT   'd' ''  '#      previously printed level.'
                        fxOUT   'd'
                        ;;
                esac

                fxOUT   'd'

                local   lAdj="$(( l + 1 ))"     # offset for the one level added by fxSETprintf function call

                fxSETprintf "BASH_SOURCE[${l}]" "BASH_SOURCE[${l}]" "BASH_SOURCE[${lAdj}]"

                fxSETprintf "FUNCNAME[${l}]"    "FUNCNAME[${l}]"    "FUNCNAME[${lAdj}]"

                fxSETprintf "BASH_LINENO[${l}]" "BASH_LINENO[${l}]" "BASH_LINENO[${lAdj}]"

                fxSETprintf "BASH_ARGC[${l}]"   "BASH_ARGC[${l}]"   "BASH_ARGC[${lAdj}]"

                    #   Notice below that BASH_ARGV is a single array for all execution levels.
                    #       the parameters are stored in decending order in BASH_ARGV
                    #       this code reverses that for display purposes
                    #       the ref=name printed shows the physical location in the BASH_ARGV
                k="${BASH_ARGC[$l]}"
                kIdx='0'

                if      [[  "${k}"  -gt 0   ]]; then
                    fxOUT   'd'
                    fxOUT   'd' ''  '#  The location in BASH_ARGV is shown in ref={name}  \(see below\)'
                    fxOUT   'd' ''
                    fxOUT   'd' ''  '#  I know bash arrays cannot have two indexes'
                    fxOUT   'd' ''  '#      but logically reflects the situation'
                    fxOUT   'd'
                    fxOUT   'd' ''  '#      Notice how the ref index continue to increment '
                    fxOUT   'd' ''  '#          as the levels are displayed'
                    fxOUT   'd'
                fi

                while   [ "${k}" -gt 0  ]
                do
                    (( k-- ))

                        #  see above 
                        #   line 283    local kIdx='0'    (also tried as "0" - no difference)
                        #   line 402    kIdx='0'          (also tried as "0" - no difference)
                        # the following two lines were added for debug purposes -- not intended to be in the final
                        #
                        # kIdx seems to be messed up for the first pass =0 however it increments properly
                        #       without a ERR trap this code would appear to function correctly.
                    fxSETprintf "kIdx"                      "kIdx"                  "kIdx"
                    echo "kIdx=\"${kIdx}\""

                        #   I added the 2>$1 in the testing process to try to force syserr to display
                        #       there appears to be no syserr message.
                    (( kIdx++ )) 2>&1

                    kRef="$(( kCum + k ))"
                    kAdj="$(( kRef + 3 ))"   # 3 arguments to fxSETprintf

                    fxSETprintf "BASH_ARGV[${l} ${kIdx}]"   "BASH_ARGV[${kRef}]"    "BASH_ARGV[${kAdj}]"

                done
                kCum=$(( kCum + ${BASH_ARGC[${l}]} ))
            done

            fxOUT   'd'
            ;;
    esac

    return '0'

}

export  -f  fxOUT
export  -f  fxSETprintf
export  -f  fxBASHdump


#############################################################################################################################################


##########
#
#   Initialize Trap functions
#
##########


fxTrapERR()
{
    local   lTrap='ERR'
            #   the following timestamp is generated in fxOUT for the print lines
            #       uncomment of required for the trap itself
    ### local   lTS=''                                      #   timestamp of trap initiation
    ### lTS="$( date -u '+%H%M%S%03N' )"                    #   {timestamp}
    local   lLvl="${1:-"0"}"                            #   "${#BASH_ARGC[@]}"  {current command execution level}
    local   lSub="${2:-"0"}"                            #   "${BASH_SUBSHELL}"  {current subshell level}
    local   lSrc="${3:-""}"                             #   "${BASH_SOURCE[0]}" {script that contains the source}
    local   lSNm=''                                     #   {scriptname}
    lSNm="$( basename "$lSrc" '.sh' )"                  #   {filename portion of "${BASH_SOURCE[0]}"}
    local   lFNm="${4:-""}"                             #   "${FUNCNAME[0]}"    {function name, if in function}
    ### local   lRcLNo="${vxLNo}"                           #   "${LINENO}"         {previous, may not need}
    local   lLNo="${5:-"0"}"                            #   "${LINENO}"         {current line number}
    local   lCmd="${6:-""}"                             #   "${BASH_COMMAND}"   {current source command}
        #   BASH_LINENO may only be used to verify the parent
    local   lBLN="${7:-"0"}"                            #   "${BASH_LINENO[0]}" {line number of parent script/function/command}
        #   the return code of the current or prior command depending on the trap initiated
    local   lRc="${8:-"0"}"                             #   "$?"

    fxOUT   'E' "${lRc}"    "Trap=\"${lTrap}\" Lvl=\"${lLvl}\" Sub=\"${lSub}\" Src=\"${lSrc}\" SNm=\"${lSNm}\" FNm=\"${lFNm}\" LNo=\"${lLNo}\""  # BLN=\"${lBLN"}\""
    fxOUT   'E' "${lRc}"    "Cmd=\"${lCmd}\""

    read -rp 'pause'

    return  '0'
}

##########
#
#   Enable Trap functions
#
##########


trap    'fxTrapERR    "${#BASH_ARGC[@]}" "${BASH_SUBSHELL}" "${BASH_SOURCE[0]}" "${FUNCNAME[0]}" "${LINENO}" "${BASH_COMMAND}" "${BASH_LINENO[0]}" "$?"'    ERR


export  PS4='x:     '

### set     -o  xtrace


if      [[  "${vxOpt}"  ==  '--test'    ]]; then
     fxBASHdump "${BASH_SUBSHELL}" "${LINENO}" "${BASH_COMMAND}"
fi

return  '0'


显示问题的第一部分输出是:在此部分中,粗体/斜体代码是调试输出和 ERR 陷阱输出。kIdx 正确递增并在非调试/陷阱行中正确显示。所有证据表明 (( kIdx++ )) 语句创建了预期的输出,没有问题。为什么我在这里捕获错误?

d:0:
d:0:    BASH_SOURCE[0]      set     BASH_SOURCE[0]=demo3.sh
d:0:    FUNCNAME[0]         set     FUNCNAME[0]=fxBASHdump
d:0:    BASH_LINENO[0]      set     BASH_LINENO[0]=511
d:0:    BASH_ARGC[0]        set     BASH_ARGC[0]=3
d:0:
d:0:    #       The location in BASH_ARGV is shown in ref={name}  \(see below\)
d:0:
d:0:    #       I know bash arrays cannot have two indexes
d:0:    #               but logically reflects the situation
d:0:
d:0:    #               Notice how the ref index continue to increment 
d:0:    #                       as the levels are displayed
d:0:
***d:0:    kIdx                set     kIdx=0
kIdx="0"
E:1:    Trap="ERR" Lvl="3" Sub="0" Src="demo3.sh" SNm="demo3" FNm="fxBASHdump" LNo="432"
E:1:    Cmd="(( kIdx++ ))"
pause***
d:0:    BASH_ARGV[0 1]      set     BASH_ARGV[2]=0
***d:0:    kIdx                set     kIdx=1
kIdx="1"***
d:0:    BASH_ARGV[0 2]      set     BASH_ARGV[1]=511
***d:0:    kIdx                set     kIdx=2
kIdx="2"***
d:0:    BASH_ARGV[0 3]      set     BASH_ARGV[0]=fxBASHdump "${BASH_SUBSHELL}" "${LINENO}" "${BASH_COMMAND}"
d:0:

完整输出如下:

ubuntu@ubuntu:/pool/src/trap/scr/old$ source demo3.sh demo --test
d:0:
d:0:    #               The first three variables point to an instruction in fxSETprintf
d:0:    #                       if used directly in the function.
d:0:    #                       This was both expected and undesired.
d:0:
d:0:    BASH_SUBSHELL       set     BASH_SUBSHELL=1
d:0:    LINENO              set     LINENO=229
d:0:    BASH_COMMAND        set     BASH_COMMAND=printf '%-20s%-8s%s=%s' "${lVarName}" "${lSet}" "${lRefName}" "${!lAdjName}"
d:0:
d:0:    #       The following three items were passed as arguments to preserve their state
d:0:    #               when tested with all traps disabled
d:0:
d:0:    #                       fxBASHdump
d:0:    #                               allowing the values to default inside the function
d:0:    #                               also yields expected and undesired results
d:0:    #                                       where LINENO points to one command in fxBASHdump
d:0:    #                                       where BASH_COMMAND references the following command
d:0:
d:0:    #                       fxBASHdump "${BASH_SUBSHELL}" "${LINENO}" "${BASH_COMMAND}"
d:0:    #                               The results reflect the fxBASHdump command, the desired result
d:0:
d:0:
d:0:    #       Based on the next two commands I believe
d:0:    #               if BASH_COMMAND is passed as lSub; it returns
d:0:    #                       the valid subshell for the fxBASHdump command.
d:0:
d:0:    BASH_SUBSHELL       set     BASH_SUBSHELL=0
d:0:
d:0:    #       This is the LINENO
d:0:    #               If LINENO is passed as lLNo; it returns
d:0:    #                       the console line number
d:0:    #                               of the fxBASHdump command, as desired
d:0:
d:0:    LINENO              set     LINENO=511
d:0:
d:0:    #       This is the source command (statement)
d:0:    #               If BASH_COMMAND is passed as lCmd; it returns 
d:0:    #                       the fxBASHdump command, as desired
d:0:
d:0:    BASH_COMMAND        set     BASH_COMMAND=fxBASHdump "${BASH_SUBSHELL}" "${LINENO}" "${BASH_COMMAND}"
d:0:
d:0:    #       This is the name of the script interpreter
d:0:
d:0:    BASH_ARGV0          set     BASH_ARGV0d=/usr/bin/bash
d:0:
d:0:    ##########
d:0:    #       The following items are a backtrace of functions, scripts, and commands
d:0:    ##########
d:0:
d:0:
d:0:    #       This entry is for fxBASHdump \(the function printing this\).
d:0:    #               BASH_LINENO[0] is the LINENO of the call to fXtrapBASH.
d:0:    #               That line number is found in BASH_SOURCE[1] \(see below\).
d:0:
d:0:
d:0:    BASH_SOURCE[0]      set     BASH_SOURCE[0]=demo3.sh
d:0:    FUNCNAME[0]         set     FUNCNAME[0]=fxBASHdump
d:0:    BASH_LINENO[0]      set     BASH_LINENO[0]=511
d:0:    BASH_ARGC[0]        set     BASH_ARGC[0]=3
d:0:
d:0:    #       The location in BASH_ARGV is shown in ref={name}  \(see below\)
d:0:
d:0:    #       I know bash arrays cannot have two indexes
d:0:    #               but logically reflects the situation
d:0:
d:0:    #               Notice how the ref index continue to increment 
d:0:    #                       as the levels are displayed
d:0:
d:0:    kIdx                set     kIdx=0
kIdx="0"
E:1:    Trap="ERR" Lvl="3" Sub="0" Src="demo3.sh" SNm="demo3" FNm="fxBASHdump" LNo="432"
E:1:    Cmd="(( kIdx++ ))"
pause
d:0:    BASH_ARGV[0 1]      set     BASH_ARGV[2]=0
d:0:    kIdx                set     kIdx=1
kIdx="1"
d:0:    BASH_ARGV[0 2]      set     BASH_ARGV[1]=511
d:0:    kIdx                set     kIdx=2
kIdx="2"
d:0:    BASH_ARGV[0 3]      set     BASH_ARGV[0]=fxBASHdump "${BASH_SUBSHELL}" "${LINENO}" "${BASH_COMMAND}"
d:0:
d:0:    #       This is probably the command line entry that started this execution.
d:0:    #               BASH_LINENO[1] is the LINENO of the initial command.
d:0:    #               The unset entry in BASH_SOURCE[2] \(see below\).
d:0:    #                       I believe indicates a console command.
d:0:
d:0:
d:0:    BASH_SOURCE[1]      set     BASH_SOURCE[1]=demo3.sh
d:0:    FUNCNAME[1]         set     FUNCNAME[1]=source
d:0:    BASH_LINENO[1]      set     BASH_LINENO[1]=6
d:0:    BASH_ARGC[1]        set     BASH_ARGC[1]=2
d:0:
d:0:    #       The location in BASH_ARGV is shown in ref={name}  \(see below\)
d:0:
d:0:    #       I know bash arrays cannot have two indexes
d:0:    #               but logically reflects the situation
d:0:
d:0:    #               Notice how the ref index continue to increment 
d:0:    #                       as the levels are displayed
d:0:
d:0:    kIdx                set     kIdx=0
kIdx="0"
E:1:    Trap="ERR" Lvl="3" Sub="0" Src="demo3.sh" SNm="demo3" FNm="fxBASHdump" LNo="432"
E:1:    Cmd="(( kIdx++ ))"
pause
d:0:    BASH_ARGV[1 1]      set     BASH_ARGV[4]=demo
d:0:    kIdx                set     kIdx=1
kIdx="1"
d:0:    BASH_ARGV[1 2]      set     BASH_ARGV[3]=--test
d:0:
d:0:    #       This is probably an entry for an idle BASH interpreter.
d:0:
d:0:
d:0:    BASH_SOURCE[2]      unset   BASH_SOURCE[2]=
d:0:    FUNCNAME[2]         unset   FUNCNAME[2]=
d:0:    BASH_LINENO[2]      unset   BASH_LINENO[2]=
d:0:    BASH_ARGC[2]        set     BASH_ARGC[2]=0
d:0:
ubuntu@ubuntu:/pool/src/trap/scr/old$ 

答案1

“错误”只是一种非零返回状态。它并不总是错误。

man bash

((expression))

表达式的求值依据下文算术求值中描述的规则。如果表达式的值非零,则返回状态为 0;否则返回状态为 1。这与 let "expression" 完全等同。

(( 0 ))返回状态为 1,表示“错误”,因此等于 0 的变量将触发陷阱ERR

该命令false总是执行相同的操作。

(( 0 )) || true||意义或者),或者更短的形式(( 0 )) ||: 会抑制“错误”。

答案2

经过多次反复试验,我发现该(( kIdx-- ))语句似乎是导致错误的间歇性原因。它在主脚本中有效,但在陷阱中选择性失败。用kIdx="$(( kIdx - 1 ))"陷阱中的指令替换指令消除了 ERR 陷阱在第一个循环的第一遍中指向指令的情况。如果您遇到此问题,这似乎是一个成功的解决方法。在此过程中,我多次重写了此代码。在当前版本中,此版本的 Kidx 被替换为 k;但该解决方法解决了该问题。

原始语句的错误具有间歇性,即当如上所述表达式的测试值为零时,会生成返回代码 1。

相关内容