owl-947741_640

Bash Debug: 3 Builtin Variables That Will Save Your Time

These 3 builtin bash variables will definitely make your life easier when it comes to debugging your script. Especially when they contain a lot of functions that are calling each other. Together they will give you a stack backtrace and the location of each function call.

FUNCNAME

FUNCNAME is an array variable that contains the name of the functions in the call stack. The first element of the array is the name of the current function. The next, the function that called this one. And so on, until the last entry, which is “main”.

BASH_SOURCE

This is also an array. Each element ${BASH_SOURCE[i]} represents the file name where the ${FUNCNAME[i]} was defined. ${BASH_SOURCE[i+1]} is the file where this function was invoked from.

BASH_LINENO

The ${BASH_LINENO[i]} is the line number in the ${BASH_SOURCE[i+1]} file where ${FUNCNAME[i]} was invoked from.

To make this more clear, let’s assume we have two files, var.sh and topLevel.sh. These files contain files that call each other, from the d function in topLevel.sh down to the function  in var.sh. This latter function dumps the contents of these three arrays. Let’s run them and see what happens.

var.sh
     1  #!/bin/bash 
     2 
     3  a() { 
     4 
     5      for ((i=0;i<${#FUNCNAME[@]};i++)) 
     6      do 
     7          echo -n "${FUNCNAME[$i]} " 
     8      done 
     9 
    10      echo 
    11 
    12      for ((i=0;i<${#BASH_LINENO[@]};i++)) 
    13      do 
    14          echo -n "${BASH_LINENO[$i]} " 
    15 
    16      done 
    17      echo 
    18 
    19      for ((i=0;i<${#BASH_SOURCE[@]};i++)) 
    20      do 
    21          echo -n "${BASH_SOURCE[$i]} " 
    22      done 
    23      echo 
    24  } 
    25  b() { 
    26      a 
    27  } 
    28 
    29  c() { 
    30      b 
    31  } 
    32 
    33
topLevel.sh

     1  #!/bin/bash 
     2 
     3  . ./var.sh 
     4  d() { 
     5      c 
     6  } 
     7 
     8  d

When running topLevel.sh you will get the following output:

$ ./topLevel.sh      
a b c d main  
26 30 5 8 0  
./var.sh ./var.sh ./var.sh ./topLevel.sh ./topLevel.sh 

So let’s take a look at this output and its meaning. The first line is the contents of the FUNCNAME array, displayed in  the first for in the a function. It is the backtrace of the current function (a) from the top level (main). This means that a is called by b, which in turn is called by c, in turn called by d, which is called from the top level.

The meanings of the next rows are linked together. The first var.sh is the file where function a is defined. Function a is called from var.sh (the second on the line) at line 26. Function b is called from var.sh (the third) at line 30. Function c is called from topLevel.sh (first)  at line 5. Function d is called from topLevel.sh at line 8.

And because a picture is worth more than the 375 words so far (current phrase excluded):

backtrace_1

References

[1] man bash
Subscribe to my mailing list
100% Privacy. I don't spam.

Leave a Reply

Your email address will not be published. Required fields are marked *