Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can a bash script know the directory it is installed in when it is sourced with . operator?

What I'd like to do is to include settings from a file into my current interactive bash shell like this:

$ . /path/to/some/dir/.settings

The problem is that the .settings script also needs to use the "." operator to include other files like this:

. .extra_settings

How do I reference the relative path for .extra_settings in the .settings file? These two files are always stored in the same directory, but the path to this directory will be different depending on where these files were installed.

The operator always knows the /path/to/some/dir/ as shown above. How can the .settings file know the directory where it is installed? I would rather not have an install process that records the name of the installed directory.

like image 467
Gary Avatar asked Jan 07 '09 19:01

Gary


People also ask

Can a bash script tell what directory is stored in?

There may be times when you need to know the actual location a BASH script is located within the script. This can be done with a combination of the $0 value and the dirname command.

How do you find the directory of a file in bash?

You can use $BASH_SOURCE : #!/usr/bin/env bash scriptdir="$( dirname -- "$BASH_SOURCE"; )"; Note that you need to use #!/bin/bash and not #!/bin/sh since it's a Bash extension.

What happens when you source a file in bash?

The source command reads and executes commands from the file specified as its argument in the current shell environment. It is useful to load functions, variables, and configuration files into shell scripts.

How do you check if a directory exists or not in bash?

Check if directory exists in Bash scriptDIR=/tmp/downloads [ -d "$DIR" ] && echo "$DIR directory exists." A command line one-liner would look like this: $ DIR=/tmp/downloads; [ -d "$DIR" ] && echo "$DIR directory exists." OR $ [ -d /tmp/downloads ] && echo "the directory exists."


2 Answers

I believe $(dirname "$BASH_SOURCE") will do what you want, as long as the file you are sourcing is not a symlink.

If the file you are sourcing may be a symlink, you can do something like the following to get the true directory:

PRG="$BASH_SOURCE"
progname=`basename "$BASH_SOURCE"`

while [ -h "$PRG" ] ; do
    ls=`ls -ld "$PRG"`
    link=`expr "$ls" : '.*-> \(.*\)$'`
    if expr "$link" : '/.*' > /dev/null; then
        PRG="$link"
    else
        PRG=`dirname "$PRG"`"/$link"
    fi
done

dir=$(dirname "$PRG")
like image 177
Jason Day Avatar answered Oct 21 '22 10:10

Jason Day


We found $(dirname "$(realpath "$0")") to be the most reliable with both sh and bash. As team mates used them interchangeably, we ran into problems with $BASH_SOURCE which is not supported by sh.

Instead, we now rely on dirname, which can also be stacked to get parent, or grandparent folders.

The following example returns the parent dir of the folder that contains the .sh file:

parent_path=$(dirname "$(dirname "$(realpath "$0")")")
echo $parent_path
like image 34
Johnny Avatar answered Oct 21 '22 12:10

Johnny