Process variable output not printed - java

I want a solution for printing value of process variable p. How can we print value of p? Currently value of p is: java.lang.UNIXProcess#727896
public class shellscript{
public static void main(String[] args) {
Runtime r = Runtime.getRuntime();
Process p = null;
String cmd[] = {
"/bin/bash",
"/home/aminul/myscript"
};
try {
p = r.exec(cmd);
System.out.println("testing..." + p);
System.out.println(p);
}
catch (Exception e) {
e.printStackTrace();
}
}
}

If you want to log the standard output and the exit code of the process, try the following:
public static void main(String[] args) throws Exception
{
final Runtime r = Runtime.getRuntime();
final String cmd[] = { "/bin/bash", "/home/aminul/myscript" };
try
{
final Process p = r.exec(cmd);
new Thread()
{
public void run()
{
BufferedReader br = null;
try
{
br = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = br.readLine();
while (line != null)
{
System.out.println(line);
line = br.readLine();
}
}
catch (final Exception e)
{
e.printStackTrace();
}
finally
{
if (br != null)
try
{
br.close();
}
catch (final IOException ioe)
{
ioe.printStackTrace();
}
}
};
}.start();
p.waitFor();//wait for process to terminate
System.out.println("Exit code: "+p.exitValue());
}
catch (Exception e)
{
e.printStackTrace();
}
}
Of course, if you want to log the ErrorStream as well, you will have to start another thread.

Process don't have name attribute. But you can use pid.
You can try it in this way
Field field=p.getClass().getField("pid"); // use reflection since pid is private
System.out.println(field);
But you can't use
System.out.println(p)
Since Process don't have a override toString() method

Related

close thread which is blocked while reading from inputStream

here is code
private static class NgrokRunner implements Runnable {
private InputStream inputStream;
private boolean doStop = false;
public NgrokRunner(InputStream inputStream) {
this.inputStream = inputStream;
}
#Override
public void run() {
// TODO Auto-generated method stub
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
try {
while((line = reader.readLine()) != null) {
System.out.println(line);
if (keepRunning()) {
continue;
} else {
System.out.println("break ----");
break;
}
}
} catch (Exception e) {
//TODO: handle exception
System.out.println("Ngrok exception");
}
}
public synchronized void doStop() {
this.doStop = true;
}
private synchronized boolean keepRunning() {
return this.doStop == false;
}
}
and i started above thread like this
ProcessBuilder processBuilder = new ProcessBuilder();
processBuilder.command("ngrok", "http","8080", "--log=stdout");
try {
Process process = processBuilder.start();
NgrokRunner runner = new NgrokRunner(process.getInputStream());
Thread ngrokThread = new Thread(runner);
ngrokThread.start();
for (int i = 0; i < 4; i++) {
System.out.println(i);
Thread.sleep(10L * 100L);
}
//System.out.println("It works");
runner.doStop();
} catch (Exception e) {
//TODO: handle exception System.out.println(e);
}
But in while loop my child thread which is reading input from ngrok , blocking and even after calling doStop() it never reached at if condition where i am checking bool flag to exit from thread.
Well can anyone suggest me logic to achieve my ideal situation.
what i want is "Run ngrok server through binary file of ngrok in a thread and close the thread/ngrok whenever i want ( like when user wants through a pause/end button )"
ok so i solved it and here is final solution
run() code :
#Override
public void run() {
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
try {
while(!Thread.interrupted()) {
if (!reader.ready()) {
try {
Thread.sleep(1000);
continue;
} catch (InterruptedException e) {
//TODO: handle exception
System.out.println("We got interrupted");
return;
}
}
line = reader.readLine();
System.out.println(line);
}
} catch (IOException e) {
//TODO: handle exception
System.out.println("Ngrok exception" + e);
}
}
Now from main thread
try {
process = processBuilder.start();
NgrokRunner runner = new NgrokRunner(process.getInputStream());
ngrokThread = new Thread(runner);
ngrokThread.start();
for (int i = 0; i < 8; i++) {
System.out.println(i);
Thread.sleep(1000);
}
ngrokThread.interrupt();
} catch (Exception e) {
//TODO: handle exception
System.out.println(e);
}

