Teaching assistant bash script to automate the process of finding, compiling, and running .java files

Viewed 75

Background:

I posted a question on https://unix.stackexchange.com/questions/469680/teaching-assistant-bash-script-to-automate-the-process-of-finding-compiling-an and received some really good advice. Now I'd like to take my process one step further.

Summary of Design:

I'm a TA in University looking to automate testing my student's java code. I am also using this opportunity to grow in my bash skills because I feel like they could be better. My current bash script looks like this:

#!/bin/bash

list='/Users/ajm/Desktop/170Grading/output/list.txt'
score='/Users/ajm/Desktop/170Grading/output/score.txt'

> "$list"
> "$score"

find "$1" -name '*.java' >> "$list"

exec 3< "$list"

while IFS='' read -r -u 3 line || [ -n "$line" ]
do

    read -p "> $line (Press Enter to continue)"

    echo "the next file is $line" >> "$score"

    open -a "Xcode" "$line" 

    javac -d "/Users/ajm/Desktop/170Grading/runs" "$line" >> class && echo compiled >> "$score" || echo not compiled >> "$score"

    echo "standard in string" | cd "/Users/ajm/Desktop/170Grading/runs" java "$class" >> "$score"
done

Point of Contention

Currently, everything works up until the last line before the done. For some strange reason, the output from the java "$class" is not appended to "$score". Any guidance would be greatly appreciated.

Additional Goals

A) I would like to be able to take in additional parameters for my script so that I don't need to keep editing it for each new assignment. For example in:

find "$1" -name '*.java' >> "$list"

I would like to be able to replace the '*.java' with 'string.java'. I know that I can obtain the string as $2 as a command arg for the script, but '$2.java' does not seem to be the correct way of going about this. As an example: say I only want to look at a subset of .java files that end color.java, I would like to be able to say

bash script.sh directory color

and have that perform the task. If there is no $2, the code should default to '*.java'.

2 Answers

My Solution:

After speaking with my professor I have worked out a solution. I would like to note the new script, and what the problems with the old script were, and what changed we made to make this work:

#!/bin/bash

list=/Users/ajm/Desktop/170Grading/output/list.txt
score=/Users/ajm/Desktop/170Grading/output/score.txt
runs=/Users/ajm/Desktop/170Grading/runs

> "$list"
> "$score"

rm -r "$runs"/*

find "$1" -name "*$3.java" >> "$list"

exec 3< "$list"

while IFS='' read -r -u 3 line || [ -n "$line" ]
do

    read -p "> $line (Press Enter to continue)"

    echo "the next file is $line" >> "$score"

    open -a "Xcode" "$line" 

    javac -d "$runs" "$line" && echo compiled >> "$score" || echo not compiled >> "$score"

    class=$(basename "$line")
    class=${class%.java}

    cd "$runs"

    echo "$2" | java -cp "$runs" ${class} >> "$score"

done

Explanation:

list, score, and runs all refer to paths on my computer, in the future, I'd like to make this solution more general for any computer. The lines:

> "$list"
> "$score"

Reinitialize these paths to be empty. In order to reinitialize the runs folder to be empty we use:

rm -r "$runs"/*

Which recursively removes anything inside the run directory. A word of

Caution: because of the asterisk, if runs is improperly set, you may do irreversible damage to your computer.

The code is the same until here:

class=$(basename "$line")
class=${class%.java}

In this step, we grab only the last item in the class directory, and then we remove the .class part of the name, because running:

java code.class

is really telling the jvm to do:

java code.class.class

and so we will encounter errors.

In the last step we use curly braces instead of quotes {} to refer to the file name:

echo "$2" | java -cp "$runs" ${class} >> "$score"

And other than making the $2 and $3 be assigned at execution as opposed to when the script is run, the code is the same.

I hope that if someone runs into this issue in the future, this answer will be helpful. I will be refactoring a more general purpose script for this usage and I may post it as an addendum in the future.

You're not executing Java. You're doing

 cd "/Users/ajm/Desktop/170Grading/runs" java "$class" >> "$score"

The cd command sees 3 arguments and ignores "java" and "$class".

Try instead:

cd "/Users/ajm/Desktop/170Grading/runs"
echo "standard in string" | java "$class" >> "$score"

Or if your CLASSPATH environment variable doesn't contain . as one of the paths, you may explicitly set the classpath without changing directory:

echo "standard in string" | java -cp "/Users/ajm/Desktop/170Grading/runs" "$class" >> "$score"
Related