1

In Visual Code, on Windows 10, I'm trying to create a function for my .sh project (which I run with Git Bash), which will report errors to the console in case user, let's say, provides fewer or more parameters for a function.

For this reason, I created the file error_report.sh with the function ErrorReport.

#!/usr/bin/env bash
function ErrorReport()
{
 local caller_func="${FUNCNAME[2]}"
 local caller_file="$(basename "${BASH_SOURCE[2]}")"
 local caller_line="${BASH_LINENO[1]}"
 local caller_code="$(sed -n "${caller_line}p" "${BASH_SOURCE[2]}" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')"
 printf "\nCaller: ${caller_func}()"
 printf "\nFile : ${caller_file}"
 printf "\nLine : ${caller_line}"
 printf "\nCode : ${caller_code}"
}

As main file of my project, I have temporarily created the tester_copy.sh where I have the following:

#!/usr/bin/env bash
declare -g script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${script_dir}/lib/ui/window_manager.sh"
source "${script_dir}/error_report.sh"
function TestFunction()
{
 if [[ "$#" -ne 3 ]]; then
 ErrorReport
 return 1
 fi
 local arg1="1ドル"
 local arg2="2ドル"
 local arg3="3ドル"
 echo "arguments: $arg1, $arg2, $arg3"
}
function Main()
{
 ConsoleWindowSetup "${MMS_WINDOW_TITLE}" 40 120
 clear
 TestFunction "11111" "22222"
 read -re -p ""
}
Main "$@"

The problem is that in my console, displays Caller and File correctly, but Line and Code incorrectly. Instead of displaying Line: 28 and Code: TestFunction "11111" "22222", it displays:

Caller: Main()
File : tester_copy.sh
Line : 6
Code : source "${script_dir}/error_report.sh"

But if I change my main script to:

#!/usr/bin/env bash
declare -g script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${script_dir}/lib/ui/window_manager.sh"
source "${script_dir}/error_report.sh"
function TestFunction()
{
 if [[ "$#" -ne 3 ]]; then
 ErrorReport
 return 1
 fi
 local arg1="1ドル"
 local arg2="2ドル"
 local arg3="3ドル"
 echo "Λήφθηκαν τα arguments: $arg1, $arg2, $arg3"
}
ConsoleWindowSetup "${MMS_WINDOW_TITLE}" 40 120
clear
TestFunction "11111" "22222"
read -re -p ""

If I take the main code outside the function Main(), then it displays correctly in the console...

Caller: main()
File : tester_copy.sh
Line : 28
Code : TestFunction "11111" "22222"

Which I don't want though because ErrorReport is intended for errors inside functions.

Why is this happening and how can I make it work when the error is inside a function?

Debugging (17/05/2025)
  • If I copy the whole .sh project into my Ubuntu Server it works even if the error is inside a function.

  • It also works using WSL.

  • I am almost sure that the problem happens only if I run the .sh file from Windows, by just double clicking on it. In any other case, works fine.

Debugging (18/05/2025)

The default application on this Windows computer to open .sh files is "C:\Program Files\Git\git-bash.exe". When I open my .sh file by double-clicking, the problem I mentioned occurs. However, if I try running it by dragging the file to "C:\Program Files\Git\bin\bash.exe", "C:\Program Files\Git\bin\sh.exe" or "C:\Program Files\Git\git-bash.exe", it works fine in all three!

I tried creating a shortcut with the target "C:\Program Files\Git\git-bash.exe" --cd="C:\Users\***\Desktop\PROGRAMMING\SH\sigma_sh_lib" -c "./tester_copy.sh" and it also works fine!

Then I created a function to get debug shell info...

