英文:
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
script
tool.
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...
$
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论