Home > Software engineering >  Java Process Builder not executing multiple commands
Java Process Builder not executing multiple commands

Time:10-26

Hi a Java newbie here.

I am currently building a Java application that executes multiple linux commands with Java Process builder.

I am planning to execute a shell scipt, and since it this shell script is an external program that takes about a second to fully execute, let the process sleep for a second and write the result into a txt file.

This is an external program and it must take in "q" to exit the program, so I finally need to type in q in the terminal.

I have gotten help on this community before and the code I constructed with that help is as follows.

public static void Linux(String fileName){

try {
  File dir = new File("/usr/local/bin");
  ProcessBuilder pb = new ProcessBuilder(new String[]{"/bin/bash", "-c", "./test_elanprv2.2.sh > \"$1\"; sleep 1; q", "_", fileName   ".txt"});
  System.out.println("wrote text");
  pb.directory(dir);
  Process start = pb.start();
  start.destroy();
}catch (Exception e){
  e.printStackTrace();
  System.out.println("failed to write text");
}

The process builder does create a txt file but it seems to be empty, and no matter how long I set the sleep to, the programs seems to instanly return the print statement.

It would really be appreciated if anyone could tell me what I am doing wrong.

Thank you in advance!!

CodePudding user response:

As mentioned by @VGR, try using redirectOutput

public static void Linux(String fileName){

try {
   File dir = new File("/usr/local/bin");
   ProcessBuilder pb = new ProcessBuilder(new String[]{"/bin/bash", "-c", "./test_elanprv2.2.sh");
   File output = new File("_", fileName   ".txt");
   pb.redirectOutput(output);
   System.out.println("wrote text");
   pb.directory(dir);
   Process start = pb.start();
   start.destroy();
} catch (Exception e) {
   e.printStackTrace();
   System.out.println("failed to write text");
}

CodePudding user response:

Most of your issues are due to a misunderstanding of how processes work. These concepts are not Java concepts; you would have the same issues in any other language.

First, you are destroying your process before it runs, and possibly before it even gets started. This is because pb.start() starts the process, and then you immediately destroy it without giving it a chance to complete.

You shouldn’t need to destroy the process at all. Just let it finish:

Process start = pb.start();
start.waitFor();

All processes have their own standard input and standard output. Again, this is not a Java concept; this has been a fundamental feature in Unix and Windows operating systems for a long time.

Normally, when a process prints information by writing it to its standard output. That is in fact what Java’s System.out.println does. In Unix shells (and in Windows), the > character redirects the standard output of a process to a file; the program still writes to its standard output, without ever knowing that the operating system is sending that output to a destination other than the terminal. Since it’s a fundamental operating system function, Java can do it for you:

ProcessBuilder pb =
    new ProcessBuilder("/bin/bash", "-c", "./test_elanprv2.2.sh");
pb.redirectOutput(new File(fileName   ".txt"));

Similarly, when a process wants to take input, it normally does so by reading from its standard input. This is not the same as executing another command. When you do this:

./test_elanprv2.2.sh > "$1"; sleep 1; q

You are not sending q to the shell script. The above commands wait for the shell script to finish, then execute a sleep, then try to execute a program named q (which probably doesn’t exist).

Since the test_elanprv2.2.sh shell script probably accepts commands by reading its standard input, you want to send the q command to the standard input of that process:

ProcessBuilder pb =
    new ProcessBuilder("/bin/bash", "-c", "./test_elanprv2.2.sh");
pb.redirectOutput(new File(fileName   ".txt"));

Process start = pb.start();
Thread.sleep(1000);

try (Writer commands = new OutputStreamWriter(start.getOutputStream())) {
    commands.write("q\n");
}

// Caution: Call this AFTER writing commands.  You don't want to write
// to the standard input of a process that has already finished!
start.waitFor();
  • Related