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
.
1 Answer 1
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]}"
You must log in to answer this question.
Explore related questions
See similar questions with these tags.
declare -p BASH_SOURCE FUNCNAME BASH_LINENO
toErrorReport()
. That should show the problem. Is the bash version the same everywhere?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).