public
Last active

Why You Lose OLDPWD in Erlang on MacOSX

  • Download Gist
0_Introduction.md
Markdown

Loss of OLDPWD in Erlang on MacOSX

I was wanting to use OLDPWD in Erlang, since the script that initially calls the application changes directories. However, I noticed it wasn't there:

mac:~ ∴ echo $OLDPWD
/Users/mirell/src/ubuntu/bash
mac:~ ∴ erl
Erlang R15B01 (erts-5.9.1) [source] [64-bit] [smp:4:4] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.9.1  (abort with ^G)
1> os:getenv("OLDPWD").
false
2> 

It worked on Linux (Ubuntu) and SmartOS though. This was incredibly puzzling.

After digging through the source code of Erlang for hours, trying to see if it was somehow discarding certain environment variables, I finally stumbled upon the fact that erl is a shell script:

#!/bin/sh
ROOTDIR=/usr/local/Cellar/erlang/R15B01/lib/erlang
BINDIR=$ROOTDIR/erts-5.9.1/bin
EMU=beam
PROGNAME=`echo $0 | sed 's/.*\///'`
export EMU
export ROOTDIR
export BINDIR
export PROGNAME
exec $BINDIR/erlexec ${1+"$@"}

The fact it was using /bin/sh made me wonder about POSIX compatability, or something of that nature. It eventually turned out that it's entirely due to the fact that MacOSX uses bash for /bin/sh. Ubuntu uses /bin/dash, SmartOS uses /bin/ksh93.

Bash itself resets the OLDPWD environment variable on startup to "save space", not bothering to check if it was already set.

Sigh.

1_MacOSX.sh
Shell
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
# Using /bin/sh
mac:~ ∴ echo $OLDPWD
/Users/mirell/src/bitbucket
mac:~ ∴ sh
sh-3.2$ echo $OLDPWD
 
sh-3.2$
 
# Using /bin/bash
mac:~ ∴ echo $OLDPWD
/Users/mirell/src/ubuntu/bash
mac:~ ∴ bash
mac:~ ∴ echo $OLDPWD
 
mac:~ ∴
 
# /bin/sh symlink (or lack thereof)
mac:~ ∴ ls -l /bin/sh
-r-xr-xr-x 1 root wheel 1371712 Oct 10 2011 /bin/sh
 
# /bin/sh version
mac:~ ∴ /bin/sh --version
GNU bash, version 3.2.48(1)-release (x86_64-apple-darwin11)
Copyright (C) 2007 Free Software Foundation, Inc.
2_Linux_Ubuntu.sh
Shell
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
# Using /bin/sh
mirell@linux:~$ echo $OLDPWD
/home/mirell/src/kerl
mirell@linux:~$ sh
$ echo $OLDPWD
/home/mirell/src/kerl
$
 
# Using /bin/bash
mirell@linux:~$ echo $OLDPWD
/home/mirell/src/kerl
mirell@linux:~$ bash
mirell@linux:~$ echo $OLDPWD
 
mirell@linux:~$
 
# /bin/sh symlink:
mirell@linux:~$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 2011-09-24 13:37 /bin/sh -> dash
mirell@linux:~$
3_SmartOS.sh
Shell
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
# Using /bin/sh
[root@smartos ~]# echo $OLDPWD
/home/jill
[root@smartos ~]# sh
# echo $OLDPWD
/home/jill
 
# Using /bin/bash
[root@smartos ~]# echo $OLDPWD
/home/jill
[root@smartos ~]# bash
[root@smartos ~]# echo $OLDPWD
 
[root@smartos ~]#
 
# /bin/sh symlink
[root@smartos ~]# ls -l /bin/sh
lrwxrwxrwx 1 root root 5 2012-01-26 16:05 /bin/sh -> ksh93
[root@smartos ~]#
bash-3.2variables.c
C
1 2 3 4 5 6
/* According to the Single Unix Specification, v2, $OLDPWD is an
`environment variable' and therefore should be auto-exported.
Make a dummy invisible variable for OLDPWD, and mark it as exported. */
 
temp_var = bind_variable ("OLDPWD", (char *)NULL, 0);
VSETATTR (temp_var, (att_exported | att_invisible));

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.