direnv/direnv

Question: Why doesn't direnv support this substitution?

msabramo opened this issue · 7 comments

I have this:

❯ cat .envrc
export DOCKER_HOST_IP="${${DOCKER_HOST#tcp://}%:[0-9]*}"

direnv doesn't like this.

❯ cd smdevstack
direnv: loading .envrc
./.envrc: line 2: ${${DOCKER_HOST#tcp://}%:[0-9]*}: bad substitution

❯ echo $DOCKER_HOST_IP


but it works when I manually source the file from my shell (zsh):

❯ source .envrc

❯ echo $DOCKER_HOST_IP
192.168.99.101

Why is that? I guess direnv is limited in the fanciness of what you can use in a .envrc?

If you're curious about the context of why I am trying to do such things in an .envrc, see docker/compose#2915 (comment)

Direnv always executes the .envrc with bash, takes the diff and exposes it to you current shell trough direnv export. That way it can work across shells.

The reason is that bash either doesn't have this feature or it just doesn't work quite the same. http://www.tldp.org/LDP/abs/html/string-manipulation.html

Also note that the direnv stdlib is also injected before executing the .envrc, I know a lot of people are missing this, it might be useful to you. http://direnv.net/#man/direnv-stdlib.1

Ah yes. That makes sense.

❯ bash
marca@marca-mac2:~/dev/surveymonkey/smdevstack$ export DOCKER_HOST_IP="${${DOCKER_HOST#tcp://}%:[0-9]*}"
bash: ${${DOCKER_HOST#tcp://}%:[0-9]*}: bad substitution

Looks like I need to find a more bash-friendly syntax. I'll check out the links you provided for bash and also for the direnv stdlib -- funny I've been using direnv for ages and never realized it had the stdlib. I reread the docs when I hit this issue and discovered it but like you said, I had overlooked it in the past.

Thanks for the quick response and for direnv in general. Awesome tool that I use every day!

Hmmm. It seems like bash supports the same basic primitives for string substitution as zsh, but with zsh it seems possible to do it in one comand. With bash, I had to do it in two steps for it to not complain.

marca@marca-mac2:~/dev/surveymonkey/smdevstack$ echo $DOCKER_HOST
tcp://192.168.99.101:2376
marca@marca-mac2:~/dev/surveymonkey/smdevstack$ export DOCKER_HOST_IP="${DOCKER_HOST#tcp://}"
marca@marca-mac2:~/dev/surveymonkey/smdevstack$ echo $DOCKER_HOST_IP
192.168.99.101:2376
marca@marca-mac2:~/dev/surveymonkey/smdevstack$ export DOCKER_HOST_IP="${DOCKER_HOST_IP%:[0-9]*}"
marca@marca-mac2:~/dev/surveymonkey/smdevstack$ echo $DOCKER_HOST_IP
192.168.99.101

This Stack Overflow answer seems to explain why the one-line version worked in zsh but not in bash.

Cool, glad you found a solution that works for you and you find direnv useful.

I think I need to rework the docs to make the stdlib more obvious. If you have any pointers let me know, I'm kind of blind to the doc.

It seems like this works well:

export DOCKER_HOST_IP=$(echo $DOCKER_HOST | egrep -o '([0-9]{1,3}\.){3}[0-9]{1,3}')

I went ahead and sent a PR to try to make it a bit clearer that the .envrc must be valid bash syntax:

#200