英文:
How can I run my own personalized bash shell in Java?
问题
我的目标是在Linux的bash shell中执行一个个性化的提示,并执行命令。
结果应该类似于图片中的样子。
ProcessBuilder builder = new ProcessBuilder();
builder.command("sh");
builder.directory(new File(System.getProperty("user.home")));
Process process = builder.start();
或者
String homeDirectory = System.getProperty("user.home");
Process process;
try {
    System.out.print("# MyShell> ");
    process = Runtime.getRuntime().exec(String.format("sh", homeDirectory));
} catch (IOException e) {
    System.err.println("Error in exec() method");
    e.printStackTrace();
}
控制异常。
所以基本上是在Java中启动一个个性化的功能性bash提示符,并控制错误消息(比如改变其颜色)。
还可以通过个性化的单词来控制退出,比如使用'quit'代替'exit'。
注意:我不是在尝试执行类似于'tree'或者'ls'之类的脚本或命令,就像在许多其他示例中所看到的那样。我正在寻找一种方法来运行我的个性化bash,并在bash中或接近这个想法的范围内进行所有系统允许的操作。
英文:
My goal is to execute a personalized prompt in a bash shell in linux and to execute orders.
The result should be like in the image.
So I suppose I should start with something like:
ProcessBuilder builder = new ProcessBuilder();
builder.command("sh");
builder.directory(new File(System.getProperty("user.home")));
Process process = builder.start();
or
String homeDirectory = System.getProperty("user.home");
Process process;
try {
    System.out.print("# MyShell> ");
    process = Runtime.getRuntime().exec(String.format("sh", homeDirectory));
} catch (IOException e) {
    System.err.println("Error en el método exec()");
    e.printStackTrace();
}
Controlling the exceptions.
So basically is to start a personalized functional bash prompt in java and control the error messages (like changing its color).
Also controlling the exit with a personalized word, like 'quit' instead of 'exit'.
Note: I am not trying to execute a script or some commands like 'tree' or 'ls' like in many other examples around here. I'm looking for a way to run my personalized bash and do everything that the system allows me in bash or close to this idea.
答案1
得分: 1
这个问题比表面上看起来要复杂,因为涉及到 shell、终端和您的程序之间的相互作用。
鉴于要求如下:
- 自定义 shell 提示符
 - 自定义命令
 - 使 shell 正常工作
 - 拦截程序输出
 
我的建议是:
- 从 shell 方面进行自定义设置
 - 创建一个伪终端(pty)来欺骗程序,使其认为它们在写入终端。在 Linux/Mac 上的 Java 中,通过 
script工具可以简单实现这一点。 
以下是示例 shell 配置文件 myrc:
export PS1='# MyShell> '
quit() { exit "$@"; }
以下是启动自定义 shell 的 Shell.java:
import java.io.*;
import java.nio.charset.*;
import java.lang.ProcessBuilder.Redirect;
class Shell {
  public static void main(String[] args) throws IOException {
    ProcessBuilder builder = new ProcessBuilder(
        // 使用 'script' 欺骗程序,使其认为 stdout 是 tty。
        "script", "-q", "/dev/null",
        // 运行带有提示符和命令自定义的 bash
        "bash", "--rcfile", "myrc"
        );
    builder
      // 从当前 TTY 获取输入
      .redirectInput(Redirect.INHERIT)
      // 但将 stdout/stderr 管道化以拦截它们
      .redirectErrorStream(true)
      .redirectOutput(Redirect.PIPE);
    Process proc = builder.start();
    InputStream input = proc.getInputStream();
    byte[] buffer = new byte[65536];
    int read;
    String search = "world";
    while((read = input.read(buffer, 0, buffer.length)) != -1) {
      // 简化假设我们只会得到文本数据,并且只会在足够大以包含整个搜索字符串的缓冲区中收到数据
      String s = new String(buffer, 0, read, StandardCharsets.UTF_8);
      // 用高亮/着色的字符串替换搜索词
      s = s.replaceAll(search, "\u001B[35m<<$0>>\u001B[m");
      System.out.print(s);
    }
    System.out.println("Java 程序正在退出...");
  }
}
下面是示例会话,显示了自定义提示符、正常工作的文本拦截(将单词 "world" 改为紫色,并用尖括号括起来),以及最后的自定义 quit 命令:
$ javac Shell.java && java Shell
# MyShell> echo "hello world"
hello <<world>>
# MyShell> quit
exit
Java 程序正在退出...
$
英文:
This problem is more complex than it appears due to the interplay of the shell, the terminal, and your program.
Given that the requirements are:
- Custom shell prompt
 - Custom commands
 - Have the shell work normally
 - Intercept the program output
 
My suggestion is:
- Do the customizations from the shell side
 - Create a pty to fool programs into thinking they're writing to a terminal. In Java on Linux/Mac, a simple way to do this is via the 
scripttool. 
Here's an example shell configuration file myrc:
export PS1='# MyShell> '
quit() { exit "$@"; }
and here's Shell.java to start the custom shell:
import java.io.*;
import java.nio.charset.*;
import java.lang.ProcessBuilder.Redirect;
class Shell {
  public static void main(String[] args) throws IOException {
    ProcessBuilder builder = new ProcessBuilder(
        // Use 'script' to fool programs into thinking stdout is a tty.
        "script", "-q", "/dev/null",
        // Run bash with prompt and command customizations
        "bash", "--rcfile", "myrc"
        );
    builder
      // Get input from the current TTY
      .redirectInput(Redirect.INHERIT)
      // But pipe stdout/stderr to intercept it
      .redirectErrorStream(true)
      .redirectOutput(Redirect.PIPE);
    Process proc = builder.start();
    InputStream input = proc.getInputStream();
    byte[] buffer = new byte[65536];
    int read;
    String search = "world";
    while((read = input.read(buffer, 0, buffer.length)) != -1) {
      // Simplify by assuming we only get text data, and only
      // in buffers large enough to contain the entire search string
      String s = new String(buffer, 0, read, StandardCharsets.UTF_8);
      // Replace search word with a highlighted/colored string.
      s = s.replaceAll(search, "\u001B[35m<<$0>>\u001B[m");
      System.out.print(s);
    }
    System.out.println("Java program is exiting...");
  }
}
Example session showing custom prompt, working text interception (making the word "world" purple and surrounded by angle brackets), and finally the custom quit command:
$ javac Shell.java && java Shell
# MyShell> echo "hello world"
hello <<world>>
# MyShell> quit
exit
Java program is exiting...
$
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。



评论