Run a shell file in java

In Java you can call a shell file like this:
public class Shell {
private static Shell rootShell = null;
private final Process proc;
private final OutputStreamWriter writer;
private Shell(String cmd) throws IOException {
this.proc = new ProcessBuilder(cmd).redirectErrorStream(true).start();
this.writer = new OutputStreamWriter(this.proc.getOutputStream(), "UTF-8");
}
public void cmd(String command) {
try {
writer.write(command+'\n');
writer.flush();
} catch (IOException e) { }
}
public void close() {
try {
if (writer != null) {
writer.close();
if(proc != null) {
proc.destroy();
}
}
} catch (IOException ignore) {}
}
public static void exec(String command) {
Shell.get().cmd(command);
}
public static Shell get() {
if (Shell.rootShell == null) {
while (Shell.rootShell == null) {
try {
Shell.rootShell = new Shell("su"); //Open with Root Privileges
} catch (IOException e) { }
}
}
return Shell.rootShell;
}
}
Shell.exec("echo " + bt.getLevel() + " > "+ flashfile);
right.
but I have a shell which giving an argument after executing it.
how can I pass that argument? I don't want user type anything to run this shell file. in another word, I want to fully automate a shell file.
If you want to automate a shell file with a Java programme, this can be done. You could even pipe a series of commands to this programme saved in a file and executing these as a batch.
You can execute commands batches of commands from like this:
java -cp experiments-1.0-SNAPSHOT.jar ConsoleReader < commands.txt
commands.txt is a file with a series of commands:
cmd /k date
cmd /k dir
netstat
ipconfig
Or you can with the same programme allow the user to execute commands on the command line.
Below you can find a sample programme which you can compile and be run in the above described manner.
What does it do?
It hooks a java.util.Scanner to the console input and consumes each line.
Then it spawns two threads which listen to the error and input streams and write out either to stderr or stdin.
Empty lines on the console are ignored
If you type "read " it will execute the commands on that file.
Source:
public class ConsoleReader {
public static void main(String[] args) throws IOException, DatatypeConfigurationException {
try(Scanner scanner = new Scanner(new BufferedInputStream(System.in), "UTF-8")) {
readFromScanner(scanner);
}
}
private static final Pattern FILE_INPUT_PAT = Pattern.compile("read\\s*([^\\s]+)");
private static void readFromScanner(Scanner scanner) {
while (scanner.hasNextLine()) {
try {
String command = scanner.nextLine();
if(command != null && !command.trim().isEmpty()) {
command = command.trim();
if("exit".equals(command)) {
break; // exit shell
}
else if(command.startsWith("read")) { // read from file whilst in the shell.
readFile(command);
}
else {
Process p = Runtime.getRuntime().exec(command);
Thread stdout = readFromStream(p.getInputStream(), System.out, "in");
Thread stderr = readFromStream(p.getErrorStream(), System.err, "err");
stdout.join(200);
stderr.join(200);
}
}
}
catch(Exception e) {
Logger.getLogger("ConsoleReader").log(Level.SEVERE, String.format("Failed to execute command %s", e));
}
}
}
private static void readFile(String command) throws FileNotFoundException {
Matcher m = FILE_INPUT_PAT.matcher(command);
if(m.matches()) {
String file = m.group(1);
File f = new File(file);
if (f.exists()) {
try (Scanner subScanner = new Scanner(f)) {
readFromScanner(subScanner);
}
}
}
else {
System.err.printf("Oops, could not find '%s'%n", command);
}
}
private static Thread readFromStream(InputStream stdin, PrintStream out, String name) throws IOException {
Thread thread = new Thread(() -> {
try (BufferedReader in = new BufferedReader(new InputStreamReader(stdin))) {
String line;
while ((line = in.readLine()) != null) {
out.println(line);
}
} catch (IOException e) {
Logger.getLogger("ConsoleReader").log(Level.SEVERE, "Failed to read from stream.", e);
}
}, name);
thread.setDaemon(true);
thread.start();
return thread;
}
}
Runtime.getRuntime().exec("src/[FILE LOCATION]");
I think this is the command you're looking for. Let me know if it works!

