17

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")
13

Another variant to get script dir:

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

then you can call script with

$DIR/script.sh
7

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)
2

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.

0

$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 '20 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. – G-Man Says 'Reinstate Monica' Oct 30 '20 at 6:40
0

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.