Start shell script in background from java program - java

I currently start a shell script from my Java by code looking like this:
ProcessBuilder processBuilder = new ProcessBuilder();
processBuilder.directory("/directory/where/the/script/is/located/");
String[] command = new String[]{"sh", "myScript.sh"};
processBuilder.command(command);
Map<String, String> env = processBuilder.environment();
//tweak the environment with needed additions
env.put(...);
Process p = processBuilder.start();
stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
stdError = new BufferedReader(new InputStreamReader(p.getErrorStream()));
// read the output from the command
String line;
while ((line = stdInput.readLine()) != null)
{
logger.fine(line);
}
p.waitFor();
int returnCode = p.exitValue();
// Return something according to the return code
return ...;
If I now want to start the script and not wait for it to end (and thus losing the ability to return according to return code), but still with being able to tweak the environment beforehand? how should I proceed?
Thank you

Just do the entire thing in a new thread.
Wrap the entire above code in a Runnable and start a Thread for it. Your main code can continue doing something else.
In the runnable once you get the result from the child process use some notify(or observer pattern) to notify interested parties.

Related

Run command line process from Java synchronously

I am running a command-line program (ClamAV virus scanner) from Java as below. I need to run it synchronously since it's running in AWS Lambda and if it goes async, the lambda will terminate early. It seems "many" times it comes out without completing. What is the best way to fix this? I added ugly Thread. Sleep improved the situation a little. I actually don't mind going that route but need to find the exact place where it should sleep. Please help!
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec(command);
BufferedReader inputReader = new BufferedReader(new InputStreamReader(proc.getInputStream()));
BufferedReader errorReader = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
String line;
StringBuilder out = new StringBuilder();
int exitValue = proc.waitFor();
logger.info("Exit Value:" + exitValue);
while ((line = inputReader.readLine()) != null) {
out.append("\n").append(line);
}
if (exitValue != 0) {
while ((line = errorReader.readLine()) != null) {
out.append("\n").append(line);
logger.error(line);
}
}
The method exec executes in a different process as stated by the javadoc:
Executes the specified string command in a separate process.
What you can do is put the main thread in a wait state until you know that the separated thread has completed his task. You can do that using the method waitFor of the Process class:
Causes the current thread to wait, if necessary, until the process represented by this Process object has terminated

How run .sh script with user input from textfield in Java?

