Finding a Bash script's Runfiles as generated by Bazel When building a sh_binary with dependencies using Bazel, a tree of Runfiles containing the dependencies is generated:

my_executable
my_executable.sh
my_executable.runfiles/
    __main__/
        a_dependency/
            lib_dependency.sh


When deploying such a binary to a typical Unix filesystem, one would install the above file tree to /usr/local/opt/my_executable for example. Binaries however are usually linked to the /usr/local/bin directory:

ln -s /usr/local/opt/my_executable/my_executable /usr/local/bin/my_executable


Like this, it is possible to run the executable as my_executable from anywhere on the system. However the trivial approach of finding the runfiles with

RUNFILES="${BASH_SOURCE[0]}.runfiles/__main__"


then fails since ${BASH_SOURCE[0]} refers to the symlink. Preferably it would be possible to find Runfiles for an arbitrary number of "indirections" using symlinks. The following snippet provides a cross-platform implementation, that searches for a script's Runfiles by successively following symlinks.

# Determine the script's executable name
if [[ ! -v EXEC_NAME ]]; then
  export EXEC_NAME="${BASH_SOURCE[0]##*/}"
fi

# Determine the script's runfiles location, possibly resolving symlinks
if [[ ! -v RUNFILES ]]; then
  EXEC_PATH="${BASH_SOURCE[0]}"
  while [[ ! -a "$EXEC_PATH.runfiles" ]]; do
    if [[ ! -h "$EXEC_PATH" ]]; then
      printf "$EXEC_NAME: error: could not find runfiles\n" 1&gt;&amp;2
      exit 1
    fi
    EXEC_PATH=$(readlink "$EXEC_PATH")
  done
  export EXEC_PATH
  export RUNFILES="$EXEC_PATH.runfiles/__main__"
fi


And later in the script, it is then possible to use the dependency like this:

source "$RUNFILES/a_dependency/lib_dependency.sh"
The following snippet provides a cross-platform implementation


That looks correct, but the script requires Bash 4, and I don't see any validation of that.

Actually, the only Bash 4 feature is the -v VAR operator of [[,
used as [[ ! -v VAR ]].
I would replace that with [[ ! "$VAR" ]],
even if it's not exactly the same thing,
but probably good enough.



Do you really need the [[ ! -v EXEC_NAME ]] check?
I don't see a point in a caller overriding this,
so I would drop the condition.

From the snippet it's not clear why this variable is exported with the export keyword.
I would review this point, and if there is no reason to export it,
then drop the export.



It seems to me the script is intended to be executed,
as opposed to being sourced.
In this case, you could use $0 as the name of the executable,
no need for the tedious ${BASH_SOURCE[0]}.



According to help test:


-a FILE        True if file exists.
...
-e FILE        True if file exists.



Although using -a is correct, I prefer -e, because it's easy to associate with the word "exists".
I had to look up help test to verify what is -a.



Instead of printf "...\n" it's simpler to write echo "...",
the \n is automatically added,
and the posted snippet doesn't use any interesting feature of printf.



Instead of:


EXEC_PATH="${BASH_SOURCE[0]}"
...
export EXEC_PATH



I would write:

export EXEC_PATH="${BASH_SOURCE[0]}"