How do I make my program run and interact with shell program? - java

There is a program I run in Ubuntu terminal, called ProgramABC, which reads a query until user presses CTRL+D, and then writes some data to the standard output. It works perfectly:
/path/ProgramABC >> file.txt [enter]
<here I write my query> [enter]
<and I press CTRL+D>
<data is written to file.txt and ProgramABC closes automatically>
I want to run it from Java. My code doesn't work - it creates the file.txt, but it's empty, so I guess something is wrong with passing my query to the process, and therefore to ProgramABC. What do I do wrong? Here is a part of my code:
ProcessBuilder builder = new ProcessBuilder("bash","-c","/path/program ABC >> file.txt");
builder.directory(new File("/another/path/"));
Process process = builder.start();
OutputStream stdin = process.getOutputStream();
InputStream stdout = process.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(stdout));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(stdin));
writer.write("<my query here>");
writer.write((char)4); //it's CTRL+D, right?
writer.flush();
writer.close();

Related

running a shell script with user interaction from java

I'm trying to use a shell script in a java file.
The script runs then prints out the content of a file, and asks the user if its ok to continue
I can start the script off with this and see some output:
try {
process = processBuilder.start();
process.getOutputStream();
process.getInputStream();
process.getErrorStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String output_line = "";
while ((output_line = reader.readLine()) != null) {
System.out.println(output_line);
}
but I think when the file is closed it drops out of the while loop.
I was hoping to see "OK to proceed?" but it's just getting stuck on the last line of the file.
is there a way to keep reading from the command line until the script ends?

Why does BufferedReader fail if BufferedWriter is still open?

I am trying to run a .exe file from a java application and would like to be able to use it (for now) like a terminal where i can write to the .exe then read back from it before writing it again.
My issue is that the code only works when the writer is closed before the reader attempts to read from the inputstream.
String line = "", prev = "";
Scanner scan = new Scanner(System.in);
ProcessBuilder b = new ProcessBuilder("myexe");
b.redirectErrorStream(true);
Process p = b.start();
OutputStream stdin = p.getOutputStream();
InputStream stdout = p.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(stdout));
System.out.println ("->");
while (scan.hasNext()) {
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(stdin));
String input = scan.nextLine();
if (input.trim().equals("exit")) {
writer.write("C");
} else {
writer.write(input);
}
writer.flush();
//writer.close();
while ((line = reader.readLine ()) != null) {
System.out.println ("[Stdout] " + line);
if (line.equals(prev)){
break;
}
prev = line;
}
reader.close();
}
So my question is, am i doing something wrong with the ProcessBuilder? I have read about not reading the output correctly can cause the system to hang. But this doesnt explain why it hangs when the writer is still open?
The issue was actually with my C compiled .exe. When it was running, the application was printing an output, therefore working in cmd terminal however i had not flushed the buffer after each command sent. Once i had done this, the java application would recognise each command as they were sent.

Writing command line output to a file with in Java

I am running a command line command from java:
ping localhost > output.txt
The command is send via a Java like this:
Process pr = rt.exec(command);
For some reason the file is not created, but when i run this command from the
command line itself, the file does create and the output is in that file.
Why doesn't the java command create the file?
Because you haven't directed it to a file.
On the command line, you've requested that it be redirected to a file. You have to do the same thing in Java, via the InputStream provided by the Process object (which corresponds to the output stream of the actual process).
Here's how you get the output from the process.
InputStream in = new BufferedInputStream( pr.getInputStream());
You can read from this until EOF, and write the output to a file. If you don't want this thread to block, read and write from another thread.
InputStream in = new BufferedInputStream( pr.getInputStream());
OutputStream out = new BufferedOutputStream( new FileOutputStream( "output.txt" ));
int cnt;
byte[] buffer = new byte[1024];
while ( (cnt = in.read(buffer)) != -1) {
out.write(buffer, 0, cnt );
}
1. After successfully executing the command from Java program, you need to read the output, and then divert the Output to the file.
Eg:
Process p = Runtime.getRuntime().exec("Your_Command");
InputStream i = p.getInputStream();
InputStreamReader isr = new InputStreamReader(i);
BufferedReader br = new BufferedReader(isr);
File f = new File("d:\\my.txt");
FileWriter fw = new FileWriter(f); // for appending use (f,true)
BufferedWriter bw = new BufferedWriter(fw);
while((br.readLine())!=null){
bw.write(br.readLine()); // You can also use append.
}
Complementing Andy's answer, I think you MUST read this article: http://www.javaworld.com/jw-12-2000/jw-1229-traps.html.
It is very important for who needs to deal with external processes in Java.
I you want to keep it simple, and you are using Windows, try:
Process pr = rt.exec("cmd /c \"ping localhost > output.txt\"");

