Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Capturing output and input of interactive program with bash

Tags:

linux

bash

shell

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)

like image 452
jthurman Avatar asked May 18 '16 17:05

jthurman


People also ask

How do you capture the output of a shell script in a variable?

To store the output of a command in a variable, you can use the shell command substitution feature in the forms below: variable_name=$(command) variable_name=$(command [option ...] arg1 arg2 ...) OR variable_name='command' variable_name='command [option ...]

How do I create an interactive bash script?

Scripts may be forced to run in interactive mode with the -i option or with a #!/bin/bash -i header.


2 Answers

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.

like image 182
Adam Avatar answered Sep 21 '22 12:09

Adam


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.

like image 22
Simonlbc Avatar answered Sep 23 '22 12:09

Simonlbc