In Java, send commands to another command-line program - java

I am using Java on Windows XP and want to be able to send commands to another program such as telnet.
I do not want to simply execute another program. I want to execute it, and then send it a sequence of commands once it's running.
Here's my code of what I want to do, but it does not work:
(If you uncomment and change the command to "cmd" it works as expected. Please help.)
This is a simplified example. In production there will be many more commands sent, so please don't suggest calling "telnet localhost".
try
{
Runtime rt = Runtime.getRuntime();
String command = "telnet";
//command = "cmd";
Process pr = rt.exec(command);
BufferedReader processOutput = new BufferedReader(new InputStreamReader(pr.getInputStream()));
BufferedWriter processInput = new BufferedWriter(new OutputStreamWriter(pr.getOutputStream()));
String commandToSend = "open localhost\n";
//commandToSend = "dir\n" + "exit\n";
processInput.write(commandToSend);
processInput.flush();
int lineCounter = 0;
while(true)
{
String line = processOutput.readLine();
if(line == null) break;
System.out.println(++lineCounter + ": " + line);
}
processInput.close();
processOutput.close();
pr.waitFor();
}
catch(Exception x)
{
x.printStackTrace();
}

That looks OK, as it won't be producing that much output, but you should really read and write in separate threads so it doesn't fill up the buffer and block waiting you to read before you reach the next step.
So if it's reaching the point where you flush the command you send to it, find out whether the Windows telnet client supports receiving commands from standard input rather than a console by piping the text you're sending to its standard input to it in a command prompt.
For example, echo dir c:\ | cmd causes cmd to run, list the c: drive contents and exit, much the same behaviour as if you typed dir c:\ into the console. But echo open localhost | telnet causes telnet to clear the screen then exit, rather than behaving the same way as if you typed it into the console. As telnet needs to mask user input for passwords, it's quite likely that it's using the console API rather than reading from standard input. It's help doesn't list any command arguments to tell it to read from standard input, so maybe you need to use a telnet implementation which is better suited to scripting.

It's not directly an answer to your question, but...
Instead of using Runtime.exec() you should use a ProcessBuilder and redirect stderr to stdout (ProcessBuilder.redirectErrorStream(true)). Otherwise your process could block if it writes something to stderr (Windows doesn't like it when the output of a process isn't read).

If you want to control a telnet session programatically from Java, you might be able to use this Java telnet library... you can do the same things (open connections, send username/password, send commands and receive results) but without actually spawning a separate process.

You may take a look at the Telnet Ant task you can call it directly in your code with out having to use a build.xml file.
You can also take a look at the source code and see how they do it.

Related

Take screenshot with ADB and retrieve it in java WITHOUT writing a file

I know that one can take a screenshot from the Android device via ADB with
$ adb shell screencap -p /mnt/sdcard/sc.png
$ adb pull /mnt/sdcard/sc.png
However this writes a file on your phone and on your PC, which I want to avoid.
So I found the following SO question and the answer suggested that the image gets printed to the Std output when you do not specify a file.
I tested this from console and it really printed binary data to the console.
Android: It there a way to read screenshot from memory without saving to internal/external storage?
Now I want to utilize this technique and start a process from java, execute the
adb shell screencap
command, read the output and create a BufferedImage from the output.
I tried something like this
ProcessBuilder pb = new ProcessBuilder("cmd");
Process start = pb.start();
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(outputStream));
bw.write("adb shell screencap");
bw.newLine();
bw.flush();
// wait some time for the process to print the image to the console
start.waitFor(10, TimeUnit.SECONDS);
StringBuilder sb = new StringBuilder(9000000);
Scanner s = new Scanner(start.getInputStream());
while (s.hasNext()) {
sb.append(s.next());
}
String result = sb.toString();
Unluckily there are quite a few issues with my Code.
the program does not terminate after getting the screenshot - so start.waitFor does not quite work as I wanted it to work
currently my code reads characters, where i actually want to read bytes
reading with scanner seems kind of slow when reading millions of characters/bytes
Maybe someone can point me in a direction such that I can get it to work.
Thanks!
Why complicating things. If you are invoking adb and want its output just run
adb exec-out screencap -p > myimg.png
exec-out is used instead of shell to get raw data (i.e. the image).
After searching some more time I came across ddmlib which already has the functionality to take screenshots and perform various other tasks via ADB built in.
The library works great and definitely made it easier for me to execute commands via ADB.

