pysh - a script that's valid python AND valid bash?!
“God is dead. God remains dead. And we have killed him. How shall we comfort ourselves, the murderers of all murderers?”
While I haven’t found the motivation to resume writing about my fractal finding
and circle packing endeavors, I was recently curious as to whether or not it
would be possible to write a script which could be executed by both python
and
bash
, and produce different output in each case.
Long story short, it’s possible and here’s a script to demonstrate it:
"""true"
# Exit on error in bash
# proves that this is perfectly valid bash!
set -e
echo hello from bash!
exit
"""
print("hello from python!")
Here’s what it would look like when run:
$ cat cursed.pysh
"""true"
echo hello from bash!
exit 0
"""
print("Hello from python!")
$ bash cursed.pysh
hello from bash!
$ python3 cursed.pysh
Hello from python!
What can you do with this?
You can do something absolutely cursed like the following:
"""true"
set -e
# ... some bash stuff ...
python3 $0 # evil!!!
# ... more bash stuff ...
exit
"""
# python stuff!?!
This could be useful if you had some program that was mostly bash or mostly python and you just wanted to briefly use the other language for something. Maybe it would be nice to just have it all in one file for some reason. There’s no good use of this to be honest.
How does it work?
When I started thinking about this I realized that one key piece of syntax that would make this possible is that in python, anything quoted in global scope is effectively a comment. Whereas in bash, strings are interpreted as commands.
This brought me to implement this initial prototype:
"true"
This script will have effectively the same behavior under python and bash - it will produce no visible output and exit. However that’s no fun. The next step was to get bash to actually execute something. This is also not that difficult:
"echo" "hello" "bash"
but what if we want python to execute something as well? The following won’t ‘work’ as bash will throw a syntax error:
"echo" "hello" "bash"
print("hello python!")
$ cat > broken.pysh
"echo" "hello" "bash"
print("hello python!")
$ bash broken.pysh
hello bash
broken.pysh: line 3: syntax error near unexpected token `"hello python!"'
broken.pysh: line 3: `print("hello python!")'
So we need bash to exit before it interprets the python:
$ cat > working.pysh
"echo" "hello" "bash"
"exit" "0"
print("hello python!")
$ bash working.pysh
hello bash
$ python3 working.pysh
hello python!
However, having to quote literally every single operator is pretty cumbersome. There must be a better way!
This got me thinking about triple quotes. In python triple quotes let you define multi-line strings. However, bash uses a very different syntax for multi-line string literals. Could a bash script be embedded in a triple quoted region?
$ cat > quotes.pysh
"""
echo hello from bash!
"""
print('hello from python!')
$ bash quotes.pysh
quotes.pysh: line 3: $'\necho hello from bash!\n': command not found
quotes.pysh: line 4: syntax error near unexpected token `'hello from python!''
quotes.pysh: line 4: `print('hello from python!')'
$ python3 quotes.pysh
hello from python!
This fails because bash is looking for something to close what it sees as a second set of quotes on the first line. What happens if we give it something to close the quotes?
$ cat > quotes.pysh
""""
echo hello from bash!
"""
print('hello from python!')
$ bash quotes.pysh
quotes.pysh: line 1: : command not found
hello from bash!
quotes.pysh: line 3: unexpected EOF while looking for matching `"'
quotes.pysh: line 5: syntax error: unexpected end of file
$ python3 quotes.pysh
hello from python!
Now the bash script executes - but with some syntax errors that it conveniently
ignores. But what if we want both interpreters to not return any syntax errors?
Looking at the bash syntax errors, it needs the quotes on the first line to
resolve to some valid bash and it needs to exit before processing the closing
triple quotes. The shortest bash command that produces no side-effects is
true
, which gives us the final program:
"""true"
echo hello from bash!
exit 0
"""
print("hello from python!")
Code golf challenge?
Now that we know this is possible, what is the shortest possible program that is both valid python and valid bash, and satisfies these requirements:
- no bash syntax errors at runtime
- no python syntax errors at runtime
- no matter which interpreter is used something must be printed to stdout
- what is printed must be different between the two languages
- both interpreters must exit with a status code of 0
Here’s my solution if you’re interested:
Solution
"""echo" 0;exit<br>
""";print(1)