9

In bash i get the executing script's parent folder name by this line

SCRIPT_PARENT=`readlink -f ${BASH_SOURCE%/*}/..`

Is there any way to achieve this in zsh in a way that works both in zsh and bash?

Assume i have got a file /some/folder/rootfolder/subfolder/script with the contents:

echo `magic-i-am-looking-for`

I want it to behave this way:

$ cd /some/other/folder
$ . /some/folder/rootfolder/subfolder/script
/some/folder/rootfolder
$ . ../../folder/rootfolder/subfolder/script
/some/folder/rootfolder
$ cd /some/folder/rootfolder
$ . subfolder/script
/some/folder/rootfolder
$ cd subfolder
$ . script
/some/folder/rootfolder

This should work in bash and zsh. My first implements this behavior, but does due to $BASH_SOURCE not work in zsh.

So basically its:

Is there a way to emulate $BASH_SOURCE in zsh, that also works in bash?

don_jones
  • 842
  • 7
  • 13

3 Answers3

14

I now realized that $0 in zsh behaves like $BASH_SOURCE in bash. So using $BASH_SOURCE when available and falling back to $0 solves my problem:

${BASH_SOURCE:-$0}

There is a little zsh edge case left, when sourcing from $PATH like:

zsh> cat ../script
echo \$0: $0
echo \$BASH_SOURCE: $BASH_SOURCE
echo '${BASH_SOURCE:-$0}:' ${BASH_SOURCE:-$0}
zsh> . script
$0: script
$BASH_SOURCE:
${BASH_SOURCE:-$0}: script
bash> . script
$0: bash
$BASH_SOURCE: /home/me/script
${BASH_SOURCE:-$0}: /home/me/script

I could do a which script but this would not play nice with other cases

don_jones
  • 842
  • 7
  • 13
  • 2
    please refer to my answer: http://stackoverflow.com/questions/9901210/bash-source0-equivalent-in-zsh/23259585#23259585 – Hui Zheng Apr 24 '14 at 04:07
9

While it would be easy to do this in zsh, it is just as easy to use pure bash which is able to be evaluated in zsh. If you cannot use any command that may or may not be on your path, then you can only use variable alteration to achieve what you want:

SCRIPT_SOURCE=${0%/*}

This is likely to be a relative path. If you really want the full path then you will have to resort to an external command (you could implement it yourself, but it would be a lot of work to avoid using a very available command):

SCRIPT_SOURCE=$(/bin/readlink -f ${0%/*})

This doesn't depend on your $PATH, it just depends on /bin/readlink being present. Which it almost certainly is.

Now, you wanted this to be a sourced file. This is fine, as you can just export any variable you set, however if you execute the above then $0 will be the location of the sourced file and not the location of the calling script.

This just means you need to set a variable to hold the $0 value which the sourced script knows about. For example:

The script you will source:

echo ${LOCATION%/*}

The script that sources that script:

LOCATION=$0
<source script here>

But given that the ${0%/*} expansion is so compact, you could just use that in place of the script.

Matthew Franglen
  • 4,441
  • 22
  • 32
  • 1
    You are right: `$0` is the answer for zsh. Unfortunately it behaves different in bash when sourcing as bash does not set `$0` – don_jones Feb 24 '13 at 20:55
0

Because you were able to run the command from your $PATH I'll do something like that:

SCRIPT_PARENT=$(readlink -f "$(which $0)/..")

Is that your desired output?

shkschneider
  • 17,833
  • 13
  • 59
  • 112
  • 1
    The command is not necessarily on the path. And it shall also work if the script is sourced into the shell. – don_jones Jul 27 '12 at 10:30