BASH: variable and function scope and subscripts

Hi,

I'm a Delphi developer new to linux, new to this forums and new to BASH programming and got a new task in my work: maintaining an existing set of BASH scripts. First thing I want to do is making the code more reliable as in my opinion it's really bad written. So here's the quest:

I'm using an EXIT-trap for cleaning up after a script. For this task I used the Idea from Use the Bash trap Statement to Clean Up Temporary Files | Linux Journal (I'm not yet allowed to post URLs) which defines a function to add to a list of statements to be executed on EXIT called add_on_exit. A second function (on_exit) is registered in the trap and executes the statements added in reverse order. To this point it's all clear to me and working in the first script.

Now I want to re-use this functions. The system consists of 3 parts: The 2 functions and the array. I'm not completely sure about the scope and when the triggering events occur. Here is what I found so far (please confirm or refute):

  • Functions and variables are valid till the shell closes.
  • The EXIT "signal" is fired whenever the script ends (in contrast to the validity of the functions and parameters).
  • When a script is called by executing the file, it is executed in the shell of the caller. (not sure how to check this - Edit: According to cero: If the file is executed by calling the file it opens a new shell for execution, if it's sourced it executes in the existing shell - thanks for clarification!)
  • When a script is executed by cron, the script is executed in a new shell which is closed afterwards (not sure how to check this)
  • Calling a script that does nothing but defining functions lets me use them in my script after the call. (doesn't seem to work: functions don't seem to be defined after the call - Edit: source them works, thanks to jim mcnamara)
  • I can pass a global variable "by reference" to a function by passing the name of the variable and using it with eval (confirmed through tests)

Things that are still unclear to me:

  • Is it safe to redefine the on_exit function (e.g. on a subscript) while a trap is set (i.e. between the first call to add_on_exit and the end of the script)?

Last but not least here's the actual code I'm planning to use:

  • Script with the functions (lets call it defineexittrapfuncs):
    text #!/bin/bash function on_exit { # evaluate statements in passed array in reverse order eval 'for ((i=${#'$1'[*]}-1; i>=0; i--)); do eval ${'$1'[$i]}; done' } function add_on_exit { local items_array="$1" # name of the array with statements shift eval 'local n=${#'$items_array'[*]}' # number of already existing statements in the array if [[ $n -eq 0 ]]; then eval $items_array'[$n]="unset '$items_array'"' # first unset the array (evaluated last) ((n++)) fi eval $items_array'[$n]="$@"' # append new statement if [[ $n -eq 1 ]]; then # create trap, if this was the first added statement eval "trap 'on_exit "$items_array"' EXIT" # on_exit gets called whenever the script ends, regardless of the end-reason fi }
  • Script that would make use of the EXIT-trap (edited according to the answer of jim mcnamara):
    text #!/bin/bash MUTEX=/tmp/mutex_`basename ${0}` EXISTS=`basename ${0}`': Mutex vorhanden' declare -a on_exit_items source ./defineexittrapfuncs # for testing it's in the same directory if [ -f $MUTEX ]; then echo -e "\n$EXISTS\n" exit 0 else date +%s > $MUTEX add_on_exit on_exit_items rm "$MUTEX" echo 'script is doing something' fi

One point:

Calling a script that does nothing but defining functions lets me use them in my script after the call. (doesn't seem to work: functions don't seem to be defined after the call)

You have to source external files that simply define variables/functions, ex: foo.shl

#! /bin/bash

# method 1
source ./path/to/foo.shl
# method 2
.  ./path/to/foo.shl

Note the leading dot, followed by a space

1 Like

Thanks for that important hint! I adapted my first post according to that.

Since there are no further replies I assune that all my other findings are not wrong and I will implement it that way.

This is not completely correct:
"When a script is called by executing the file, it is executed in the shell of the caller. (not sure how to check this)"

Not sure what you mean with "called by executing the file", but unless you source it a script starts a subshell which terminates when the script ends. That's why functions and variables are not defined after execution (see jims post).

1 Like

That makes perfect sense to me. I assume the first line in the script, the shebang, opens the new shell for execution.

Again, I edited my first post. Thanks very much!

RSE

p.s. Sorry for the delay, there was an official holiday on thursday and I didn't check from at home.

The shebang does not open the new shell, it just defines what is used to process the script. Usually it says which shell should be used, but the shebang does not have to point to a shell.