26

Why are shell scripts are so hard to develop? In NodeJS I could simply do:

require('./script')

and it will always require script relative to the current script. But if I try that in shell/bash:

./script.sh

it will look for script relative to cwd (pwd). Seems the dot means cwd (pwd) and not the directory where current script is located as I was expecting.

line 8: ./script.sh: No such file or directory

How can I execute a script relative to the directory where the current executing script is located?

I have tried

/bin/bash script.sh

but I get the error:

/bin/bash: script.sh: No such file or directory

Then I tried

script.sh

Got this error

line 8: script.sh: command not found

Only the following solution worked fine, but the problem is that it is unreadable:

$("$(dirname "$(realpath "$0")")/script.sh")

6 Answers 6

16

Another variant to get script dir:

DIR="$(cd "$(dirname "$0")" && pwd)"

then you can call script with

$DIR/script.sh
8

Unfortunately that is the way to go.

Another way (which I prefer) is to cd into the current dir at the beginning of your scripts like this:

cd $(dirname $0)
5

As the other answers have indicated, your solution is correct.

  • As the other answers have suggested, you can get the script directory once and use it multiple times.  This may be cleaner and more efficient.

  • As the other answers have suggested, you might not need the realpath.  Can you say why you believe that you need it?

  • You seem to have an extra $( and ) in your solution.

    "$(dirname "$(realpath "$0")")/script.sh"
    

    should be enough …

  • … except there’s a really subtle corner case that nobody else pointed out.  Let’s homogenize the other answers:

    DIR="$(dirname "$(realpath "$0")")"
    "$DIR"/script.sh
    

    If the “current script” is in the root directory (e.g., it is /first_script), and assuming that realpath doesn’t have any effect, we will get DIR="/", so the

    "$DIR"/script.sh
    

    line will be expanded as

    "/"/script.sh
    

    i.e.,

    //script.sh
    

    This is typically equivalent to /script.sh.  But Unix (POSIX) reserves the right to treat // at the beginning of a pathname specially.  It is infinitesimally safer to do

    DIR="$(dirname "$(realpath "$0")")"/
    "$DIR"/script.sh
    

    with an (extra, explicit) / at the end of the definition of DIR.  If $0 is /first_script, DIR will be set to //, and "$DIR"/script.sh will be expanded as ///script.sh, which is guaranteed to be equivalent to /script.sh.  And if $0 is something more common, like /foo/bin/first_script, then DIR will be set to /foo/bin/, and "$DIR"/script.sh will be expanded as /foo/bin//script.sh, which is also guaranteed to be equivalent to /foo/bin/script.sh.

2

In most cases, when script.sh is in the same directory, you can use just:

${0%/*}/script.sh

Explanation:
$0 stores the name of your process (in most cases it's the full path to your script).
${parameter%word} removes suffix pattern word from variable $parameter (in the command above it removes file name /* from the full path stored in variable $0).

If for some reasons you don't want to use $0, in bash you can use $BASH_SOURCE instead:

${BASH_SOURCE%/*}/helper.sh

As for me, these are the easiest ways to achieve your goal.

2

Improving on the Answer from Mikael Kjær.

I had problems handling path with spaces in them but was able to solve it using

cd "$(dirname "$0")"
1

$0 refers to your current script and dirname $0 will get the directory name of your current script (the full path without the file name)

so you can do it like this:

$(dirname $0)/script.sh
2
  • 1
    Welcome to the site, and thank you for your contribution. Please note that the "backtick"-style for command substitutions is discouraged and the new $( ... )-style is now recommended.
    – AdminBee
    Oct 29, 2020 at 9:44
  • 1
    (1) This is a subset of the answer that was presented in the question! Do you claim that realpath is totally unnecessary in this situation? Can you justify such a claim?  (2) You should learn why people use quotes. Oct 30, 2020 at 6:40

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .