1

linux version: MINT 14 netbeans 7.2

I am pretty recent into programming, and I face this difficulty. I have a GUI with 2 jtextarea, one where we type commands, one where the commands output goes (a third one will be implemented for errors (linux, not java) this works ok, for now for my prototype, up to this point:

the output of the command goes into the text area, but it is missing the prompts, I tried many things, but cannot get around to it, I also browsed many faqs, but prompt is used in so many ways, but not in the shell prompt. Help welcome.

I have inserted the code for the process builder class (please ignore for now the best practises like capital letters and so on, it is a prototype only, I will have coders afters if the prototype works)

    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.Reader;
    import java.io.StringWriter;
    import java.io.Writer;

    /**
     *
     * @author bane
     */
    public class myprocessBuilderRunCommand {
        public static String myprocessBuilderRunCommand(String command, boolean waitForResponse) {

    String response = "";

    ProcessBuilder pb = new ProcessBuilder("bash", "-c", command);
    pb.redirectErrorStream(true);

    System.out.println("Linux command: " + command);

    try {
    Process shell = pb.start();

    if (waitForResponse) {

    // To capture output from the shell
    InputStream shellIn;
            shellIn = shell.getInputStream();

    // Wait for the shell to finish and get the return code
    int shellExitStatus = shell.waitFor();
    System.out.println("Exit status" + shellExitStatus);

    response = convertStreamToStr(shellIn);

    shellIn.close();
    }

    }

    catch ( IOException | InterruptedException e) {
    System.out.println("Error occured while executing Linux command. Error Description: "
    + e.getMessage());
    }

    return response;
    }

    /*
    * To convert the InputStream to String we use the Reader.read(char[]
    * buffer) method. We iterate until the Reader return -1 which means
    * there's no more data to read. We use the StringWriter class to
    * produce the string.
    */

    public static String convertStreamToStr(InputStream is) throws IOException {

    if (is != null) {
    Writer writer = new StringWriter();

    char[] buffer = new char[1024];
    try {
    Reader reader;
            reader = new BufferedReader(new InputStreamReader(is,
     "UTF-8"));
    int n;
    while ((n = reader.read(buffer)) != -1) {
    writer.write(buffer, 0, n);
    }
    } finally {
    is.close();
    }
    return writer.toString();
    }
    else {
    return "";
    }
    }
    }
baneyu
  • 11
  • 3
  • all right, no answer, so I update with my findings so far. 1) the prompt is sent on the terminal, not on any of the unix displays. 2) the terminal stream is not part of what can be captured by the tool. 3) I went on to use expectJ, with many difficulties to get it in my java project without using a Maven project. 4) ExpectJ is better, I can now ssh and capture the prompt 5) there seems to be an expect4J also, but I have not investigated it yet NOTE: still having difficulties to treat my responses in expectj.expect() without the linux control characters. – baneyu May 08 '13 at 21:34

1 Answers1

0

From what I understand you were looking for a way to execute commands from java code and display the output in a different window. This is a working example that executes command echo 1 and then returns true for output 1 and false for output 0, (throws Exception in all other cases). That way you can redirect the output anywhere you want.