How to manage ProcessBuilder for multiple OS?

I would like to manage a Shell executor and i have some problems with Windows (not a surprise).
No pb to detect OS, no pb to start Process with ProcessBuilder, no pb to code a StreamGobbler.
But when i want to test it with JUnit, i have a strange behavior...
If i put "cmd.exe" and "/C" commands for Windows, my CMD script is not working. Without all is perfect.
Where is the problem ?
If tomorrow i want to start an exe, i think cmd.exe /c will be necessary completed with start and path to exe.
My Shell executor:
public static boolean execCmd(List<String> cmd, Map<String, String> env, File workingDir, GobblerListener gobblerListener) {
boolean result = false;
if (isWindows()) {
//cmd.add(0, "cmd.exe");
//cmd.add(1, "/C");
} else if (isUnixSolaris()) {
cmd.add(0, "/bin/ksh");
cmd.add(1, "-c");
} else {
logger.debug(ResourceBundle.getBundle(bundleName).getString("system.env.unknown"));
return result;
}
ProcessBuilder pb = new ProcessBuilder(cmd);
Map<String, String> envp = pb.environment();
for (Map.Entry<String, String> entry : env.entrySet()) {
envp.put(entry.getKey(), entry.getValue());
}
if (workingDir != null) {
pb.directory(workingDir);
}
pb.redirectErrorStream(true);
Process p = null;
try {
p = pb.start();
StreamGobbler outputGobbler = new StreamGobbler(p.getInputStream(),
gobblerListener);
outputGobbler.start();
p.waitFor();
outputGobbler.join();
int exitValue = p.exitValue();
result = (exitValue == 0 ? true : false);
} catch (InterruptedException ex) {
logger.error(ResourceBundle.getBundle(bundleName).getString(
"system.env.exec.interrupted"));
} catch (IOException e) {
logger.error(
ResourceBundle.getBundle(bundleName).getString(
"system.env.exec.exception"), e);
} finally {
if (p != null) {
p.destroy();
}
}
return result;
}
Here my StreamGobbler:
public class StreamGobbler extends Thread {
private static final Logger logger = LoggerFactory.getLogger(GobblerListener.class);
public interface Listener {
public void onLine(String line);
}
private Listener listener = null;
private InputStream is = null;
private BufferedReader reader = null;
public StreamGobbler(InputStream is, Listener onLineListener) {
this.is = is;
this.listener = onLineListener;
}
#Override
public void run() {
// keep reading the InputStream until it ends (or an error occurs)
try {
reader = new BufferedReader(new InputStreamReader(is));
try {
String line = reader.readLine();
while (line != null) {
if (listener != null && !line.trim().isEmpty())
listener.onLine(line);
line = reader.readLine();
}
} finally {
reader.close();
}
} catch (IOException e) {
logger.error("", e);
}
}
}
Thank you.

DOSBox commands through Java Program-word gets removed

String run="c:\\Program Files\DOSBox-0.74\dosbox.exe dosbox -c mount c c:\games";
The word c c:\games gets removed.
Please advise how do I prevent this? Should I use a literal to insert the spaces in the command?
A little bit of experimentation...
public class Test {
public static void main(String[] args) {
try {
ProcessBuilder pb = new ProcessBuilder("C:\\Program Files (x86)\\DOSBox-0.74\\DOSBox.exe", "dosbox", "-c", "mount c c:\\games");
pb.redirectError();
Process p = pb.start();
new Thread(new InputStreamConsumer(p.getInputStream())).start();
System.out.println("Have exited with " + p.waitFor());
} catch (IOException | InterruptedException exp) {
exp.printStackTrace();
}
}
public static class InputStreamConsumer implements Runnable {
private InputStream is;
public InputStreamConsumer(InputStream inputStream) {
is = inputStream;
}
#Override
public void run() {
int in = -1;
try {
while ((in = is.read()) != -1) {
System.out.print((char) in);
}
} catch (IOException exp) {
exp.printStackTrace();
}
}
}
}