I try start .sh script with user input from txtfield.
Idea: user write parametre in txt fild. When push the button and script start with this parametre.
My code:
private void jButton2ActionPerformed(java.awt.event.ActionEvent evt)
{
String valueURL;
valueURL = URLtxt.getText().toString();
ProcessBuilder processBuilder = new ProcessBuilder();
// -- Linux --
// Run a shell command
processBuilder.command("bash", "-c","nikto -h", valueURL,");
try {
Process process = processBuilder.start();
StringBuilder output = new StringBuilder();
BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
output.append(line + "\n");
}
int exitVal = process.waitFor();
if (exitVal == 0)
{
this.hide();
ScanWS sws = new ScanWS() ;
sws.setVisible(true);
An event istener is triggered in UI thread, so the processing must be fast. Your listener implementation waits for an external process, it can freeze your ui. All the process triggering and caring logic must start in a separate Thread.
A process is quite an old construction and it has input/output issue. A process writes something during it's work into a buffer of it's output stream and when the buffer is all filled - the process hungs, waiting for the output stream to make some space.
So, both process.input and process.output processors also must work in separate threads.

How to I exit a while loop after starting a process in Java?

Just found this post (and found the code which I'm also pasting below):
java runtime.getruntime() getting output from executing a command line program
My question is, how do I kill the process? It seems that the code blocks in the while loop. I've tried several options like using a boolean, running all the code in a separate thread and stuff like this, but without any success.
I just want to start an Android emulator and kill it whenever I want.
Runtime rt = Runtime.getRuntime();
String[] commands = {"emulator", "-avd", "jenkins",
"-scale", "96dpi", "-dpi-device", "100"};
Process proc = rt.exec(commands);
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(proc.getInputStream()));
BufferedReader stdError = new BufferedReader(new
InputStreamReader(proc.getErrorStream()));
// read the output from the command
System.out.println("Here is the standard output of the command:\n");
String s = null;
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}
// read any errors from the attempted command
System.out.println("Here is the standard error of the command (if any):\n");
while ((s = stdError.readLine()) != null) {
System.out.println(s);
}
Okay.
Use below code to get The Process ID of that current running thread or Process.
String processName =java.lang.management.ManagementFactory.getRuntimeMXBean().getName();
String ProcessID = processName.split("#")[0];//Process Id
Use that Process ID to kill that Process in your CPU.
I think for that purpose you may wish to write any other trigger or any condition in While loop.

Get output of terminal command using Java

For some terminal commands, they repeatedly output. For example, for something that's generating a file, it may output the percent that it is complete.
I know how to call terminal commands in Java using
Process p = Runtime.getRuntim().exec("command goes here");
but that doesn't give me a live feed of the current output of the command. How can I do this so that I can do a System.out.println() every 100 milliseconds, for example, to see what the most recent output of the process was.
You need to read InputStream from the process, here is an example:
Edit I modified the code as suggested here to receive the errStream with the stdInput
ProcessBuilder builder = new ProcessBuilder("command goes here");
builder.redirectErrorStream(true);
Process process = builder.start();
InputStream is = process.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line = null;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
For debugging purpose, you can read the input as bytes instead of using readLine just in case that the process does not terminate messages with newLine

Capture the output of an external program in JAVA

I'm trying to capture output of an external program using java but I can't.
I have the code to show it, but not to put it into a variable.
I will use, for example, sqlplus to execute my oracle code "into exec.sql"
system/orcl#orcl : user/password/DB name
public static String test_script () {
String RESULT="";
String fileName = "#src\\exec.sql";
String sqlPath = ".";
String arg1="system/orcl#orcl";
String sqlCmd = "sqlplus";
String arg2 = fileName;
try {
String line;
ProcessBuilder pb = new ProcessBuilder(sqlCmd, arg1, arg2);
Map<String, String> env = pb.environment();
env.put("VAR1", arg1);
env.put("VAR2", arg2);
pb.directory(new File(sqlPath));
pb.redirectErrorStream(true);
Process p = pb.start();
BufferedReader bri = new BufferedReader
(new InputStreamReader(p.getInputStream()));
while ((line = bri.readLine()) != null) {
RESULT+=line;
}
System.out.println("Done.");
}
catch (Exception err) {
err.printStackTrace();
}
return RESULT;
}
Because the Process will execute in a new thread it's likely that there is no output or incomplete output available when you come to your while loop.
Process p = pb.start();
// process runs in another thread parallel to this one
BufferedReader bri = new BufferedReader(new InputStreamReader(p.getInputStream()));
// bri may be empty or incomplete.
while ((line = bri.readLine()) != null) {
RESULT+=line;
}
So you need to wait for the process to complete before attempting to interact with it's output. Try using the Process.waitFor() method to pause the current thread until your process has had an opportunity to complete.
Process p = pb.start();
p.waitFor(); // wait for process to finish then continue.
BufferedReader bri = new BufferedReader(new InputStreamReader(p.getInputStream()));
while ((line = bri.readLine()) != null) {
RESULT+=line;
}
This is only a simple approach you could also process the output of the process while it runs in parallel but then you would need to monitor the status of the process i.e. is it still running or has it completed, and the availability of output.
Use Apache Commons Exec, it will make your life much easier. Check the tutorials for information about basic usage. To read the command line output after obtaining an executor object (probably DefaultExecutor), create an OutputStream to whatever stream you wish (i.e a FileOutputStream instance may be, or System.out), and:
executor.setStreamHandler(new PumpStreamHandler(yourOutputStream));

Categories