Fire a cmd.exe command through ProcessBuilder with visual window - java

I am using this code:
ProcessBuilder builder = new ProcessBuilder("cmd.exe","java","invalidArg");
builder.redirectErrorStream(true);
try {
Process p = builder.start();
BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()),10240);
String line;
if(processIsTerminated(p)){
line = r.readLine();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Is there a way to have the cmd window open as well when I use the .start() function? Currently it runs hidden and if there is no response I don't know if my command was ran successfully or it didn't run at all.

Well you have only 2 ways of running a command under Windows :
the way you go : you have full access to the input, output and error stream of the lauched command, but it has no window and anyway it would not write anything there since your program gets all the output
ask cmd.exe to start the other command in its own window (and optionnaly wait for its end). But then as the command writes to its own window, you program has no access to the input, output or error streams of the command
You can obtain that 2nd execution way with the start [/w] command arguments command of cmd.exe, just type start /w cmd.exe /c "echo foo & pause" in a cmd window to see what happens (the & pause is only there to let you some time to read the output ...)
From java, it would be :
ProcessBuilder builder = new ProcessBuilder("cmd.exe","/c", "start", "/w",
"cmd", "/c", "java invalidArg & pause");

Related

Start native terminal with command arguments (Java)

I have a seemingly trivial problem: I want to start a terminal from a java process and give the terminal one or two commands.
I have a simple example code, that works perfectly on windows with CMD. But I have not been able to achieve the same exact behavior on a Linux nor a Mac OS machine.
I am aware, that the command needs to be changed, but unfortunately I have not been able to pass a string of arguments to a terminal on Mac.
Here the working code for windows:
import java.lang.ProcessBuilder.Redirect;
public class ExecTest {
public static void main(String[] args){
String cmd = "cmd /c start cmd.exe /K \"echo hello && echo bye\"";
try {
Process p = Runtime.getRuntime().exec(cmd);
p.waitFor();
} catch (Exception e) {
e.printStackTrace();
}
}
}
On lubuntu I have been able to create a terminal with this command:
lxterminal -l -e 'echo hello && echo bye && read'
But this only works if called by a terminal but not with the java process.
.
TLDR: What is the Linux and Mac equivalent of this command:
cmd /c start cmd.exe /K \"echo hello && echo bye\"
I suggest you use ProcessBuilder to benefit from easier output redirection and ability to consume it without using threads, and also pass the command as a String[] instead of flat String to be able to support the various wrapping approaches. If you prefer to stick with Runtime.exec(), it also supports String[], but the example below uses ProcessBuilder.
static int executeInTerminal(String command) throws IOException, InterruptedException {
final String[] wrappedCommand;
if (isWindows) {
wrappedCommand = new String[]{ "cmd", "/c", "start", "/wait", "cmd.exe", "/K", command };
}
else if (isLinux) {
wrappedCommand = new String[]{ "xterm", "-e", "bash", "-c", command};
}
else if (isMac) {
wrappedCommand = new String[]{"osascript",
"-e", "tell application \"Terminal\" to activate",
"-e", "tell application \"Terminal\" to do script \"" + command + ";exit\""};
}
else {
throw new RuntimeException("Unsupported OS ☹");
}
Process process = new ProcessBuilder(wrappedCommand)
.redirectErrorStream(true)
.start();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line); // Your superior logging approach here
}
}
return process.waitFor();
}
Tested on 3 operating systems. The 3 booleans is{Windows|Linux|Mac} are unexplained here as OS detection is another topic, so for the example I kept it simple and handled out of the method.
The ProcessBuilder is configured to redirect stderr to stdout, so that a single stream needs to be read. That stream is then read and logged, because you must consume stderr and stdout, in case the Terminal itself prints stuff (not the command you are running in the Terminal, this is about what the Terminal itself prints), if it prints too much you risk getting the process to block indefinitely, waiting for the buffer to be read. See this nice answer.
For macOS if the command you pass is always a single executable script, you could also use {"open", "-a", "Terminal", command}, but that will not work with echo hello && echo bye. Similarly you could use {"/Applications/Utilities/Terminal.app/Contents/MacOS/Terminal", command}, which would get you a second instance of the app running, but with same limitations.
Final note: you can offer a reasonable basic implementation, but you'll probably need to make it configurable to allow alternative terminal applications (especially on Linux where it varies a lot).
String[] cmd = {"echo", "hello", "&&", "echo", "hi"};
Runtime.getRuntime().exec(cmd);
There are multiple ways to do this, but this should work for you. Executables on Mac should run automatically in Terminal.
Possibly similar to: How To Run Mac OS Terminal Commands From Java (Using Runtime?)
If anything they have a few methods for running scripts in the terminal.