I also added setting a working path and an environment variable, which is not required for your particular example so you can delete it.

  1. You can copy paste this code as a class, compile it to jar and run it.
  2. It is verified in WSL Ubuntu 16.04.
  3. Setting the workdirectory is verified by setting binaryCommand[0]="touch";and binaryCommand[1]="1";, re-compiling and running the .jar file.

    import java.io.BufferedReader;
    import java.io.File;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.OutputStream;
    import java.io.PrintWriter;
    import java.util.Arrays;
    import java.util.Map;
    import java.util.StringJoiner;
    
    public class GenerateOutput {
    
        /**
         * This code can execute a command and return the binary value of it's output if it 
         * is actually binary.
         * 
         * compile this project into a .jar and run it with for example:
         * java -jar readOutputOfCommand.jar
         * 
         * @param args
         * @throws Exception 
         */
        public static void main(String[] args) throws Exception {
            boolean answerYes = false; // no yes answer to any command prompts is needed.
    
            // to execute a command with spaces in it in terminal, put them in an array of Strings.
            String[] binaryCommand = new String[2];
    
            // write a command that gives a binary output:
            binaryCommand[0] = "echo";
            binaryCommand[1] = "1";
    
            // pass the commands to a method that executes them
            System.out.println("The output of the echo command = "+executeCommands(binaryCommand,answerYes));
        }
    
        /**
         * This executes the commands in terminal. 
         * Additionally it sets an environment variable (not necessary for your particular solution)
         * Additionally it sets a working path (not necessary for your particular solution)
         * @param commandData
         * @param ansYes
         * @throws Exception 
         */
        public static boolean executeCommands(String[] commands,Boolean ansYes) throws Exception {
            String capturedCommandOutput = null;
            System.out.println("Incoming commandData = "+Arrays.deepToString(commands));
            File workingDirectory = new File("/mnt/c/testfolder b/");
    
            // create a ProcessBuilder to execute the commands in
            ProcessBuilder processBuilder = new ProcessBuilder(commands);
    
            // this is not necessary but can be used to set an environment variable for the command
            processBuilder = setEnvironmentVariable(processBuilder); 
    
            // this is not necessary but can be used to set the working directory for the command
            processBuilder.directory(workingDirectory);
    
            // execute the actual commands
            try {
    
                    Process shell = processBuilder.start();
    
                 // capture the output stream of the command
                 BufferedReader reader = new BufferedReader(new InputStreamReader(shell.getInputStream()));
                StringJoiner sj = new StringJoiner(System.getProperty("line.separator"));
                reader.lines().iterator().forEachRemaining(sj::add);
                capturedCommandOutput = sj.toString();
                System.out.println("The output of this command ="+ capturedCommandOutput);
    
                 // here you connect the output of your command to any new input, e.g. if you get prompted for `yes`
                 new Thread(new SyncPipe(shell.getErrorStream(), System.err)).start();
                 new Thread(new SyncPipe(shell.getInputStream(), System.out)).start();
                PrintWriter stdin = new PrintWriter(shell.getOutputStream());
    
                //This is not necessary but can be used to answer yes to being prompted
                if (ansYes) {
                    System.out.println("WITH YES!");
                stdin.println("yes");
                }
    
                // write any other commands you want here
    
                stdin.close();
    
                // this lets you know whether the command execution led to an error(!=0), or not (=0).
                int returnCode = shell.waitFor();
                System.out.println("Return code = " + returnCode);
            } catch (IOException e1) {
                e1.printStackTrace();
            }
            return retrieveBooleanOutput(capturedCommandOutput);
        }
    
        private static boolean retrieveBooleanOutput(String commandOutput) throws Exception {
            if (commandOutput != null && commandOutput.length() == 1) { 
                if (commandOutput.contains("0")) {
                    return false;
                } else if (commandOutput.contains("1")) {
                    return true;
                }
            }
            throw new Exception("The output is not binary.");
        }
    
        /**
         * source: https://stackoverflow.com/questions/7369664/using-export-in-java
         * @param processBuilder
         * @param varName
         * @param varContent
         * @return
         */
        private static ProcessBuilder setEnvironmentVariable(ProcessBuilder processBuilder){
            String varName = "variableName";
            String varContent = "/mnt/c/testfolder a/";
    
            Map<String, String> env = processBuilder.environment();
             System.out.println("Setting environment variable "+varName+"="+varContent);
             env.put(varName, varContent);
    
             processBuilder.environment().put(varName, varContent);
    
             return processBuilder;
        }
    }
    
    
    class SyncPipe implements Runnable
    {   
        /**
         * This class pipes the output of your command to any new input you generated
         * with stdin. For example, suppose you run cp /mnt/c/a.txt /mnt/b/
         * but for some reason you are prompted: "do you really want to copy there yes/no?
         * then you can answer yes since your input is piped to the output of your
         * original command. (At least that is my practical interpretation might be wrong.)
         * @param istrm
         * @param ostrm
         */
        public SyncPipe(InputStream istrm, OutputStream ostrm) {
            istrm_ = istrm;
            ostrm_ = ostrm;
        }
        public void run() {
    
          try
          {
              final byte[] buffer = new byte[1024];
              for (int length = 0; (length = istrm_.read(buffer)) != -1; )
              {
                  ostrm_.write(buffer, 0, length);                
                  }
              }
              catch (Exception e)
              {
                  e.printStackTrace();
              }
          }
          private final OutputStream ostrm_;
          private final InputStream istrm_;
    }
    
a.t.
  • 2,002
  • 3
  • 26
  • 66