Java Process stops early even when output is redirected

I have a Java application that calls a tcsh script which in turn calls a perl script in the same directory. If I run this script from the command by typing "runPerlScript.sh", it works completely fine, and generates several output files as it should. However, if I call the script from Java, using the code below:
String[] runCmd = {"/bin/tcsh","-c","/filepath/runPerlScript.sh"};
Process run = Runtime.getRuntime().exec(runCmd);
BufferedReader reader = new BufferedReader(new InputStreamReader(run.getInputStream()));
String line = "";
line = reader.readLine();
System.out.println("\nStarting while.");
while((line)!=null){
System.out.println("Output from script: "+line);
line=reader.readLine();
}
reader.close();
System.out.println("Finished running perl script.");
it prints out the echo statements from my shell script to my console (I'm using NetBeans), but generates only 4 output files (when normally it generates near 50). It seems as if the process is quitting to early, because after these 4 files are generated, an echo statement in my shell script that says "Finished running runPerlScript.sh" prints out to my console. I've tried several different ways to run this script, including ProcessBuilder, but none seem to generate the output files. The code I have above was in fact the only way I was able to generate ANY output, because ProcessBuilder just resulted in hangups. Does anyone know how I can continuously make the script run?
From the Runtime.exec() javadoc:
"Executes the specified string command in a separate process."
Assuming you want to wait for the process to end, you will need to wait for the process to terminate in your main java thread. The best way to do this would be by monitoring the Process returned by ProcessBuilder.start() and wait with Process.waitFor().

error for Importing sql file to mysql database using java in windows

here is my code
try{
String logf = "mysql -p -h localhost ruralcdn<E:\\data\\DBServer\\"+FileName;
System.out.println("Command"+logf);
Runtime rt = Runtime.getRuntime();
Process pr = rt.exec(logf);
int lm = pr.waitFor();
System.out.println("lm"+lm);
System.out.println("!!Done!!");
}catch(Exception ex){
System.out.println("!!error!!");
}
when i compile the above code, it hangs for infinite period of time and no entry updated in my database.
when i tried using the method given below
Connection conn = dbConnectionSource.getConnection();
Statement stmt = conn.createStatement();
stmt.execute(FileUtils.readFileToString(new File("./some-sql-file")));
console displayed error:you have an error in your sql syntex
please help me so that i can do things correctly.
Thanks -A
Your command (in logf) includes a redirection of standard input. Unfortunately, you can't do it that way because the Process.exec(String) method doesn't understand how to do command redirection, quoting and sso on. It only understands how to execute a simple command with arguments separated by spaces.
You've got two choices:
You can open the file in Java, and write it to the process object's output stream so that it show up on the commands standard input.
You can tell Java to run the mysql command in a shell / command interpretter that can take care of the redirection and so on.
Your code should look something like this:
String[] command = new String{
"cmd",
"/c",
"mysql -p -h localhost ruralcdn < E:\\data\\DBServer\\" + fileName;
ProcessBuilder pb = new ProcessBuilder(command);
Process p = pb.start();
p.waitFor();
The other thing that your code should do is to read and display (or discard) the standard output / error from the command. If you don't read it:
you won't know if it contains any error messages, and
there is the possibility that the mysql command will block because it can't write any more to the pipe that you haven't reading.
console displayed error:you have an error in your sql syntex
It is probably telling the truth ...
By the way, the reason that the mysql command currently hangs for ever is that it is waiting for the Java process to send it data on its standard input. And that ain't going to happen because your Java code doesn't write anything to it.

Can't launch external program from Java without closing java app

I'm trying to launch an external program from my java swing app using this:
Process proc = Runtime.getRuntime().exec(cmd);
But the external program never actually gets launched until I close out of my java app...everytime.
It waits to launch only after I have closed out.
the external program I am trying to run is an exe that takes arguments so:
cmd = "externalProgram.exe -v --fullscreen --nowing";
What could possibly be wrong here.
Funny enough it works as expected if i try something simple like:
Process proc = Runtime.getRuntime().exec("notepad.exe");
You may need to read from the process's standard output, or close the standard input, before it will proceed. For reading the output, the problem is that the buffer can get full, blocking the program; for closing the input, the problem is that some programs will try to read data from there if it's available, waiting to do so. One or both of these tricks is very likely to straighten things out for you.
You may also read the error output stream to check it the program is actually being unsuccessfully executed
String cmd = "svn.exe";
Process proc = Runtime.getRuntime().exec(cmd);
BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
String line = null;
while((line=reader.readLine())!=null){
System.out.println(line);
}
reader.close();
My console shows
Type 'svn help' for usage.
Which evidently shows the program was executed by Java.

Unix Script not working in Java Process Runtime.exec()

I am developing an application in Spring Web MVC where i need to execute some of the linux script..
I am using tomcat version 5.5 for running my project in linux..
My code is looking like this :
Process proc = runtime.exec("sudo cp /var/tmp/mailserverfiles/editinterface.txt /etc/sysconfig/network-scripts/editinterface.txt");
InputStream inputstream = proc.getInputStream();
InputStreamReader inputstreamreader = new InputStreamReader(inputstream);
BufferedReader bufferedreader = new BufferedReader(inputstreamreader);
String line;
while ((line = bufferedreader.readLine()) != null) {
System.out.println("\nOUTPUT = " + line);
}
System.out.print("\nbefore execute6");
try {
if (proc.waitFor() != 0) {
System.err.println("\nexit value = " + proc.exitValue());
}
} catch (InterruptedException e) {
System.err.println("\nERROR = " + e);
}
Here i want to cp a particular file from one location to another using linux script..
But when i am executing this part, i am getting
exit value = 1
as a output.. I have also tried to put this script into .sh file and try to execute that shell script here from Java Code, but i am getting same result..
Can anybody tell me, what should be the reason for this ?
Thanks in advance..
I would guess that sudo is expecting an interactive terminal in order to ask for a password. Since there is no interactive terminal, it prints an error message to stderr and exits with an exit code of 1. You are not reading the error stream, so you won't see any message that it might print.
You will definitely want to read the error stream in any case. Doing so now will help you diagnose what is going wrong at this point.
I assume the user that Tomcat is running under has unrestricted access to sudo? And that it's not being prompted for a password?
It is possible that your search path is weird and that "cp" and "sudo" are not found when you try to execute the command.
Here are some things you could try to track down your problem(s):
Try running the "cp" command without "sudo".
Try giving the full pathname of the command(s). This will avoid search path problems.
By default "sudo" logs failed commands using syslog(3). See if you can find traces in the corresponding logfiles.
Assuming you can run your command from a command line, logged in as the tomcat user - try
ProcessBuilder pb = new ProcessBuilder("/usr/bin/sudo", "cp",
"/var/tmp/mailserverfiles/editinterface.txt",
"/etc/sysconfig/network-scripts/editinterface.txt");
pb.redirectErrorStream(true);
Process proc = pb.start();
... rest of code as before
if things still fail, start debugging. strace should be helpful. e.g. run this shell script
from your java application, and figure out where things fail in the /tmp/trace.txt file:
#!/bin/sh
strace -f sudo cp /var/tmp/mailserverfiles/editinterface.txt /etc/sysconfig/network-scripts/editinterface.txt >/tmp/trace.txt 2>&1
Whilst not directly answering your question, the following will help. You need to read stdout and stderr (to capture all process output), and do this concurrently to prevent blocking of the spawned process. See this answer for more info.

Categories

Resources