How to execute a interactive shell script using java Runtime?
Asked Answered
L

4

7

I am wondering is there any way to execute following shell script, which waits for user input using java's Runtime class?

#!/bin/bash

echo "Please enter your name:"
read name
echo "Welcome $name"

I am using following java code to do this task but it just shows blank console.

public class TestShellScript {
public static void main(String[] args) {

        File wd = new File("/mnt/client/");
           System.out.println("Working Directory: " +wd);
           Process proc = null;

           try {
               proc = Runtime.getRuntime().exec("sudo ./test.sh", null, wd);

           } catch (Exception e) {
             e.printStackTrace();
             }


}

}

Thing is when I execute above program, I believed it will execute a shell script and that shell script will wait for user input, but it just prints current directory and then exits. Is there any way to do this or it is not possible at all in java?

Thanks in advance

Lentil answered 29/3, 2012 at 14:29 Comment(1)
#4785289Endogenous
S
1

The reason it prints the current dir and exits is because your java app exits. You need to add a (threaded) listener to the input and error streams of your created process, and you'll probably want to add a printStream to the process's output stream

example:



            proc = Runtime.getRuntime().exec(cmds);
            PrintStream pw = new PrintStream(proc.getOutputStream());
            FetcherListener fl = new FetcherListener() {

                @Override
                public void fetchedMore(byte[] buf, int start, int end) {
                    textOut.println(new String(buf, start, end - start));
                }

                @Override
                public void fetchedAll(byte[] buf) {
                }           
            };
            IOUtils.loadDataASync(proc.getInputStream(), fl);
            IOUtils.loadDataASync(proc.getErrorStream(), fl);
            String home = System.getProperty("user.home");
            //System.out.println("home: " + home);
            String profile = IOUtils.loadTextFile(new File(home + "/.profile"));
            pw.println(profile);
            pw.flush();

To run this, you will need to download my sourceforge project: http://tus.sourceforge.net/ but hopefully the code snippet is instructive enough that you can just adapt to J2SE and whatever else you are using.

Spicebush answered 29/3, 2012 at 14:34 Comment(7)
Can you post some example code or link of webpage explaining that with example in detail.Lentil
I tried with your code and downloading your source from SVN, what happens is it waits for input and also I am able to type input on console, but it never passes that input to shell script and programs keep on executing. Ideally how it should behave is after entering name shell script should print name and program should execute.Lentil
So once you get the data, write it into the shell script via printWriter / printStream and then use flush()Spicebush
Thanks for your help, but I am just somewhat confused how to get data user is typing.Lentil
Actually I am just searching for a way to fetch data user is entering, Should I use DataFetcher class, if yes, how can get data using this?Lentil
Yes that's what I'm saying. The code snippet I posted shows exactly how to add a DataFetcher to an InputStream, which System.in isSpicebush
Thanks dude it is working, now I need to take out code from your project that is helpful.Lentil
R
1

If you use a Java ProcessBuilder you should be able to get the Input, Error and Output streams of the Process you create.

These streams can be used to get information coming out of the process (like prompts for input) but they can also be written to to put information into the process directly too. For instance:

InputStream stdout = process.getInputStream ();
BufferedReader reader = new BufferedReader (new InputStreamReader(stdout));

String line;
while(true){
    line = reader.readLine();
    //...

That'll get you the output from the process directly. I've not done it myself, but I'm pretty sure that process.getOutputStream() gives you something that can be written to directly to send input to the process.

Raft answered 29/3, 2012 at 14:36 Comment(0)
F
1

The problem with running interactive programs, such as sudo, from Runtime.exec is that it attaches their stdin and stdout to pipes rather than the console device they need. You can make it work by redirecting the input and output to /dev/tty.

You can achieve the same behaviour using the new ProcessBuilder class, setting up the redirection using ProcessBuilder.Redirect.INHERIT.

Fluke answered 29/3, 2012 at 14:43 Comment(0)
D
0

Note sure at all you can send input to your script from Java. However I very strongly recommend to have a look at Commons Exec if you are to execute external scripts from Java:

Commons Exec homepage

Commons Exec API

Daman answered 29/3, 2012 at 16:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.