skip to Main Content

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


  1. Chosen as BEST ANSWER

    It seems that my problem is a mixture of:

    1. Unsourced variables not available to initial-tests.bash in case it is run directly and not via main.bash (the colour escape sequences)
    2. Using echo -ne $nc as the last command in echoerr, which is prepending $nc to the echo that immediately follows in first_check function.

    Regarding point 1, when I run bash main.bash and then source initial-tests.bash, the sourced script will have access to the colour escape sequences. But when I directly source 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:

    echo -n hi; echo bye
    > hibye
    

    When $nc is blank due to sourcing initial-tests.bash directly as explained, function first_check is producing a mere false since nothing is prepended to 'false' because $nc is empty:

    echo -ne $nc (last command in echoerr)
    echo false
    

    And the if test in do_check passes:

    if [[ "$x" = 'false' ]]; then
        echo
    else
        echo false
    fi
    

    => 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:

    1. Making sure the colour sequences vars are always available before using them
    2. Removing echo -n from echoerr to avoid prepending anything to the immediate next echo.

  2. why source is producing a different result from the bash run.

    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 run main.bash, the initial-tests.bash script is sourced in a subshell, and since several variable is declared in main.bash, it is not 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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search