使用System.console启动另一个进程

Iva*_*van 8 java process processbuilder

我有两个程序:

  • 首先,它使用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();
Run Code Online (Sandbox Code Playgroud)

当第一个程序从第二个程序开始时,System.console()为空,它随NPE失败.

所以,问题是:有没有办法运行System.console()的另一个进程?

kri*_*aex 4

答案很简单:如果你从像Eclipse或IntelliJ IDEA这样的IDE运行你的启动器,可能它System.console()首先没有设置,因此子进程没有任何东西可以继承.只是尝试System.console()从启动器写一些东西,它也会失败,同样的错误.但是如果你从像Cmd.exe或Git Bash这样的交互式控制台启动你的启动器,启动器和启动过程ProcessBuilder都可以写入System.console().您的启动器甚至不需要"cmd", "/c",它可以使用或不使用这些参数.

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();
  }
}
Run Code Online (Sandbox Code Playgroud)
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");
  }
}
Run Code Online (Sandbox Code Playgroud)

从IntelliJ IDEA启动时的控制台日志:

Exception in thread "main" java.lang.NullPointerException
    at de.scrum_master.stackoverflow.Launcher.main(Launcher.java:11)
    (...)
Run Code Online (Sandbox Code Playgroud)

从cmd.exe启动时的控制台日志:

Hi, I am the launcher app!
Hi, I am an externally started app!
Run Code Online (Sandbox Code Playgroud)

随意提出任何后续问题.


更新:如果您不介意外部程序在其自己的交互式控制台中而不是在IDE控制台中运行,则可以使用Windows命令start进行此操作,然后cmd /c(外部程序结束后立即关闭cmd /k窗口)或(窗口)保持开放状态,以便检查结果):

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();
  }
}
Run Code Online (Sandbox Code Playgroud)

但是如果那时你想要从/向该控制台读/写,你就回到了#1广场.您问为什么不能继承System.console()子进程.好吧,那是因为它是null由于Eclipse和IntelliJ从IDE中启动Java程序的方式(参见[此处]获取背景信息).但正如马格努斯所说,你仍然System.{out|in}可以使用它们,如下所示:

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.");
  }
}
Run Code Online (Sandbox Code Playgroud)
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("----------------------------------------");
  }
}
Run Code Online (Sandbox Code Playgroud)
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.
Run Code Online (Sandbox Code Playgroud)