3

given the following:

# a.sh

source ./stuff/b.sh

and

# b.sh

source ./c.sh

folder structure

- a.sh
- stuff
  - b.sh
  - c.sh

when running a.sh it gives an error ./c.sh: No such file or directory

While I can put absolute path for c, I rather keep it relative since the scripts could run in numerous locations.

Is it possible to do?

2
  • When you're calling your script, . stands for the folder you're in when calling it. You can use realpath and dirname to get the absolute path to your file and create the relative path you need for your script. If you're on Mac os, try brew install coreutils to get realpath command. Hope it helps Commented Apr 7, 2018 at 16:35
  • The only script that should need to worry about its location is a.sh. It should export a variable like ADIR that contains its installation location; then everything else uses dynamic absolute paths like $ADIR/stuff/b.sh. Commented Apr 7, 2018 at 16:39

1 Answer 1

4

A portable solution to achieve what you want consists in replacing the contents of file b.sh with:

#!/usr/bin/env bash
# (file b.sh)

srcdir=$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )

source "$srcdir/c.sh"

As a side remark, note that it is maybe unnecessary to source the files at stake: it is especially useful if you need to export in the ambient shell session the variables defined in c.sh. Otherwise (if you just need to run c.sh as a standalone script) you may want to replace the script above with:

#!/usr/bin/env bash
# (file b.sh)

srcdir=$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )

"$srcdir/c.sh"

and at the same time:

  • add a shebang such as #!/usr/bin/env bash or #!/bin/bash at the beginning of c.sh
  • set the executable bit of c.sh by doing chmod a+x c.sh
Sign up to request clarification or add additional context in comments.

3 Comments

source "${BASH_SOURCE[0]%/*}"/c.sh is enough in b.sh
@ctac_ Indeed, source "${BASH_SOURCE[0]%/*}"/c.sh would be very OK if we just want to get a relative path :) But if the OP wants to get an absolute path, or in case there is some cd somewhere in the script b.sh before the line source "${BASH_SOURCE[0]%/*}"/c.sh), this wouldn't be enough... And the issue is that commands such as readlink -f to normalize the path are not POSIX... hence that cumbersome command with pwd which should be portable (using bash on macOS or Windows for example)
Actually I believe the command at stake is rather standard and I just saw on Unix SE that it could be improved a bit by adding > /dev/null (to avoid issues with $CDPATH)... I'm going to refine my answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.