Reputation: 465
I'm working on automating an interactive command line Java program in bash to validate that the program produces proper output for the input (basically poor-man's unit testing in bash).
For example, if I have a java program that asks the user to enter their full name, and then outputs only their first name, it should look something like this:
Enter your name: John Doe
John
Where "John Doe" was typed in by the user.
A simple bash command to run this might look like this:
OUTPUT=`echo "John Doe" | java NameReader`
or
OUTPUT=`java NameReader <<< "John Doe"`
The trouble with both of these is that $OUTPUT now contains the following:
Enter your name: John
Because the text that was sent to stdin (and its newline accompanying) isn't reproduced in the output of the program the way we would see it in the console.
Ideally, $OUTPUT would contain this:
Enter your name: John Doe
John
But I could live with this:
Enter your name:
John
(The input is omitted entirely, but the output is on a new line, as expected)
Is there a way in bash (without altering the underlying java program) to get the text that is being piped to stdin to also pipe to stdout at the "time" it's read by the java program, so the full interactive session is captured?
(One more note: Some searching indicated that the spawn/expect commands might be helpful, but the system this will run on does not appear to have them available)
Upvotes: 5
Views: 4200
Reputation: 465
Here's what I ended up doing. It's not a complete solution, but it works in this case and may be useful to someone else facing something similar later:
{ sleep 3; echo "John Doe" | tee -a out.txt; } | java NameReader >> out.txt
OUTPUT=`cat out.txt`
rm out.txt
This causes the script to do two things in parallel:
By using tee, the text gets written to both the pipe (which the java program is waiting to read), and to the file. The -a option appends the text to the file instead of overwriting it.
The java program also appends its content to out.txt (using >>).
Then we read the file contents into the OUTPUT variable and delete the file.
This isn't really a complete solution, because...
...So this is the best I've got for now. Better solutions are still invited, of course.
Upvotes: 0
Reputation: 18807
You can use the script
command
script -q -c "java NameReader" log.txt
This will record the input and ouput of the java NameReader
command in the log.txt
file.
Upvotes: 6
Reputation: 651
If your java program is like this:
import java.util.Scanner;
class A {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println(sc.next());
}
}
then you could build a bash script that would parse an input of the form
Enter your name: John
John Doe
to transform it into
Enter your name: John Doe
John
Here is one possible bash script:
#!/bin/bash
arg1Outpt=`eval "$1"`
javaOut=`echo "$arg1Outpt" | eval "$2"`
#prints Enter your name: John\nJohn Doe
echo "${javaOut}"$'\n'"${arg1Outpt}" |
sed 'N; s/\(Enter your name: \)\(.*\)\(\n\)\(.*\)/\1\4\3\2/'
#and this is a multiline sed(man sed) that transforms your
#input into what you want :)
use it like this:
bash pipeCheat.bash 'echo "john doe"' 'java A'
where pipeCheat.bash is the name of the file where you saved the script above.
If you have questions don't hesitate to ask.
Upvotes: 1