1

Our directory structure looks like

/long/dir/name/bin/exec.sh
/long/dir/name/logs
/long/dir/name/input
/long/dir/name/output.

in exec.sh I want to retrieve the root directory (/long/dir/name in this case), store this in a variable so I can use it to refer to $DIR/output, $DIR/input etc.

I got as far as [exec.sh]:

#!/bin/sh
export DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" | sed -e 's,/*[^/]\+/*$,,'
echo "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" | sed -e 's,/*[^/]\+/*$,,'
echo "My Dir: '$DIR'"

This outputs:

/long/dir/name   <-- Which is what I want
My Dir: ''

What is going wrong when assigning it to the DIR variable?

1
  • 1
    ...mind you, using a pipeline (involving sed?!) for this is silly (inefficient, hard-to-read, error-prone); fixing John's advice to use $BASH_SOURCE rather than $0 makes more sense. Commented Nov 7, 2014 at 14:13

2 Answers 2

3

To answer the "what went wrong" question.

You stuck the pipe to sed outside the subshell for the assignment (and technically export var=... isn't an assignment it is a call to export (see ksh get exit status in assignment as an example of this).

Anyway, what happens on that first line therefore is the shell sees

export DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" | sed -e 's,/*[^/]\+/*$,,'

(note the whitespace around the pipe there). And pipelines execute in sub-shells so your export is happening in a su-shell and then being lost.

Stick the sed in the sub-shell and you fix the problem.

export DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd | sed -e 's,/*[^/]\+/*$,,')"
Sign up to request clarification or add additional context in comments.

1 Comment

You're right about the direct problem with the original code, but it's still way more complicated than it needs to be (see my answer).
2

I think you want this:

DIR=${BASH_SOURCE%/*/*}

That is, strip the last two path parts from the script's own path, and use that. Run it through realpath or readlink -f if you need to get a canonical path.

4 Comments

If you are going to suggest readlink it might be better to just suggest readlink $path/../.. and let readlink do the work.
@John DIR=${0%/*/*} gives me 'exec.sh'?
${BASH_SOURCE%/*/*}, rather. $0 isn't a good fit for this use -- as @drjerry's issue above demonstrates.
echo ${BASH_SOURCE%/*/*} in exec.sh still gives ./exec.sh?

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.