4

I have a bash script that looks like this:

...
SOME_VARIABLE=$(readlink -f $(dirname ${BASH_SOURCE[0]}))
export SOME_VARIABLE
...

I need to source it from a zsh shell as I need to have all the environment variables it defines.

The issue is that I get this error message because of BASH_SOURCE:

dirname: missing operand
Try 'dirname --help' for more information.
readlink: missing operand
Try 'readlink --help' for more information.
Invalid location:

Constraints: I cannot modify the script.

Question: Can I source a bash script containing BASH_SOURCE from zsh?

3
  • 4
    Source it from a bash shell, then start the zsh shell.
    – Kusalananda
    Nov 1 '18 at 10:31
  • 1
    . <(awk '{gsub(/\${BASH_SOURCE\[0\]}/, FILENAME); print}' /path/to/the/bash/script)
    – mosvy
    Nov 1 '18 at 11:44
  • @mosvy that works for me, I would mark it as accepted if it was an answer instead of a comment
    – rual93
    Nov 1 '18 at 11:54
6

Instead of doing . /path/to/that/script.bash, do:

BASH_SOURCE=/path/to/that/script.bash emulate ksh -c '. "$BASH_SOURCE"'

emulate ksh -c '...' runs the code in ksh emulation (so that for instance, array indices start at 0 like in bash) and also makes sure all functions defined within inherit that emulation mode.

$BASH_SOURCE in bash refers to the file being sourced, so we preseed that variable with the path of the script.

The zsh equivalent of that bash code would be:

export SOME_VARIABLE=$0:h:P

(:h giving the head like in csh (the equivalent of dirname), and :P the equivalent of GNU readlink -f).

0

Cool; I had a similar issue -- which I solved by other means, after giving it a second thought --, but this question is quite interesting actually. And the solution quite elegant (I think so).

The main/real question (AFAIU) is:

I need to source it from a zsh shell as I need to have all the environment variables it defines.

, where it is the Bash script.

The fact that the script uses BASH_SOURCE is actually secondary; The script is Bash, period. We may be consider it a "black-box", and all we wanna do is to figure out what variables are being defined (or modified) there.

  • The script has to be source'd on Bash.

That being said, what we have to do is to (from inside a Bash interpreter)

  1. buffer the initial state of the environment,
  2. source the script,
  3. buffer the afterwards state of the environment,
  4. diff the buffers.

And you/we should have the new/modified variables printed out.

The proposed SOLUTION -- the above steps -- look like:

% bash -c 'buf1=$(env|sort) && source bashrc && buf2=$(env|sort) && diff <(echo "$buf1") <(echo "$buf2")'

, where bashrc is the name of the supposed script.

Notice that this actually works for any shell (zsh, csh, ksh, etc), as long as Bash is installed and the version is compatible with the script (most likely to happen, but worth noting).

As an EXAMPLE, I have here the following script -- I'm calling it bashrc:

#!/bin/bash
HERE=$(cd `dirname $BASH_SOURCE`; pwd)
PATH="${HERE}/bin:$PATH"
export HERE
export PATH

, which defines a new variable -- $HERE -- and a modifies an existing one -- $PATH. I put this script in my /tmp directory. The above command gives me:

6a7
> HERE=/tmp
15c16
< PATH=/Users/chbrandt/bin/links:/Users/chbrandt/bin/links:/Users/chbrandt/bin/links:/opt/miniconda3/bin:/opt/miniconda3/condabin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
---
> PATH=/tmp/bin:/Users/chbrandt/bin/links:/Users/chbrandt/bin/links:/Users/chbrandt/bin/links:/opt/miniconda3/bin:/opt/miniconda3/condabin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin

Sweet, isn't it? ...Now you do some post-proc (inside your zsh, for instance) to handle the symbols and whatever else and that's it ;)

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.