启动另一个可用 System.console 的进程
Start another Process with System.console available
我有两个程序:
- 首先,使用Console对象读写数据
- 其次,应该运行首先使用一些动态计算的参数
第二个程序代码如下所示:
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();
当第一个程序从第二个开始时,System.console() 为 null 并且失败并出现 NPE。
所以,问题是:有什么方法可以 运行 另一个可用 System.console() 的进程吗?
答案很简单:如果您 运行 您的启动器来自 IDE,如 Eclipse 或 IntelliJ IDEA,可能它没有在 System.console()
中设置首先,因此没有任何子进程可以继承。只需尝试从启动器向 System.console()
写入一些内容,它也会因同样的错误而失败。但是,如果您从 Cmd.exe 或 Git Bash 等交互式控制台启动启动器,启动器和通过 ProcessBuilder
启动的进程都可以写入 System.console()
。您的启动器甚至不需要 "cmd", "/c"
,无论是否使用这些参数,它都可以工作。
package de.scrum_master.Whosebug;
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.Whosebug.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.Whosebug;
public class MyApp {
public static void main(String[] args) {
System.console().printf("Hi, I am an externally started app!%n");
}
}
从 IntelliJ 启动时的控制台日志 IDEA:
Exception in thread "main" java.lang.NullPointerException
at de.scrum_master.Whosebug.Launcher.main(Launcher.java:11)
(...)
从 cmd.exe:
启动时的控制台日志
Hi, I am the launcher app!
Hi, I am an externally started app!
如有任何 follow-up 问题,请随时提出。
更新: 如果您不介意外部程序 运行 在其自己的交互式控制台中而不是在 IDE 控制台中,您可以为此目的使用 Windows 命令 start
然后 cmd /c
(windows 在外部程序结束后立即关闭)或 cmd /k
(window 保持开放供您检查结果):
package de.scrum_master.Whosebug;
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.Whosebug.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();
}
}
但是如果你想 read/write from/to 那个控制台,你又回到了第 1 个方块。您问为什么不能将 System.console()
继承给子进程。好吧,那是因为它是 null
由于 Eclipse 和 IntelliJ 从 IDE 中启动 Java 程序的方式(请参阅 [此处] 了解背景信息)。但是正如 Magnus 所说,您仍然有 System.{out|in}
并且可以按如下方式使用它们:
package de.scrum_master.Whosebug;
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.Whosebug.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.Whosebug;
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.
我有两个程序:
- 首先,使用Console对象读写数据
- 其次,应该运行首先使用一些动态计算的参数
第二个程序代码如下所示:
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();
当第一个程序从第二个开始时,System.console() 为 null 并且失败并出现 NPE。
所以,问题是:有什么方法可以 运行 另一个可用 System.console() 的进程吗?
答案很简单:如果您 运行 您的启动器来自 IDE,如 Eclipse 或 IntelliJ IDEA,可能它没有在 System.console()
中设置首先,因此没有任何子进程可以继承。只需尝试从启动器向 System.console()
写入一些内容,它也会因同样的错误而失败。但是,如果您从 Cmd.exe 或 Git Bash 等交互式控制台启动启动器,启动器和通过 ProcessBuilder
启动的进程都可以写入 System.console()
。您的启动器甚至不需要 "cmd", "/c"
,无论是否使用这些参数,它都可以工作。
package de.scrum_master.Whosebug;
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.Whosebug.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.Whosebug;
public class MyApp {
public static void main(String[] args) {
System.console().printf("Hi, I am an externally started app!%n");
}
}
从 IntelliJ 启动时的控制台日志 IDEA:
Exception in thread "main" java.lang.NullPointerException
at de.scrum_master.Whosebug.Launcher.main(Launcher.java:11)
(...)
从 cmd.exe:
启动时的控制台日志Hi, I am the launcher app!
Hi, I am an externally started app!
如有任何 follow-up 问题,请随时提出。
更新: 如果您不介意外部程序 运行 在其自己的交互式控制台中而不是在 IDE 控制台中,您可以为此目的使用 Windows 命令 start
然后 cmd /c
(windows 在外部程序结束后立即关闭)或 cmd /k
(window 保持开放供您检查结果):
package de.scrum_master.Whosebug;
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.Whosebug.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();
}
}
但是如果你想 read/write from/to 那个控制台,你又回到了第 1 个方块。您问为什么不能将 System.console()
继承给子进程。好吧,那是因为它是 null
由于 Eclipse 和 IntelliJ 从 IDE 中启动 Java 程序的方式(请参阅 [此处] 了解背景信息)。但是正如 Magnus 所说,您仍然有 System.{out|in}
并且可以按如下方式使用它们:
package de.scrum_master.Whosebug;
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.Whosebug.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.Whosebug;
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.