I have a simple shell script which prints "Hello world", asks for a number from user and prints that number.
I am trying to run this script from a Java class in linux machine using runtime and process.
However, when I run this Java class in linux machine from commandline using java command, it prints the first 2 lines and hangs at the point of taking input from user. I am not able to pass any input to the script.
Kindly let know how I can run the script interactively via java. Below is my script and java class file:
sample.sh
#!/bin/sh
echo "Hello world"
echo "Enter any number"
read response
echo "The number you entered is: $response"
ExecuteScript.java
package com.scripting;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
public class ExecuteScript {
public static void main(String args[]) {
System.out.println("Java program ran!!");
String[] cmdScript = new String[]{"/bin/bash", "/root/sample.sh"};
Process procScript = null;
try {
procScript = Runtime.getRuntime().exec(cmdScript);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
InputStream ip = procScript.getInputStream();
OutputStream op = procScript.getOutputStream();
BufferedReader reader = new BufferedReader(new
InputStreamReader(ip));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(op));
BufferedReader consoleReader =
new BufferedReader(new InputStreamReader(System.in));
try {
while(reader.readLine() != null) {
if(!reader.ready()) {
String input = consoleReader.readLine();
writer.write(input);
writer.flush();
}else {
System.out.println(reader.readLine());
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Related
The following code has I/O authority in my local PC and runs correctly. However when I've tried to do this on my windows server2012, some problems occured. It can't run python code correctly by using exec, my python cannot give the final result. I think it has no authority to I/O, but why?
Java code:
package test;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
public class test {
private static void generateFile() throws IOException{
BufferedWriter bw = new BufferedWriter(new FileWriter("src/test/input.txt", false));
String eventString = "This is a example";
bw.write(eventString);
bw.close();
}
private static void getFile() throws IOException{
BufferedReader br = new BufferedReader(new FileReader("src/test/output.txt"));
String jsonResults = br.readLine();
br.close();
}
public static void main(String[] args) throws IOException {
generateFile();
Runtime rt = Runtime.getRuntime();
Process pr = rt.exec("python test.py", null, new File("src/test/"));
BufferedReader in = new BufferedReader(new InputStreamReader(pr.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
System.out.println(line);
}
in.close();
try {
pr.waitFor();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
pr.destroy();
}
getFile();
}
}
python code:
f = open('input.txt', 'r')
line = f.readline()
with open('output.txt', 'w') as fw:
fw.write(line)
print("Done!")
ERROR infomation :
Exception in thread "main" java.io.FileNotFoundException: src\test\output.txt (The system cannot find the specified file.)
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(FileInputStream.java:195)
at java.io.FileInputStream.<init>(FileInputStream.java:138)
at java.io.FileInputStream.<init>(FileInputStream.java:93)
at java.io.FileReader.<init>(FileReader.java:58)
at test.test.getFile(test.java:21)
at test.test.main(test.java:49)
Various things here (for the moment more "code quality" hints):
Your poor method is doing way too many things. Example:
Individual "parts", like the following - should all go into a simple helper methods:
String eventString = getJsonEventListInTopic(topicLabel);
FileWriter fw = ...
fw.close();
Meaning: you want to read about the Single Layer Of Abstraction principle
The core point to make progress on your actual question: when you run your python script manually on that windows system (with exactly the same arguments/parameters) on the command line - does that work? You know, it could be something super-simple as "python.exe is not in your path"
I am writing a program in which I want to start a shell in the background, and send and receive the input and output. I already have managed to do this, and can successfully read and write to this process. This is where I run into trouble.
I would like to have a method in ShellManager (see below code) that waits until whatever the process is doing finishes/fails, and returns input to the user.
For example, if I send tar xzf something_that_will_take_a_while.tar.gz,
I can see in the output how it takes its time, and then echoes this:
]0;~
[32mMe#MyComputer [33m~[0m
I already tried blocking the thread until ]0;~ was received, this did not work. (Never returned)
I also tried \u001B, same problem :(
I'm not sure what the symbol is, and can't find much on how to detect when the process returns.
Here is my code:
package buildSystem.shell;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import base.TermConstants;
public class ShellManager {
private InputStream termOut;
private OutputStream termIn;
private ProcessBuilder build;
private Process main;
BufferedReader reader;
BufferedWriter writer;
public ShellManager() {
build = new ProcessBuilder(TermConstants.getShellLocation());
build.redirectErrorStream(true);
}
public void start() throws IOException {
try {
main = build.start();
termOut = main.getInputStream();
termIn = main.getOutputStream();
reader = new BufferedReader (new InputStreamReader(termOut));
writer = new BufferedWriter(new OutputStreamWriter(termIn));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void writeLine(String s) throws IOException {
writer.write(s);
writer.newLine();
writer.flush();
}
public String readNextLine() throws IOException {
return reader.readLine();
}
public void end() {
try {
writeLine("exit\n");
main.waitFor();
termOut.close();
termIn.close();
reader.close();
writer.close();
} catch (IOException | InterruptedException e) {
kill();
}
}
public void kill() {
main.destroyForcibly();
try {
termOut.close();
termIn.close();
reader.close();
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/*THE PART I AM HAVING TROUBLE WITH:*/
public void waitForReturn() {
try {
while(reader.readLine() != "\u001B") {}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Basically, I want a reliable way to detect when a program exits from a bash shell. The bash process will still be running, but the program running from that bash instance will have returned. Because of this I cannot use process.waitFor().
I tried waiting for ]0;~, and then the [32mMe#MyComputer [33m~[0m, which worked until an tar exited with an error code, in which case the two lines would be reversed. I am unsure how to proceed, as detecting that bash has returned to the user should be a relatively easy task.
Thanks for your help!
If this represents the way you have been trying to match output, it's your problem:
while(reader.readLine() != "\u001B") {}
Except in special cases, you have to use the equals() method on String instances:
while (true) {
String line = reader.readLine();
if ((line == null) || "\u001B".equals(line))
break;
}
I'm not sure why you expect ESC and a newline when a process exits though.
I believe you need to call the Process.waitFor() method.
So you need something like:
Process p = build.start();
p.waitFor()
If you are trying to simulate a bash shell, allowing input of a command, executing, and processing output without terminating. There is an open source project that may be a good reference for code on how to do this. It is available on Git. Take a look at the Jediterm Pure Java Emulator.
Thinking about simulating a bash, I also found this example for Piping between processes also be be relevant.
It does show how to extract the output of a process executing and piping that data as the input into another Java Process. Should be helpful.
I'm trying to retrieve the version of python form java using ProcessBuilder.
The command i'm using is:
{process = new ProcessBuilder("C:\\Python27\\python.exe", "-V")}
This command does not return anything.
I'm almost sure this is the correct syntax to retrieve the python version,
{process = new ProcessBuilder("C:\\Python27\\python.exe", "-h")}
returns the python help as expected, but python -V does not return the python version.
package com.x.x.precheck.python;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Arrays;
public class Test {
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Process process = null;
try {
process = new ProcessBuilder("C:\\Python27\\python.exe", "-V")
.start();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
InputStream is = process.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
System.out.printf("Output of running %s is:", Arrays.toString(args));
try {
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
It's because, strangely enough, the python2.7 version is displayed in stderr. in python version 3.4 this behaviour will change see http://bugs.python.org/issue18338
so instead of
InputStream is = process.getInputStream();
you should call
InputStream stderr = process.getErrorStream ();
I tested your code with other programs.It all works fine.for example i gave octave instead of the python and It printed out.Its weird.
Following works on my win8.1 but not on Windows Server 2008. If I close the outputstream then it works on windows server 2008 but that's not what I want. I want to keep open the wmic and process multiple commands.
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
public class WMI {
BufferedWriter writer;
public WMI() {
Process process = null;
try {
process = Runtime.getRuntime().exec("wmic");
new Thread(new Reader(process.getInputStream())).start();
new Thread(new Reader(process.getErrorStream())).start();
writer = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
} catch(Exception e) {
e.printStackTrace();
}
}
public void execute(String cmd) {
try {
writer.write(cmd);
writer.newLine();
writer.flush();
} catch(Exception e) {
e.printStackTrace();
}
}
private static class Reader implements Runnable {
private BufferedReader reader;
public Reader(InputStream is) {
this.reader = new BufferedReader(new InputStreamReader(is));
}
#Override
public void run() {
String line = null;
try {
while((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch(Exception e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
WMI wmi = new WMI();
wmi.execute("service get name");
}
}
Make sure your program (JVM) does not stop before the reader threads get a chance to print anything. Along the lines of:
Thread stdoutReader = new Thread(new Reader(process.getInputStream()));
stdoutReader.setDaemon(false);
stdoutReader.start():
Similarly for the stderr reader. The default (daemon on/off) may be different for the different Windows platforms.
Also make sure the command service get name is valid and does not require further input.
How can I use a command line program from within Java?
I'm trying to pass a graph definition in the dot-language (see Wikipedia) to the interpreter program dot (see GraphViz) through java.
The problem is, that the program does not answer, after I have sent the dot-graph to its InputStream, because it does not know, that I'm finished sending the description.
This is, what I currently have:
package exercise4;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
public class Main {
public static void main(String[] args) {
PrintStream out = System.out;
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
try {
final String start =
"strict graph LSR%1$d {\n" +
" node [shape=circle color=lightblue style=filled];\n\n" +
" {rank=same; A--B [label=6];}\n" +
" {rank=same; C--D [label=12]; D--E [label=4];}\n" +
" A--C [label=4]; B--D [label=4]; B--E [label=9];\n\n" +
" node [shape=record color=\"#000000FF\" fillcolor=\"#00000000\"];\n}\n";
Process dot = Runtime.getRuntime().exec("dot -Tsvg");
in = new BufferedReader(new InputStreamReader(System.in));
out = new PrintStream(dot.getOutputStream(), false, "UTF-8");
out.printf(start, 0);
out.flush();
out.close();
while(in.ready()) {
System.out.println(in.readLine());
}
in.close();
dot.destroy();
} catch (UnsupportedEncodingException ex) {
} catch (IOException ex) {
} finally {
out.close();
}
}
}
Looks as if you are reading from the wrong input stream. Have a look at this answer: https://stackoverflow.com/a/4741987/1686330