3

Inspired by this question.

Getting the source directory of a Bash script from within

Is it possible, but without the need for bash.

I'm running Ubuntu and before i needed that accepted solution from the Bash question, my hash bang was like this

#!/bin/sh

and I liked it that way, is there a way to keep it that way?

EDIT:

It should output the correct directory, even when run thus,

./script.sh
Community
  • 1
  • 1
bluekeys
  • 2,217
  • 1
  • 22
  • 30

6 Answers6

4

How about $(dirname -- "$0")?

If your shell uses backticks only, it'd be:

`dirname -- "$0"`
John Zwinck
  • 239,568
  • 38
  • 324
  • 436
3

/bin/sh is a bourne-compatible shell (today either bash or ksh). On those, the following line of code will give you the absolute path of the currently running script:

DIR=$( cd $( dirname -- "$0" ) > /dev/null ; pwd )

There is a lot of wisdom in this line:

  • The quotes make sure that spaces in the path don't cause problems.
  • No quotes are necessary to protect the results of $(...). If you use backticks, you need more quotes but almost any shell today supports $() because of the many problems with backticks.
  • The $() has the nice side effect that the commands are executed in a subshell, so the current path doesn't change.
  • The -- is there to avoid problems with paths that start with -
  • The > /dev/null is there because cd can print the current path depending on a shell option.
  • I'm using dirname because everything else needs special features which aren't available everywhere. It means that a process has to be forked but then, this happens once.
  • pwd prints the absolute path
Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
2

For those who looking cross BASH DASH current script folder.

1.sh:

#!/bin/sh
if [ "$BASH_SOURCE" != "" ]
then
    DIR="$( cd "$( dirname "$BASH_SOURCE" )" && pwd )"
elif [ "$DASH_SOURCE" != "" ]
then
    DIR="$( cd "$( dirname "$DASH_SOURCE" )" && pwd )"
else
    DIR="$( cd "$( dirname "$0" )" && pwd )"
fi
echo $DIR

Will produce the following:

cd ~
docker@boot2docker:~$ sh ./test/1.sh 
/home/docker/test
docker@boot2docker:~$ ./test/1.sh 
/home/docker/test
docker@boot2docker:~$ source ./test/1.sh 
/home/docker

If anybody knows how to deal with source, please comment below.

FelikZ
  • 2,976
  • 4
  • 32
  • 41
2
mydir="${0%/*}"
if [ "$mydir" == "$0" ]; then
    echo "Indeterminate location."
    exit 1;
fi;

No need to create an extra process and call dirname. Indetermine location can happen when running it directly within the shell prompt (where $0 == "-bash", for example), or when a program is invoked by searching through $PATH. (Then $0 will also be without slashes)

#optional addition
mydir=$(readlink -f "$0")
jørgensen
  • 10,149
  • 2
  • 20
  • 27
2

It's not possible to do this in a reliable way without making assumptions about the system it's running on. This bash wiki entry goes into a lot of detail about the issue.

The page offers these alternatives:

It really makes the most sense to keep your script's configuration in a single, static location such as /etc/foobar.conf. If you need to define multiple configuration files, then you can have a directory (say, /var/lib/foobar/ or /usr/local/lib/foobar/), and read that directory's location from a fixed place such as /etc/foobar.conf. If you don't even want that much to be hard-coded, you could pass the location of foobar.conf (or of your configuration directory itself) as a parameter to the script. If you need the script to assume certain default in the absence of /etc/foobar.conf, you can put defaults in the script itself, or fall back to something like $HOME/.foobar.conf if /etc/foobar.conf is missing. When you install the script on a target system, you could put the script's location into a variable in the script itself. The information is available at that point, and as long as the script doesn't move, it will always remain correct for each installed system. In most cases, it makes more sense to abort gracefully if your configuration data can't be found by obvious means, rather than going through arcane processes and possibly coming up with wrong answers.

Daenyth
  • 35,856
  • 13
  • 85
  • 124
2

Personally, I use :

EXEC_DIR=$( readlink -f $( dirname -- "$0" ) )

in my shell scripts (/bin/sh). Works OK for me so far.

Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
Offirmo
  • 18,962
  • 12
  • 76
  • 97