我的代码如下:
错误语句移至 fxSETprintf 调用之前,因此 kIdx 将与函数调用中的 ${kIdx} 参数编号匹配。还删除并修改了注释。功能上没有任何变化。
错误语句是第 432 行——其之前有调试语句和注释。
陷阱代码从第 466 行开始
如果代码运行时没有陷阱,它似乎可以完美运行(注意 kIdx 在循环中按预期递增)
如果你
- 将此文件保存为 demo3.sh
- 从终端窗口运行“source demo3.sh“demo3”“--test”
- 函数已加载
- demo3.sh 底部附近
- 调用“fxBASHdump “${BASH_SUBSHELL}” “${LINENO}” “${BASH_COMMAND}”
- 创建显示的输出
#!/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。