Executing Shell Scripts from Java, Shell scripts having read operation

I have a Shell Scripts that read the Input
#!/bin/bash
echo "Type the year that you want to check (4 digits), followed by [ENTER]:"
read year
echo $year
I'm executing this shell scripts using JAVA APi
ProcessBuilder pb = new ProcessBuilder("/bin/bash", "/junk/leaptest.sh");
final Process process = pb.start();
InputStream is = process.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
System.out.println("Program terminated!");
In the Java Console I can see the Output
Type the year that you want to check (4 digits), followed by [ENTER]:
Now the Actual Problem in How to pass the values to the Shell Scripts in my scripts how the varialble "year" can be read
I have edited the code as per the suggestion but doesn't work where we correct it
ProcessBuilder pb = new ProcessBuilder("/bin/bash", "-c", "/junk/leaptest.sh");
final Process process = pb.start();
InputStream is = process.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
/*
* OutputStream os = process.getOutputStream(); PrintWriter pw = new
* PrintWriter(os);
*/
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
while ((line = br.readLine()) != null) {
System.out.println(line);
// pw.println("8999");
bw.write("2012");
}
System.out.println("Program terminated!");
You can use the OutputStream of the Process class:
OutputStream os = process.getOutputStream();
PrintWriter pw = new PrintWriter(os);
pw.println("1997");
What you write to this output stream will become the input stream of the shell script. So read year will read 1987 to the year variable.
EDIT:
I also tried it out and I've managed to find the problem. The 1997 string hasn't reached the script, beacuse PrintWriter buffers the data that was written to it. You either have to flush the PrintWriter stream after the println() with pw.flush() or you have to set the auto-flush property to true upon creation:
PrintWriter pw = new PrintWriter(os, true);
Here is the complete code that was working fine for me:
leaptest.sh:
#!/bin/bash
echo "Type the year that you want to check (4 digits), followed by [ENTER]:"
read year
echo $year
Test.java:
import java.io.*;
class Test {
public static void main(String[] args) {
try {
ProcessBuilder pb = new ProcessBuilder("/bin/bash", "leaptest.sh");
final Process process = pb.start();
BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));
PrintWriter pw = new PrintWriter(process.getOutputStream());
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
pw.println("1997");
pw.flush();
}
System.out.println("Program terminated!");
} catch(Exception e) {
e.printStackTrace();
}
}
}
Output:
$ java Test
Type the year that you want to check (4 digits), followed by [ENTER]:
1997
Program terminated!
To pass values from java program that executes script to the script use command line arguments. If you want to send information back from script to java program print the value in script, read the script's STDOUT in java program and parse it.
You really almost there. Now you are reading the script output (into while loop) but you are just printing it. Parse the output and do what you need with it.
Think you should parse input stream is to extract your values. Parse it by lines.
You want to set up an OutputStream using getOutputStream aswell, to be able to write data from your Java program into the process.
public abstract OutputStream getOutputStream()
Gets the output stream of the subprocess. Output to the stream is piped into the standard input stream of the process represented by
this Process object.
I think this should work. You need to handle your subprocess' output stream. Read the docs.
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
bw.write("2012");

How to edit file on console from Java?

I'm trying to edit a file from CLI. I'm executing the nano command (I know that command will always be available); when I execute it, I can see nano's output but I cannot interact with it. How can I pass user input to the command? Do you have a better idea to easily edit a file from within my Java app?
This is my code:
String command = "nano /tmp/163377867.txt ";
try {
Process process = Runtime.getRuntime().exec(command);
InputStream inputStream = process.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String line;
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
The problem with Java's Runtime.exec is that it connects stdin and stdout to "pipes," while many console programs need a TTY device.
One way to solve this problem is to make the Java program's controlling terminal available to the program you execute:
Process proc = Runtime.getRuntime().exec(new String[]{
"sh", "-c", command+" </dev/tty >/dev/tty"});
proc.waitFor(); // wait for user to finish editing the file

Categories

Resources