0

I want to put all common functions in a "included_by_other_shell_script.sh" and then call it by using source command.

Here is the sourcing script: /tmp/main/sourcing_test.sh

#!/bin/bash

source /tmp/sourced/included_by_other_shell_script.sh

echo "test_dir: $test_dir"

Here is the sourced script: /tmp/sourced/included_by_other_shell_script.sh

#!/bin/bash

get_bash_script_dir() {
    printf "%s" "${BASH_SOURCE[0]}"
}

test_dir="$(get_bash_script_dir)"

Run the sourcing test:

/tmp/main/sourcing_test.sh

Here is the output:

root@test:~# /tmp/main/sourcing_test.sh
test_dir: /tmp/sourced/included_by_other_shell_script.sh

Here is the expected output:

root@test:~# /tmp/main/sourcing_test.sh
test_dir: /tmp/main

How to get the sourcing bash dir in the common function "get_bash_script_dir()"?

stackbiz
  • 1,136
  • 1
  • 5
  • 22
  • Simply `dirname "$0"`? – tripleee Apr 12 '23 at 04:54
  • Apparent duplicate of https://stackoverflow.com/questions/59895/how-do-i-get-the-directory-where-a-bash-script-is-located-from-within-the-script – tripleee Apr 12 '23 at 04:55
  • It's not duplicated at all, @tripleee. The solution in that link only works when the function is in the "sourcing" script but it will not work when in "sourced" script. This post asks another question. – stackbiz Apr 12 '23 at 04:57
  • I'm not sure what you mean; this demo does what you seem to be asking. https://ideone.com/q9R2cp – tripleee Apr 12 '23 at 05:02
  • (Separately, calling the function in the main script would seem to make more sense. Defining it in the included script is fine but polluting the variable name space in included code seems like a spaghetti technique.) – tripleee Apr 12 '23 at 05:03
  • When using the "sourced" solution, I only define a global "variable_name" in the souced script, and then can simply use the global "vairable_name" from all other calling scripts, that's the purpose. – stackbiz Apr 12 '23 at 05:05
  • I have many scripts need to use the same path defined by the common function in the sourced script. – stackbiz Apr 12 '23 at 05:08
  • A common band aid is to use a variable prefix which properly identifies the variable as a global and belonging to your package. Anyway, this discussion is parenthetical. Again, can you explain how the linked demo does not provide what you are asking for? – tripleee Apr 12 '23 at 05:19

1 Answers1

2

Use "${BASH_SOURCE[-1]}" or maybe "${BASH_SOURCE[2]}" instead of "${BASH_SOURCE[0]}".

Explanation: BASH_SOURCE is an array, with an entry for each layer in the current call stack (and source is treated like a function call). So within your function:

  • ${BASH_SOURCE[0]} is the source file the function's in "/tmp/sourced/included_by_other_shell_script.sh".
  • ${BASH_SOURCE[1]} is the file it's being run from. In this case, it's the location of the test_dir="$(get_bash_script_dir)" line, which is in the same file.
  • ${BASH_SOURCE[2]} is the file that that is being run from. In this case, it's the location of the source ... line, which is in "/tmp/main/sourcing_test.sh".

"${BASH_SOURCE[-1]}" will get the last entry in the array, which will be the parent-of-all-calls file, i.e. the main script. If you know the exact context the function will be run from, you could also use e.g. "${BASH_SOURCE[2]}" to get the specific call level you want.

BTW, adding declare -p BASH_SOURCE >&2 to the function would show this pretty clearly.

Gordon Davisson
  • 118,432
  • 16
  • 123
  • 151