Pass parameter to processbuilder outputstream in different class

I am just trying to control processbuilder inputstream and outputstream from different class
It is main class
public class Controller
{
public static void main(String[]args)
{
Runner r=new Runner("Test");
r.activateInput();
r.setInput("Test");
}
}
It is other class to run process
import java.io.*;
public class Runner
{
boolean activeInput=true;
boolean active=true;
String input;
public Runner(String command)
{
try {
// create a new process
System.out.println("Creating Process...");
ProcessBuilder compile = new ProcessBuilder("java","TestOut");
compile.directory(new File("C:/Users/abhishek221192/Documents/Socket"));
Process process = compile.start();
OutputStream stdin = process.getOutputStream ();
InputStream stderr = process.getErrorStream ();
InputStream stdout = process.getInputStream ();
final BufferedReader reader = new BufferedReader (new InputStreamReader(stdout));
BufferedReader error = new BufferedReader (new InputStreamReader(stderr));
final BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(stdin));
//final Scanner scan=new Scanner(System.in);
Thread T=new Thread(new Runnable() {
#Override
public void run() {
while(active)
{
if(activeInput)
System.out.println(activeInput+" "+input);
String data ="Abhi";
data += "\n";
try {
if(activeInput){
writer.write(data);
writer.flush();
activeInput=false;
}
//
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
} );
T.start();
T.setName("Input");
Thread T1=new Thread(new Runnable() {
#Override
public void run() {
String line;
try{
while ((line = reader.readLine ()) != null) {
System.out.println(line);
}} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} );
T1.start();
T1.setName("Output");
/*
String line;
while ((line = error.readLine ()) != null) {
System.out.println(line);
}
*/
//stdout.close();
//error.close();
//T.stop();
//stdin.close();
//System.err.println("stdin closed");
active=false;
// close the output stream
System.out.println("Closing the output stream...");
//testProcessBuilder();
} catch (Exception ex) {
System.out.println("Error"+ex.getMessage());
}
}
public void activateInput()
{
this.activeInput=true;
System.out.println("active"+activeInput);
}
public void setInput(String input)
{
this.input=input;
}
}
It is TestOut code it include only one input statement
TestOut.java
import java.util.*;
public class TestOut
{
public static void main(String[]args)
{
Scanner sc=new Scanner(System.in);
System.out.println("Output hello TestOut");
System.out.println("Output1 "+sc.nextLine());
}
}
I am geting this output
Creating Process...
true null
Closing the output stream...
activetrue
Output hello TestOut
Output1 Abhi
r.setInput(); is not setting value
Couple of changes i made to make it work. the main problem with this piece of code is concurrency issues as two threads are working on same set of data. activeInput is being modified by Controller and by thread T
Change 1:
public synchronized void activateInput(boolean activate) {
this.activeInput = activate;
System.out.println("active" + activeInput);
}
if (activeInput) {
writer.write(data);
writer.flush();
activateInput(false);
}
declared method activateInput synchronized and replaced activateInput = false with the method call in thread T
Change 2:
// active = false;
commented out this line at the end of Runner() method because it is stopping the writer Thread unnecessarily.
Change 3:
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Added this at the end of Writer Thread's while loop to give writer Thread T some breathing space and to give it a chance on reading the values.
Output:
Here is the output i got:
Creating Process...
activetrue
Output hello TestOut
true Test
activefalse
Output1 Abhi
Hope this helps.

Categories