Running Bash programs on Moodle CodeRunner
I have been teaching a course at APU that includes Bash scripting. I have a love-hate relationship with Bash. It’s a weird combination of a programming language and an iterative CLI. It’s confusing, easy to make mistakes, and hard to debug, but on the other hand, it’s available on almost all systems. It builds on the power of CLI and CLI tools available in the OS. Easy to write small and useful scripts that can automate your daily painful work. Hence, it’s worth knowing a bit of it even today.
The platform we (APU) use is Moodle. I have been in the MOOC industry for a decade now, and I have heard of Moodle so much, but this is the first time I have used it to run a course. To run a programming course, you will need an easy programming environment to challenge students. In my previous cases, we have used an NSJail-based environment with CourseBuilder (now called Seek), which works really well. But in this case, for Moodle, it’s CodeRunner plugin. It seems fairly easy to use. That said, Bash is not supported out of the box as user language. So I had to use Python to make it possible. This also assumes the environment (CodeRunner/JOBE) has Bash installed, though not directly accessible through API as user language.
import subprocess
script = """{{ TEST.testcode | e('py') }}""" + '\n' + """{{ STUDENT_ANSWER | e('py') }}""" + '\n' + """{{ TEST.extra | e('py') }}"""
input = """{{ TEST.stdin | e('py') }}"""
with open('__prog__.sh', 'w') as outfile:
outfile.write(script)
result = subprocess.run(['/bin/bash', '__prog__.sh'], capture_output=True, text=True, input=input, timeout=5)
stdout = result.stdout.strip()
print(stdout)
The template Python code takes the TEST.testcode and prepends it to the user-entered STUDENT_ANSWER code. It also takes TEST.extra code and appends it. Then, it runs it as a bash script using Python subprocess by passing TEST.stdin as input. Captures STDOUT and prints it for comparison.

Example Question 1: Read an input as score. If the score is greater than or equal to 40, then print P. If the score is less than 40, then print U.
Example Question 2: Write a function called cube. If a number is passed, it returns the cube of that number. For example cube 5 # will return 25

We did about three in-class labs using this. It worked well for all our cases. Though I must say we tried only Bash basics. Maybe there are use cases where this might break, but I think for most of it, this should work.



