I have a two programs:
first, that uses Console object to read and write data
second, that should run first with some dynamically calculated arguments
Second program code looks like this:
String[] arguments = {
"cmd", "/c",
"java", "-cp", classPath
lauchClass,
// Arguments for first program
}
ProcessBuilder pb = new ProcessBuilder(arguments);
pb.environment().putAll(System.getenv());
pb.directory(workDir);
pb.inheritIO();
Process process = pb.start();
process.waitFor();
When fist programs starts from second, System.console() is null and it fails with NPE.
So, question is: is there any way to run another process with System.console() available?
The answer is simple: If you run your launcher from an IDE like Eclipse or IntelliJ IDEA, probably it does not have System.console() set in the first place, thus there is nothing the subprocess can inherit from. Just try to write something to System.console() from the launcher, it will also fail with the same error. But if you start your launcher from an interactive console like Cmd.exe or Git Bash, both the launcher and the process started via ProcessBuilder can write to System.console(). Your launcher does not even need "cmd", "/c", it works with or without those parameters.
package de.scrum_master.stackoverflow;
import java.io.File;
import java.io.IOException;
public class Launcher {
public static void main(String[] args) throws IOException, InterruptedException {
String classPath = "out/production/SO_ExternalProcessSystemConsole";
String launchClass = "de.scrum_master.stackoverflow.MyApp";
File workDir = new File(".");
System.console().printf("Hi, I am the launcher app!%n");
String[] arguments = new String[] {
// "cmd", "/c",
"java", "-cp", classPath,
launchClass
};
ProcessBuilder pb = new ProcessBuilder(arguments);
pb.environment().putAll(System.getenv());
pb.directory(workDir);
pb.inheritIO();
Process process = pb.start();
process.waitFor();
}
}
package de.scrum_master.stackoverflow;
public class MyApp {
public static void main(String[] args) {
System.console().printf("Hi, I am an externally started app!%n");
}
}
Console log when started from IntelliJ IDEA:
Exception in thread "main" java.lang.NullPointerException
at de.scrum_master.stackoverflow.Launcher.main(Launcher.java:11)
(...)
Console log when started from cmd.exe:
Hi, I am the launcher app!
Hi, I am an externally started app!
Feel free to ask any follow-up questions.
Update: If you do not mind that the external program runs in its own interactive console instead of in the IDE console, you can use the Windows command start for that purpose and then either cmd /c (windows is closed immediately after external program has ended) or cmd /k (window stays open for you to inspect the result):
package de.scrum_master.stackoverflow;
import java.io.File;
import java.io.IOException;
public class Launcher {
public static void main(String[] args) throws IOException, InterruptedException {
String classPath = "out/production/SO_ExternalProcessSystemConsole";
String launchClass = "de.scrum_master.stackoverflow.MyApp";
String[] arguments = new String[] {
"cmd", "/c", "start",
"cmd", "/k", "java", "-cp", classPath, launchClass
};
ProcessBuilder pb = new ProcessBuilder(arguments);
Process process = pb.start();
process.waitFor();
}
}
But if then you want to read/write from/to that console, you are back at square #1. You asked why you cannot inherit System.console() to a subprocess. Well, that is because it is null due to the way Eclipse and IntelliJ launch Java programs from within the IDE (see [here] for background info). But as Magnus said, you still have System.{out|in} and can use them as follows:
package de.scrum_master.stackoverflow;
import java.io.File;
import java.io.IOException;
import java.util.Scanner;
public class Launcher {
public static void main(String[] args) throws IOException, InterruptedException {
String classPath = "out/production/SO_ExternalProcessSystemConsole";
String launchClass = "de.scrum_master.stackoverflow.MyApp";
File workDir = new File(".");
System.out.println("Hi, I am the launcher app!");
String[] arguments = new String[] { "cmd", "/c", "java", "-cp", classPath, launchClass };
ProcessBuilder pb = new ProcessBuilder(arguments);
pb.environment().putAll(System.getenv());
pb.directory(workDir);
pb.inheritIO();
Process process = pb.start();
process.waitFor();
System.out.print("What is your favourite city? ");
Scanner scanner = new Scanner(System.in);
String city = scanner.nextLine();
System.out.println("I guess that " + city + " is a nice place.");
}
}
package de.scrum_master.stackoverflow;
import java.util.Scanner;
public class MyApp {
public static void main(String[] args) {
System.out.println("----------------------------------------");
System.out.println("Hi, I am an externally started app.");
System.out.print("Please enter your name: ");
Scanner scanner = new Scanner(System.in);
String name = scanner.nextLine();
System.out.println("Hello " + name + "!");
System.out.println("----------------------------------------");
}
}
Hi, I am the launcher app!
----------------------------------------
Hi, I am an externally started app.
Please enter your name: Alexander
Hello Alexander!
----------------------------------------
What is your favourite city? Berlin
I guess that Berlin is a nice place.
Related
I just want some files to be read and written in my Java program. So I use java.security.SecurityManager to manage this, but it seems unsatisfactory.
The Main.java file is below
import java.io.*;
import java.util.*;
public class Main {
static private final String INPUT = "in.txt";
public static void main(String args[]) throws Exception {
FileInputStream instream = null;
BufferedReader reader = new BufferedReader(new FileReader(INPUT));
String tempString = null;
while ((tempString = reader.readLine()) != null) {
System.out.println(tempString);
}
}
}
and the file /opt/java.policy like below
grant {
permission java.io.FilePermission "./out.txt", "write";
};
Then I run
java -Xss64m -Xms16m -Xmx512m -Djava.security.manager -Djava.security.policy=/opt/java.policy Main
But there are no errors, the output is what the in.txt is. I tried other file and got the same result. Why does this happen?
From the Javadoc:
Please note: Code can always read a file from the same directory it's in (or a subdirectory of that directory); it does not need explicit permission to do so.
Not that this is well-specified. Code isn't 'in' a directory: it is executed from a current working directory, and this appears to be what is meant.
I have this piece of program
import java.io.IOException;
public class ShellCommand {
public void execShellCmd(String cmd) throws IOException{
Runtime.getRuntime().exec(new String[] {"gnome-terminal", "-x", "bash", "-c", cmd});
}
}
cmd is a String that contains parameters such as:
/home/fireworks/workspace/ABT/hello.sh
where hello.sh is the sh file to run from java
The program works, only that, after opening the gnome-terminal continues normally not waiting for the closure of the gnome-terminal.
I already tried the method waitFor(); but nothing changes
Is there any solution that allows the program to wait for the closure of the gnome-terminal?
Solved: Is gnome-terminal of ubuntu 15 the problem. I use xterm
The following works for me:
import java.io.IOException;
public class ShellCommand {
public void execShellCmd(String cmd) throws IOException, InterruptedException {
Process p = Runtime.getRuntime().exec(new String[] {"gnome-terminal", "-x", "bash", "-c", cmd});
System.out.println( "Started proc" );
p.waitFor();
System.out.println( "Done waiting" );
}
public static void main( String[] args ) {
ShellCommand s = new ShellCommand();
try {
s.execShellCmd( "sleep 10; echo done" );
} catch( Exception e ) {
}
}
}
I see the "started proc" printout, then it waits for the terminal to finish, then I see "Done waiting".
i have a batch file saved on my desktop and it serves the purpose of opening a calculator when executed.
i want this batch file to function quite in the same way using java. i wrote the following command in netbeans
package runbatch;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Runbatch {
public static void main(String[] args) {
try {
Runtime.getRuntime().exec("cmd /c hello.bat");
} catch (IOException ex) {
Logger.getLogger(Runbatch.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
although i get the build to be successful i am not getting the calculator opened up.
Try this:
Runtime.getRuntime().exec("cmd /c start calculator.bat");
Or you can execute your program without going through a batch file, like so:
Runtime.getRuntime().exec("cmd /c start java NameOfJavaFile");
Add "start" argument and complete path of batch file:
Runtime.getRuntime().exec("cmd /c start D:\sandbox\src\runbatch\hello.bat");
This works for me.
I prefer something like this:
String pathToExecutable = "C:/Program Files/calculator.exe";
try
{
final List<String> processBuilderCommand = new ArrayList<String>();
// Here you can add other commands too eg a bat or other exe
processBuilderCommand.add(pathToExecutable);
final ProcessBuilder processbuilder = new ProcessBuilder(processBuilderCommand);
// Here you be able to add some additional infos to the process, some variables
final Map<String, String> environment = processbuilder.environment();
environment.put("AUTOBATCHNOPROGRESS", "no");
processbuilder.inheritIO();
final Process start = processbuilder.start();
start.waitFor();
}
catch (IOException | InterruptedException e)
{
LOGGER.error(e.getLocalizedMessage(), e);
}
i think it's a little bit flexibel then the others because you can add several and more then one execuable und you be able to add variables.
ProcessBuilder is the safe and right way of doing this in java :
String[] command = new String[]{"cmd", "/c" ,"hello.bat"};
ProcessBuilder processBuilder = new ProcessBuilder();
processBuilder.command(command);
processBuilder.start();
I am creating a text based program/ game and someone I know created one that opened the console into the Windows Command prompt. This made it so it could be continually refreshed, making the text clear and having a clean look, rather than the clunky console view, which just adds the text onto it, making a bad medium for a text-based game.
The following may give you an idea:
public static void main(String[] args) throws Exception {
// Since you are using eclipse, bin contains the compiled classes
// This depends on your working directory.
File directory = new File("bin");
// In my case, the main class is Game (in the default package)
ProcessBuilder pb = new ProcessBuilder("cmd", "/c", "java", "Game");
// directory defined above
pb.directory(directory);
// The fun begins!
pb.start();
}
The Game class containing only the following:
import java.util.Scanner;
public class Game {
public static void main(String[] args) {
try (Scanner sc = new Scanner(System.in)) {
System.out.println(sc.nextLine());
}
}
}
I want to use cmd Commands in java program,
Want to crope all images in folder, I downlaoded ImageMagick, and using cmd commands Its working 1 image,
cd C:\Users\Robert\Java-workspace\Crop_test\Crop_test1
cd convert -crop 312x312+0-10 image1.jpg new_image1.jpg
But, I want to use this in Java so, I can crop all images in folder by program, Here is my java program:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import org.omg.CORBA.portable.OutputStream;
public class test1 {
public static void main(String argv[]) throws IOException, InterruptedException {
ProcessBuilder pb = new ProcessBuilder("cmd", "/c", "C:\\Users\\Robert\\Java-workspace\\Crop_test\\Crop_test1\\", "convert -crop 312x312+0-10 image1.jpg new_image1.jpg");
Process p = pb.start();
p.waitFor();
}
}
Although you are asking how to use CMD and this was addressed on other answers I think that the best solution (considering your explanation of your implementation) would be to use a ImageMagick wrapper for Java as you can see here.
Cheers
You can invoke CMD commands as follows in Java;
Runtime.getRuntime().exec(your_command);
Best thing for you to do is to creat a batch file with the commands you need to run and then invoke your batch file using the following command;
Runtime.getRuntime().exec("cmd /C start D:\\test.bat");
because you cannot do any change directory commands using the Runtime class. Please try this option and let me know if you face any other issues.
A couple of things to try (both of which are untested):
Put a cd in the command line and use && to run both commands in one line.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import org.omg.CORBA.portable.OutputStream;
public class test1 {
public static void main(String argv[]) throws IOException, InterruptedException {
ProcessBuilder pb = new ProcessBuilder("cmd", "/c", "cd C:\\Users\\Robert\\Java-workspace\\Crop_test\\Crop_test1\\ && convert -crop 312x312+0-10 image1.jpg new_image1.jpg");
pb.redirectErrorStream(true);
Process p = pb.start();
p.waitFor();
}
}
Change the directory that the ProcessBuilder starts in:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import org.omg.CORBA.portable.OutputStream;
public class test1 {
public static void main(String argv[]) throws IOException, InterruptedException {
ProcessBuilder pb = new ProcessBuilder("cmd", "/c", "convert -crop 312x312+0-10 image1.jpg new_image1.jpg");
pb.directory(new File("C:\\Users\\Robert\\Java-workspace\\Crop_test\\Crop_test1\\"));
pb.redirectErrorStream(true);
Process p = pb.start();
p.waitFor();
}
}
Incidentally, are you sure you want to import org.omg.CORBA.portable.OutputStream? Did you mean java.io.OutputStream instead?
EDIT: if things still aren't working, then the next step is to see whether the problem is that convert isn't being found. Let's just run convert on its own without any arguments and see if it spits out its usage message to standard output. Run the following:
public class test1 {
public static void main(String argv[]) throws IOException, InterruptedException {
ProcessBuilder pb = new ProcessBuilder("cmd.exe", "/c", "convert");
pb.redirectErrorStream(true);
Process p = pb.start();
StreamGobbler g = new StreamGobbler(p.getInputStream(), "OUT");
g.start();
p.waitFor();
}
}
Use the StreamGobbler class here. Does this print out convert's usage method, with each line prefixed with OUT>?