Trying to show the execution of bat file in eclipse console [duplicate]

In my Java application, I want to run a batch file that calls "scons -Q implicit-deps-changed build\file_load_type export\file_load_type"
It seems that I can't even get my batch file to execute. I'm out of ideas.
This is what I have in Java:
Runtime.
getRuntime().
exec("build.bat", null, new File("."));
Previously, I had a Python Sconscript file that I wanted to run but since that didn't work I decided I would call the script via a batch file but that method has not been successful as of yet.
Batch files are not an executable. They need an application to run them (i.e. cmd).
On UNIX, the script file has shebang (#!) at the start of a file to specify the program that executes it. Double-clicking in Windows is performed by Windows Explorer. CreateProcess does not know anything about that.
Runtime.
getRuntime().
exec("cmd /c start \"\" build.bat");
Note: With the start \"\" command, a separate command window will be opened with a blank title and any output from the batch file will be displayed there. It should also work with just `cmd /c build.bat", in which case the output can be read from the sub-process in Java if desired.
Sometimes the thread execution process time is higher than JVM thread waiting process time, it use to happen when the process you're invoking takes some time to be processed, use the waitFor() command as follows:
try{
Process p = Runtime.getRuntime().exec("file location here, don't forget using / instead of \\ to make it interoperable");
p.waitFor();
}catch( IOException ex ){
//Validate the case the file can't be accesed (not enought permissions)
}catch( InterruptedException ex ){
//Validate the case the process is being stopped by some external situation
}
This way the JVM will stop until the process you're invoking is done before it continue with the thread execution stack.
Runtime runtime = Runtime.getRuntime();
try {
Process p1 = runtime.exec("cmd /c start D:\\temp\\a.bat");
InputStream is = p1.getInputStream();
int i = 0;
while( (i = is.read() ) != -1) {
System.out.print((char)i);
}
} catch(IOException ioException) {
System.out.println(ioException.getMessage() );
}
ProcessBuilder is the Java 5/6 way to run external processes.
To run batch files using java if that's you're talking about...
String path="cmd /c start d:\\sample\\sample.bat";
Runtime rn=Runtime.getRuntime();
Process pr=rn.exec(path);`
This should do it.
The executable used to run batch scripts is cmd.exe which uses the /c flag to specify the name of the batch file to run:
Runtime.getRuntime().exec(new String[]{"cmd.exe", "/c", "build.bat"});
Theoretically you should also be able to run Scons in this manner, though I haven't tested this:
Runtime.getRuntime().exec(new String[]{"scons", "-Q", "implicit-deps-changed", "build\file_load_type", "export\file_load_type"});
EDIT: Amara, you say that this isn't working. The error you listed is the error you'd get when running Java from a Cygwin terminal on a Windows box; is this what you're doing? The problem with that is that Windows and Cygwin have different paths, so the Windows version of Java won't find the scons executable on your Cygwin path. I can explain further if this turns out to be your problem.
Process p = Runtime.getRuntime().exec(
new String[]{"cmd", "/C", "orgreg.bat"},
null,
new File("D://TEST//home//libs//"));
tested with jdk1.5 and jdk1.6
This was working fine for me, hope it helps others too.
to get this i have struggled more days. :(
I had the same issue. However sometimes CMD failed to run my files.
That's why i create a temp.bat on my desktop, next this temp.bat is going to run my file, and next the temp file is going to be deleted.
I know this is a bigger code, however worked for me in 100% when even Runtime.getRuntime().exec() failed.
// creating a string for the Userprofile (either C:\Admin or whatever)
String userprofile = System.getenv("USERPROFILE");
BufferedWriter writer = null;
try {
//create a temporary file
File logFile = new File(userprofile+"\\Desktop\\temp.bat");
writer = new BufferedWriter(new FileWriter(logFile));
// Here comes the lines for the batch file!
// First line is #echo off
// Next line is the directory of our file
// Then we open our file in that directory and exit the cmd
// To seperate each line, please use \r\n
writer.write("cd %ProgramFiles(x86)%\\SOME_FOLDER \r\nstart xyz.bat \r\nexit");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
// Close the writer regardless of what happens...
writer.close();
} catch (Exception e) {
}
}
// running our temp.bat file
Runtime rt = Runtime.getRuntime();
try {
Process pr = rt.exec("cmd /c start \"\" \""+userprofile+"\\Desktop\\temp.bat" );
pr.getOutputStream().close();
} catch (IOException ex) {
Logger.getLogger(MainFrame.class.getName()).log(Level.SEVERE, null, ex);
}
// deleting our temp file
File databl = new File(userprofile+"\\Desktop\\temp.bat");
databl.delete();
The following is working fine:
String path="cmd /c start d:\\sample\\sample.bat";
Runtime rn=Runtime.getRuntime();
Process pr=rn.exec(path);
This code will execute two commands.bat that exist in the path C:/folders/folder.
Runtime.getRuntime().exec("cd C:/folders/folder & call commands.bat");
import java.io.IOException;
public class TestBatch {
public static void main(String[] args) {
{
try {
String[] command = {"cmd.exe", "/C", "Start", "C:\\temp\\runtest.bat"};
Process p = Runtime.getRuntime().exec(command);
} catch (IOException ex) {
}
}
}
}
To expand on #Isha's anwser you could just do the following to get the returned output (post-facto not in rea-ltime) of the script that was run:
try {
Process process = Runtime.getRuntime().exec("cmd /c start D:\\temp\\a.bat");
System.out.println(process.getText());
} catch(IOException e) {
e.printStackTrace();
}

How to execute cd commands using java Runtime in a single cmd window

I need to execute the following Change directories commands into the cmd prompt, but using java to execute them. the dir command works fine , but not the cd ones. I have to execute them in a single cmd windows
cd inputDir
dir
cd outputDir
inputDir and outputDir are directories from the windows.
Java Snippet:
ArrayList<String> dosCommands = new ArrayList<String>();
Process p;
for (int i=0;i< dosCommands.size();i++){
p=Runtime.getRuntime().exec("cmd.exe /c "+dosCommands.get(i));
p.waitFor();
BufferedReader reader=new BufferedReader(new InputStreamReader(p.getInputStream()));
String line=reader.readLine();
while(line!=null)
{
System.out.println(line);
line=reader.readLine();
}
}
UPDATE
Changing the argument to cmd.exe /k instead of /c
p=Runtime.getRuntime().exec("cmd.exe /k "+dosCommands.get(i));
I had to remove the
p.waitFor();
method, because I was getting stucked in it.
Doing so, know I do get stucked in the
line.reader.readLine();
use
cmd.exe /K
Not
cmd.exe /c
You can find more about cmd params here
With /c, cmd finishes and exit. With /k, it does not exit.
__UPDATE__
What I mean is as follows:
cd inputDir
dir
cd outputDir
exit
Pay attention to the last line please.
__UPDATE 2__
Please use something similar in your code to find out what is the current working directory, according to running process:
public class JavaApplication1 {
public static void main(String[] args) {
System.out.println("Working Directory = " +
System.getProperty("user.dir"));
}
}
After that, let's make sure that the folders you are trying to cd to exists in that folder.
Try this experiment: Open a command window (using your mouse and/or keyboard, not with code). Now change to a different directory, with a command like cd \ or cd C:\Windows.
Then open a second command window. What is its current directory? Did it remember what you did in the first command window?
It didn't, because each time you run cmd.exe you are starting a new process, with its own current directory state.
In your code, you are executing a new cmd.exe process in each iteration of your for-loop. Each time you start a new cmd.exe, it has no awareness of what the current directory may be in other cmd.exe instances.
You can set the current directory in which a process executes:
String inputDir = "C:\\Users\\eleite\\Workspace\\RunCmd\\Petrel_Logs";
p = Runtime.getRuntime().exec("cmd.exe /c " + dosCommands.get(i),
null, inputDir);
If you want to
create process simulating console
and make this console execute few commands
and after these commands are executed continue code from main thread
then try this code
ProcessBuilder pb = new ProcessBuilder("cmd.exe", "/k");
pb.redirectOutput(Redirect.INHERIT);//redirect process output to System.out
pb.redirectError(Redirect.INHERIT);//redirect process output to System.err
Process p = pb.start();
try(PrintWriter pw = new PrintWriter(new OutputStreamWriter(p.getOutputStream()), true)){
pw.println("dir");//execute command 1, for instance "dir"
pw.println("ver");//execute command 2, for instance "ver"
//... rest of commands
pw.println("exit");//when last command finished, exit console
}
p.waitFor();//this will make main thread wait till process (console) will finish (will be closed)
//here we place rest of code which should be executed after console after console process will finish
System.out.println("---------------- after process ended ----------------");
So if you want list of commands you want to execute simply place them here:
try(PrintWriter pw = new PrintWriter(new OutputStreamWriter(p.getOutputStream()), true)){
//here and execute them like
for (String command : dosCommands){
pw.println(command);
}
pw.println("exit");//when last command finished, exit console
}

How to check if process is running

ProcessBuilder pb = new ProcessBuilder("notepad");
Process p = pb.run();
System.out.println("Notepad is closed")
The code above will run fine and open up notepad. However the print statement will not print until I manually close the notepad window. This is because Java waits until the process is terminated. Is there anyway I can just open a process and check if the window has loaded?
The ProcessBuilder.start() method will not halt program execution.
You can use just like this:
ProcessBuilder pb = new ProcessBuilder("notepad");
Process p = pb.start();
System.out.println("This will print right after notepad is launched.")
You can then use the process object to read any output from the program, kill the program, or halt program execution until it is finished.
Here is the reference page: Process
You can use exitValue like this:
try {
// instead of 0 use the exit value of your started program to run some logic if it has failed
if (p.exitValue() != 0) {
}
} catch (IllegalThreadStateException e) {
// expected, here the logic will jump to if the program is still running
}

Why doesn't the Java console show when using ProcessBuilder?

I use the following to launch a Java application from another Java app.
ProcessBuilder pb = new ProcessBuilder(javaPath + javaCommand, maxMemStr,
minMemStr, stackSizeStr, jarCommand, jarfile, jarArg);
try {
Process p = pb.start();
} catch (IOException ex) {
Logger.getLogger(launch.class.getName()).log(Level.SEVERE, null, ex);
}
where javaCommand is either java or javaw (javaPath is empty most of the time unless a user points to an alternate path). The problem is, after the app launches, even when I verify the process list to contain java, it doesn't show the console.
Is it because PrcoessBuilder doesn't invoke the command shell? Is there a way to show the console programatically?
Thanks in advance.
This is because the "command console" itself is a process that attaches to the std-in/-out/-err streams of another process and displays them on the screen. When you launch Java all by itself, no other processes will be handling those streams, hence the lack of a command console. To get the results you want, you will need to launch a new instance of the command console and subsequently have it run your custom java command.
There may be a better way to do this... but I think the solution to this is going to be platform-dependent. In Windows, you could do something like:
ProcessBuilder pb = new ProcessBuilder("start", "\"JAwesomeSauce\"", "cmd.exe",
"/k", javaPath + javaCommand, maxMemStr, minMemStr, stackSizeStr, jarCommand,
jarfile, jarArg);
try {
Process p = pb.start();
} catch (IOException ex) {
Logger.getLogger(launch.class.getName()).log(Level.SEVERE, null, ex);
}
I assume you could do something similar in Linux/Mac if that's the O/S you're using.
You may want to run the command like this:
cmd /K java ...
or
cmd /C java ...
As far as I remember the Processbuilder opens a pipe to a specific process.
Your command window is a process itself with all you see. If you enter commands the cmd/bash usually creates new processes and attaches to them.

Categories