I have a bash script initial-tests.bash
that runs some tests, using another script with pure functions. It looks something like:
#! /bin/bash
source ./scripts/_functions.bash
check=$(do_check)
echo "$check"
The script _functions.bash
contains this:
#! /bin/bash
# Here we save reusable functions to aid the other scripts
echoerr() {
# Output to stderr while freeing stdout for returns
echo -ne $red
echo "ERROR: $*" | ts '[%Y-%m-%d %H:%M:%S]' 1>&2
echo -ne $nc
}
first_check() {
echoerr "This is an echoerr with echo -e"
echo false
}
do_check() {
local x
x=$(first_check)
if [[ "$x" = 'false' ]]; then
echo
else
echo false
fi
}
initial-tests.bash
is in turn sourced by another script main.bash
:
#! /bin/bash
nc='e[0m'
yellow='e[1;33m'
green='e[1;32m'
red='e[1;31m'
blue='e[1;34m'
# Fail early in case of argumentation error
echo -e "${blue}- - - Initial Checks - - -${nc}"
source ./scripts/initial-checks-load-config.bash
The tests’ outputs are correct when I source
that script directly: source scripts/initial-tests.bash
:
[2024-10-10 08:30:55] ERROR: This is an echoerr with echo -e
But when I run bash main.bash
, the tests are wrong:
- - - Initial Checks - - -
[2024-10-10 08:30:49] ERROR: This is an echoerr with echo -e
false
Note that false
should be empty.
It is not clear to me why source
is producing a different result from the bash
run.
More info:
- OS: Ubuntu 24.04.1 LTS (GNU/Linux 6.8.0-1015-azure x86_64)
- Bash: GNU bash, version 5.2.21(1)-release (x86_64-pc-linux-gnu)
2
Answers
It seems that my problem is a mixture of:
initial-tests.bash
in case it is run directly and not viamain.bash
(the colour escape sequences)echo -ne $nc
as the last command inechoerr
, which is prepending$nc
to theecho
that immediately follows infirst_check
function.Regarding point 1, when I run
bash main.bash
and then sourceinitial-tests.bash
, the sourced script will have access to the colour escape sequences. But when I directlysource initial-tests.bash
, and since the colour sequences are not (re-)defined within, these colour sequences are blank.Regarding point 2, using
-n
prepends to next echo:When
$nc
is blank due to sourcinginitial-tests.bash
directly as explained, functionfirst_check
is producing a mere false since nothing is prepended to 'false' because$nc
is empty:And the
if
test indo_check
passes:=> so output is ''.
However, when I run
bash main.bash
,$nc
contains a colour escape sequence, so that sequence is prepended to false and is making the same test fail, and hence going to the else, and echoing 'false' instead of nothing => so output is 'false'. It was tricky to detect since the prepended value was an escape sequence.I could fix this by:
echo -n
fromechoerr
to avoid prepending anything to the immediate next echo.It’s probably because that source executes scripts in the current shell environment, while bash runs the script in a new subshell. This can lead to differences in the way variables and setting.
Potential problem: When you source the
scripts/initial-tests.bash
directly, the environment remains the same, and also several variable assignments are accessible as they are part of the current shell. However, when you runmain.bash
, the initial-tests.bash script is sourced in asubshell
, and since several variable is declared in main.bash, it isnot available to _functions.bash
.What you can try to check that several variables are accessible when _functions.bash is sourced and used. Alternatively, ensure main.bash sources _functions.bash before any function calls, so that the variables are accessible.