Godot: OS.execute trouble with shell evaluation ("export PATH=test && echo $PATH" doesn't work)

Created on 25 Mar 2020  Â·  7Comments  Â·  Source: godotengine/godot

Godot version:
3.2.1

OS/device including version:
macos

Issue description:
OS.execute("/bin/bash", ['-c',"export PATH=test && echo $PATH"], true, output,true)
print(output)
print result
[/usr/bin:/bin:/usr/sbin:/sbin
]
don't work

Steps to reproduce:

Minimal reproduction project:

discussion documentation enhancement porting

Most helpful comment

I'll keep it open for now as we might want to change the method, or at least improve the documentation to mention this caveat.

All 7 comments

It also doesn't work in Bash...

$ /bin/bash -c "export PATH=test && echo $PATH"
/home/akien/Projects/godot/emscripten/emsdk:/home/akien/Projects/godot/emscripten/emsdk/upstream/emscripten:/home/akien/Projects/godot/emscripten/emsdk/node/12.9.1_64bit/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games:/usr/lib64/qt5/bin:/usr/lib64/qt4/bin:/home/akien/.cargo/bin:/home/akien/.local/bin:/home/akien/bin:/home/akien/.cargo/bin

Actually it works when using single quotes to prevent shell expansion:

$ /bin/bash -c 'export PATH=test; echo $PATH'
test

The problem is that we use double quotes to enclose arguments passed to the executable (here /bin/bash), which means that shell variables get expanded. That's likely what most users would expect, but in this case it makes things tricky.

https://github.com/godotengine/godot/blob/5fede4a81c67961c6fb2309b9b0ceb753d143566/drivers/unix/os_unix.cpp#L283-L296

You can work it around by closing the double-quoted string and concatenating with a single-quote enclosed string:

OS.execute("/bin/bash", ['-c', "\"'export PATH=test && echo $PATH'\""], true, output, true)

I'm not sure what we can do to improve this. One solution would be to switch to using single quotes by default (no shell expansion), and then add a boolean parameter to toggle shell expansion (thus using double quotes as delimiter instead of single quotes).

/bin/bash -c 'export PATH=test; echo $PATH'
gdscript don't work
OS.execute("/bin/bash", ['-c','export PATH=test && echo $PATH'], true, output,true)

[/usr/bin:/bin:/usr/sbin:/sbin
]

The problem is that we use double quotes to enclose arguments passed to the executable (here /bin/bash), which means that shell variables get expanded. That's likely what most users would expect, but in this case it makes things tricky.

https://github.com/godotengine/godot/blob/5fede4a81c67961c6fb2309b9b0ceb753d143566/drivers/unix/os_unix.cpp#L283-L296

You can work it around by closing the double-quoted string and concatenating with a single-quote enclosed string:

OS.execute("/bin/bash", ['-c', "\"'export PATH=test && echo $PATH'\""], true, output, true)

I'm not sure what we can do to improve this. One solution would be to switch to using single quotes by default (no shell expansion), and then add a boolean parameter to toggle shell expansion (thus using double quotes as delimiter instead of single quotes).

OS.execute("/bin/bash", ['-c', "\"'export PATH=test && echo $PATH'\""], true, output, true)
That's right.

I'll keep it open for now as we might want to change the method, or at least improve the documentation to mention this caveat.

So @bleeptrack and I just stumbled over this problem – we definitely had expected that OS.execute would pass the arguments to the command literally, without any modification. A more stable implementation (using C's execv?) would sure be nice!

@akien-mga, your workaround was helpful and worked, thanks! To preserve single quotes inside the command, we ended up replacing all of them by '"'"', like this:

var command = "echo \"hello 'world'\""
command = '"\''+command.replace("'", "'\"'\"'")+'\'"'
OS.execute("/bin/bash, ["-c",  command])
Was this page helpful?
0 / 5 - 0 ratings