What makes bash forget the environment variable?

My bash knows what PATH is:

pkonl@Hedwig MINGW64 ~/ (main)$ echo $PATH                                                                                             
/mingw64/bin:/usr/bin....           
                  

However, starting a julia somehow makes the bash lose that information:

pkonl@Hedwig MINGW64 ~/ (main)$ julia                                                                                                  
              _                                                                                         
   _       _ _(_)_     |  Documentation: https://docs.julialang.org                                      
  (_)     | (_) (_)    |                                                                                 
   _ _   _| |_  __ _   |  Type "?" for help, "]?" for Pkg help.                                          
  | | | | | | |/ _` |  |                                                                                 
  | | |_| | | | (_| |  |  Version 1.8.1 (2022-09-06)                                                     
 _/ |\__'_|_|_|\__'_|  |  Official https://julialang.org/ release                                        
|__/                   |                                                                                 
                                                                                                         
julia> run(`echo $PATH`)                                                                                 
ERROR: UndefVarError: PATH not defined                                                                   
Stacktrace:                                                                                              
 [1] top-level scope                                                                                     
   @ REPL[1]:1                                                                                           
                                                                                                         

Does anyone know why?

Julia is trying to interpolate the value of a Julia variable PATH

4 Likes

Thats not bash, which produces the error but Julia trying to interpolate PATH:

julia> run(`echo $PATH`)
ERROR: UndefVarError: PATH not defined
Stacktrace:
 [1] top-level scope
   @ REPL[1]:1

julia> PATH="XXX"
"XXX"

julia> run(`echo $PATH`)
XXX
←[0mProcess(`←[4mecho←[24m ←[4mXXX←[24m`, ProcessExited(0))

(ninjad) :slight_smile:

What you want to see or test is this:

julia> run(`bash -c "echo \\\$PATH"`)

There is quite some effort to escape everything which is involved.
Why?
First, run doesn’t call a shell (e.g. bash) but executes the commend directly: Running External Programs · The Julia Language
So, your attempt doesn’t run a bash, but (for me) /bin/echo :

julia> run(`bash -c "which echo"`)
/bin/echo
Process(`bash -c 'which echo'`, ProcessExited(0))

Second, just escaping single with \$ is not enough. It just escapes Julias string interpolation. The bash, which is called sees $PATH and would again put the value of this variable, which results in something like:

echo /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin....

For me, this gives an error because I have some special characters in some paths. So, to avoid this, triple escaping:

\\\$PATH

which is equivalent to

\${PATH}

because you already avoided Julias string interpolation with ${PATH}, so only a single escape is enough now.

1 Like

Thanks, but this does not work. This does:

run(`bash -c "echo \${PATH}"`) 

Edit: Wow, quoting code with backslashes really IS fiddly.

FYI: The ENV isn’t forgotten, you can also do at least this way (only bash interpolates with shell ENVs, and run doesn’t why you did what you did, but bash might not even be available, so this way might be preferable, and more portable):

P=ENV["PATH"]; run(`echo $P`)
2 Likes

This seems to depend on the system. I tried out with WSL2 and this doesn’t work there. I had to use the triple escape version

run(`bash -c "echo \\\${PATH}"`)

here also.

On windows, with julia running in a bash,

julia> run(`bash -c "echo \\\${PATH}"`)                                                                  
${PATH}                                                                                                  
←[0mProcess(`←[4mbash←[24m ←[4m-c←[24m ←[4m'echo \${PATH}'←[24m`, ProcessExited(0))                      
                                                                                                         
julia> 

So, no, this didn’t work.

That didn’t even work on (my Mint) Linux. This works for me:

julia> run(`bash -c "echo \${PATH}"`)

I’m confused why \\ would be needed in WSL2, or why you tried that way. It doesn’t get me the actual path, only

julia> run(`bash -c "echo \\\${PATH}"`)
${PATH}
Process(`bash -c 'echo \${PATH}'`, ProcessExited(0))

I think the point of (bash in) WSL2 is that whatever you do works the same as in Linux, including the default (bash) shell you would run Julia under. I’m curious is anyone here running bash in Windows but not under WSL2? I mean is that possible? Then using Windows binary of Julia, not Linux binary of Julia.

You can interpolate the dict-key access directly too:

run(`echo $(ENV["PATH"])`)
1 Like

I just have to confirm your finding:

Native Debian bash:

julia> run(`bash -c "echo \\\${PATH}"`)
${PATH}
Process(`bash -c 'echo \${PATH}'`, ProcessExited(0))

julia> run(`bash -c "echo \${PATH}"`)
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
Process(`bash -c 'echo ${PATH}'`, ProcessExited(0))

WSL2 (Debian) bash, running native Windows Julia from path
/mnt/c/Users/Oli/AppData/Local/Programs/Julia-1.7.2/bin/julia.exe :

julia> run(`bash -c "echo \\\${PATH}"`)
/usr/local/sbin:/usr/local/bin:...
Process(`bash -c 'echo \${PATH}'`, ProcessExited(0))

julia> run(`bash -c "echo \${PATH}"`)
/bin/bash: -c: line 1: syntax error near unexpected token `('
/bin/bash: -c: line 1: `echo /usr/local/sbin:/usr/local/bin:...:/mnt/c/Program Files (x86)/Common Files/Oracle/Java/javapath: ...'
ERROR: failed process: Process(`bash -c 'echo ${PATH}'`, ProcessExited(2)) [2]

Stacktrace:
 [1] pipeline_error
   @ .\process.jl:531 [inlined]
 [2] run(::Cmd; wait::Bool)
   @ Base .\process.jl:446
 [3] run(::Cmd)
   @ Base .\process.jl:444
 [4] top-level scope
   @ REPL[2]:1

It’s always more complicated as it seems :wink:

1 Like

What about WSL2 running Linux julia?

What happens if you’re running windows inside a Linux VM which is a guest of a Windows bare metal :joy:

My question is about WSL2 running inside Windows 10, running inside Linux VM, hosted by Windows Server bare metal. Better?

Hopefully there’s a fixed point attractor for iteration…

1 Like

This sort of confusion is precisely the reason why using system-dependent shell commands is wrong and you really don’t want to do it for portability.

1 Like

OK, but when I know I have a Linux bash, taking advantage of all those powerful shell commands is a natural choice.

Is there still something I should try out?

Downloaded Generic Linux on x86 inside WSL2 and checked:

julia> run(`bash -c "echo \\\${PATH}"`)
${PATH}
Process(`bash -c 'echo \${PATH}'`, ProcessExited(0))

julia> run(`bash -c "echo \${PATH}"`)
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:...
Process(`bash -c 'echo ${PATH}'`, ProcessExited(0))

Lesson learned:

Don’t use native Windows Julia inside a WSL2 Linux!

2 Likes
2 Likes