BASH   35

lib trap sh

Guest on 13th May 2022 01:54:14 AM

  1. lib_name='trap'
  2. lib_version=20121026
  3.  
  4. stderr_log="/dev/shm/stderr.log"
  5.  
  6. #
  7. # TO BE SOURCED ONLY ONCE:
  8. #
  9. ###~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~##
  10.  
  11. if test "${g_libs[$lib_name]+_}"; then
  12.     return 0
  13. else
  14.     if test ${#g_libs[@]} == 0; then
  15.         declare -A g_libs
  16.     fi
  17.     g_libs[$lib_name]=$lib_version
  18. fi
  19.  
  20.  
  21. #
  22. # MAIN CODE:
  23. #
  24. ###~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~##
  25.  
  26. set -o pipefail  # trace ERR through pipes
  27. set -o errtrace  # trace ERR through 'time command' and other functions
  28. set -o nounset   ## set -u : exit the script if you try to use an uninitialised variable
  29. set -o errexit   ## set -e : exit the script if any statement returns a non-true return value
  30.  
  31. exec 2>"$stderr_log"
  32.  
  33.  
  34. ###~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~##
  35. #
  36. # FUNCTION: EXIT_HANDLER
  37. #
  38. ###~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~##
  39.  
  40. function exit_handler ()
  41. {
  42.     local error_code="$?"
  43.  
  44.     test $error_code == 0 && return;
  45.  
  46.     #
  47.     # LOCAL VARIABLES:
  48.     # ------------------------------------------------------------------
  49.     #    
  50.     local i=0
  51.     local regex=''
  52.     local mem=''
  53.  
  54.     local error_file=''
  55.     local error_lineno=''
  56.     local error_message='unknown'
  57.  
  58.     local lineno=''
  59.  
  60.  
  61.     #
  62.     # PRINT THE HEADER:
  63.     # ------------------------------------------------------------------
  64.     #
  65.     # Color the output if it's an interactive terminal
  66.     test -t 1 && tput bold; tput setf 4                                 ## red bold
  67.     echo -e "\n(!) EXIT HANDLER:\n"
  68.  
  69.  
  70.     #
  71.     # GETTING LAST ERROR OCCURRED:
  72.     # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
  73.  
  74.     #
  75.     # Read last file from the error log
  76.     # ------------------------------------------------------------------
  77.     #
  78.     if test -f "$stderr_log"
  79.         then
  80.             stderr=$( tail -n 1 "$stderr_log" )
  81.             rm "$stderr_log"
  82.     fi
  83.  
  84.     #
  85.     # Managing the line to extract information:
  86.     # ------------------------------------------------------------------
  87.     #
  88.  
  89.     if test -n "$stderr"
  90.         then        
  91.             # Exploding stderr on :
  92.             mem="$IFS"
  93.             local shrunk_stderr=$( echo "$stderr" | sed 's/\: /\:/g' )
  94.             IFS=':'
  95.             local stderr_parts=( $shrunk_stderr )
  96.             IFS="$mem"
  97.  
  98.             # Storing information on the error
  99.             error_file="${stderr_parts[0]}"
  100.             error_lineno="${stderr_parts[1]}"
  101.             error_message=""
  102.  
  103.             for (( i = 3; i <= ${#stderr_parts[@]}; i++ ))
  104.                 do
  105.                     error_message="$error_message "${stderr_parts[$i-1]}": "
  106.             done
  107.  
  108.             # Removing last ':' (colon character)
  109.             error_message="${error_message%:*}"
  110.  
  111.             # Trim
  112.             error_message="$( echo "$error_message" | sed -e 's/^[ \t]*//' | sed -e 's/[ \t]*$//' )"
  113.     fi
  114.  
  115.     #
  116.     # GETTING BACKTRACE:
  117.     # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
  118.     _backtrace=$( backtrace 2 )
  119.  
  120.  
  121.     #
  122.     # MANAGING THE OUTPUT:
  123.     # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
  124.  
  125.     local lineno=""
  126.     regex='^([a-z]{1,}) ([0-9]{1,})$'
  127.  
  128.     if [[ $error_lineno =~ $regex ]]
  129.  
  130.         # The error line was found on the log
  131.         # (e.g. type 'ff' without quotes wherever)
  132.         # --------------------------------------------------------------
  133.         then
  134.             local row="${BASH_REMATCH[1]}"
  135.             lineno="${BASH_REMATCH[2]}"
  136.  
  137.             echo -e "FILE:\t\t${error_file}"
  138.             echo -e "${row^^}:\t\t${lineno}\n"
  139.  
  140.             echo -e "ERROR CODE:\t${error_code}"            
  141.             test -t 1 && tput setf 6                                    ## white yellow
  142.             echo -e "ERROR MESSAGE:\n$error_message"
  143.  
  144.  
  145.         else
  146.             regex="^${error_file}\$|^${error_file}\s+|\s+${error_file}\s+|\s+${error_file}\$"
  147.             if [[ "$_backtrace" =~ $regex ]]
  148.  
  149.                 # The file was found on the log but not the error line
  150.                 # (could not reproduce this case so far)
  151.                 # ------------------------------------------------------
  152.                 then
  153.                     echo -e "FILE:\t\t$error_file"
  154.                     echo -e "ROW:\t\tunknown\n"
  155.  
  156.                     echo -e "ERROR CODE:\t${error_code}"
  157.                     test -t 1 && tput setf 6                            ## white yellow
  158.                     echo -e "ERROR MESSAGE:\n${stderr}"
  159.  
  160.                 # Neither the error line nor the error file was found on the log
  161.                 # (e.g. type 'cp ffd fdf' without quotes wherever)
  162.                 # ------------------------------------------------------
  163.                 else
  164.                     #
  165.                     # The error file is the first on backtrace list:
  166.  
  167.                     # Exploding backtrace on newlines
  168.                     mem=$IFS
  169.                     IFS='
  170.                    '
  171.                     #
  172.                     # Substring: I keep only the carriage return
  173.                     # (others needed only for tabbing purpose)
  174.                     IFS=${IFS:0:1}
  175.                     local lines=( $_backtrace )
  176.  
  177.                     IFS=$mem
  178.  
  179.                     error_file=""
  180.  
  181.                     if test -n "${lines[1]}"
  182.                         then
  183.                             array=( ${lines[1]} )
  184.  
  185.                             for (( i=2; i<${#array[@]}; i++ ))
  186.                                 do
  187.                                     error_file="$error_file ${array[$i]}"
  188.                             done
  189.  
  190.                             # Trim
  191.                             error_file="$( echo "$error_file" | sed -e 's/^[ \t]*//' | sed -e 's/[ \t]*$//' )"
  192.                     fi
  193.  
  194.                     echo -e "FILE:\t\t$error_file"
  195.                     echo -e "ROW:\t\tunknown\n"
  196.  
  197.                     echo -e "ERROR CODE:\t${error_code}"
  198.                     test -t 1 && tput setf 6                            ## white yellow
  199.                     if test -n "${stderr}"
  200.                         then
  201.                             echo -e "ERROR MESSAGE:\n${stderr}"
  202.                         else
  203.                             echo -e "ERROR MESSAGE:\n${error_message}"
  204.                     fi
  205.             fi
  206.     fi
  207.  
  208.     #
  209.     # PRINTING THE BACKTRACE:
  210.     # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
  211.  
  212.     test -t 1 && tput setf 7                                            ## white bold
  213.     echo -e "\n$_backtrace\n"
  214.  
  215.     #
  216.     # EXITING:
  217.     # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #
  218.  
  219.     test -t 1 && tput setf 4                                            ## red bold
  220.     echo "Exiting!"
  221.  
  222.     test -t 1 && tput sgr0 # Reset terminal
  223.  
  224.     exit "$error_code"
  225. }
  226. trap exit_handler EXIT                                                  # ! ! ! TRAP EXIT ! ! !
  227. trap exit ERR                                                           # ! ! ! TRAP ERR ! ! !
  228.  
  229.  
  230. ###~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~##
  231. #
  232. # FUNCTION: BACKTRACE
  233. #
  234. ###~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~##
  235.  
  236. function backtrace
  237. {
  238.     local _start_from_=0
  239.  
  240.     local params=( "$@" )
  241.     if (( "${#params[@]}" >= "1" ))
  242.         then
  243.             _start_from_="$1"
  244.     fi
  245.  
  246.     local i=0
  247.     local first=false
  248.     while caller $i > /dev/null
  249.     do
  250.         if test -n "$_start_from_" && (( "$i" + 1   >= "$_start_from_" ))
  251.             then
  252.                 if test "$first" == false
  253.                     then
  254.                         echo "BACKTRACE IS:"
  255.                         first=true
  256.                 fi
  257.                 caller $i
  258.         fi
  259.         let "i=i+1"
  260.     done
  261. }
  262.  
  263. return 0

Raw Paste


Login or Register to edit or fork this paste. It's free.