DebugShellInfo() {
 echo "================= DEBUG INFO ================="
 printf "🔹 Shell Script Name : %s\n" "0ドル"
 printf "🔹 Declared Interpreter : %s\n" "${SHELL:-<not set>}"
 printf "🔹 Bash Version : %s\n" "${BASH_VERSION:-<not bash>}"
 # FUNCNAME stack
 printf "🔹 FUNCNAME Stack :"
 if [[ ${#FUNCNAME[@]} -eq 0 ]]; then
 echo " <empty>"
 else
 echo " ${FUNCNAME[0]}"
 for ((i = 1; i < ${#FUNCNAME[@]}; i++)); do
 printf " %s\n" "${FUNCNAME[i]}"
 done
 fi
 # BASH_SOURCE stack
 printf "🔹 BASH_SOURCE Stack :"
 if [[ ${#BASH_SOURCE[@]} -eq 0 ]]; then
 echo " <empty>"
 else
 echo " ${BASH_SOURCE[0]}"
 for ((i = 1; i < ${#BASH_SOURCE[@]}; i++)); do
 printf " %s\n" "${BASH_SOURCE[i]}"
 done
 fi
 # BASH_LINENO stack
 printf "🔹 BASH_LINENO Stack :"
 if [[ ${#BASH_LINENO[@]} -eq 0 ]]; then
 echo " <empty>"
 else
 echo " ${BASH_LINENO[0]}"
 for ((i = 1; i < ${#BASH_LINENO[@]}; i++)); do
 printf " %s\n" "${BASH_LINENO[i]}"
 done
 fi
 echo "=============================================="
}

Now, when I called it, I noticed the following. When it is called while the file is running by double-clicking it outputs...

================= DEBUG INFO =================
🔹 Shell Script Name : C:\Users\***\Desktop\PROGRAMMING\SH STUFF\sigma_sh_lib\tester_copy.sh
🔹 Declared Interpreter : /usr/bin/bash
🔹 Bash Version : 5.2.37(1)-release
🔹 FUNCNAME Stack : DebugShellInfo
 MSG
 MSG
 Main
 main
🔹 BASH_SOURCE Stack : /c/Users/***/Desktop/PROGRAMMING/SH STUFF/sigma_sh_lib/lib/utils/debug_shell_info.sh
 /c/Users/***/Desktop/PROGRAMMING/SH STUFF/sigma_sh_lib/lib/ui/msg.sh
 /c/Users/***/Desktop/PROGRAMMING/SH STUFF/sigma_sh_lib/lib/ui/msg.sh
 C:\Users\***\Desktop\PROGRAMMING\SH STUFF\sigma_sh_lib\tester_copy.sh
 C:\Users\***\Desktop\PROGRAMMING\SH STUFF\sigma_sh_lib\tester_copy.sh
🔹 BASH_LINENO Stack : 130
 1
 14
 70
 0
==============================================

But when it is called with the other ways I mentioned above, it outputs...

================= DEBUG INFO =================
🔹 Shell Script Name : ./tester_copy.sh
🔹 Declared Interpreter : /usr/bin/bash
🔹 Bash Version : 5.2.37(1)-release
🔹 FUNCNAME Stack : DebugShellInfo
 MSG
 MSG
 Main
 main
🔹 BASH_SOURCE Stack : /c/Users/***/Desktop/PROGRAMMING/SH STUFF/sigma_sh_lib/lib/utils/debug_shell_info.sh
 /c/Users/***/Desktop/PROGRAMMING/SH STUFF/sigma_sh_lib/lib/ui/msg.sh
 /c/Users/***/Desktop/PROGRAMMING/SH STUFF/sigma_sh_lib/lib/ui/msg.sh
 ./tester_copy.sh
 ./tester_copy.sh
🔹 BASH_LINENO Stack : 194
 95
 60
 70
 0
==============================================

Notice the differences in the "Shell Script Name" paths and in "BASH_SOURCE Stack" and "BASH_LINENO Stack" paths!!!

Note: I moved the code of ErrorReport function into a function called MSG.

asked May 17 at 9:04
5
  • 1
    You should add declare -p BASH_SOURCE FUNCNAME BASH_LINENO to ErrorReport(). That should show the problem. Is the bash version the same everywhere? Commented May 17 at 15:04
  • Please take a look at my question under "Debugging (18/05/2025)"! Commented May 18 at 8:26
  • 1
    Please don't multi-post - stackoverflow.com/q/79626351/1745001 Commented May 18 at 14:28
  • Sorry, I though it was two different things! Commented May 18 at 14:34
  • Seeing Windows paths (C:\Users`) with lower line numbers and Linux paths (./tester_copy.sh) with higher numbers makes me wonder if that is a line ending problem (\r\n` being counted as one / two). Commented May 18 at 16:31

1 Answer 1

0

You could say that the source of the problem is the positive indexing in

 local caller_func="${FUNCNAME[2]}"
 local caller_file="$(basename "${BASH_SOURCE[2]}")"
 local caller_line="${BASH_LINENO[1]}"

You could replace 2 with -1 and 1 with -2. That may solve the problem.

Even safer (as sourcing files adds entries to these stacks) when you want to know what is happening in Main() at that moment, add this to Main():

FUNC_MAIN_LEVEL=${#FUNCNAME[@]}

And use that variable in ErrorReport():

 local caller_func="${FUNCNAME[-FUNC_MAIN_LEVEL]}"
 local caller_file="$(basename "${BASH_SOURCE[-FUNC_MAIN_LEVEL]}")"
 local caller_line="${BASH_LINENO[-FUNC_MAIN_LEVEL-1]}"
answered May 17 at 15:21
1
  • It didn't work... Commented May 18 at 8:27

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.