gpt4 book ai didi

java - 在管道 ProcessBuilder 中运行的 Grep 永远不会终止

转载 作者:太空宇宙 更新时间:2023-11-04 12:43:39 27 4
gpt4 key购买 nike

我正在尝试在 java 中实现一个 shell,作为要求的一部分,我只能使用 ProcessBuilder 类来重定向 IO。不允许进程 IO 流的线程或轮询。我一切正常,但我似乎无法让管道 (|) 正常工作。我目前实现它们的方式是为每个子命令创建一个不同的 ProcessBuilder,然后将每个子命令的输入设置为它之前的输出,管道的头部和尾部链接到 shell 的继承 IO 流.这工作正常,但某些进程(特别是 grep)不会终止,并且在以这种方式使用时从不输出任何内容。 Grep 在没有管道 (grep -i) 的情况下工作正常,但是当在管道 (ls | grep txt) 中运行时,它永远不会终止,尽管 ls 已经完成(这可以通过检查 shell 的进程树来验证)。

我知道正常的解决方案是只轮询每个进程的 IO 流并在它们进入时复制字节,或者创建一个包装类来创建一个线程来为您执行此操作。不幸的是,我不允许使用任何一种方法来完成这项任务,所以我只能使用 ProcessBuilder。

谷歌搜索一无所获,如有任何帮助,我们将不胜感激!相关代码如下:

/*
Runs a pipeline of commands. Each String argument is a command to execute and pipe to the next.
*/
private static void runExternalMulti(String[] cmds) {
//array of process builders in order of pipe
ProcessBuilder[] builders = new ProcessBuilder[cmds.length];
for (String cmd : cmds) {
cmd = cmd.trim();
for (int i = 0; i < builders.length; i++) {
builders[i] = createProcessBuilder(cmd.split("\\s+"));
}
}

//set ProcessBuilder pipes
//skip last index
for (int i = 0; i < builders.length - 1; i++) {
ProcessBuilder first = builders[i];
ProcessBuilder next = builders[i+1];
first.redirectOutput(next.redirectInput());
next.redirectInput(first.redirectOutput());
}

//start each process and hold in array
Process[] processes = new Process[builders.length];
for (int i = 0; i < builders.length; i++) {
processes[i] = builders[i].start();
}

//loop until all process have finished
boolean running = true;
while (running) {
running = false;
for (Process process : processes) {
if (process.isAlive()) {
running = true;
}
}
//pause to avoid churning CPU
Thread.sleep(10);
}
}

/*
Creates a processBuilder for the command specified in parts. Each string is a space-separated part of the command line, with the first being the executable to run.
*/
private static ProcessBuilder createProcessBuilder(String[] parts) {
ProcessBuilder builder = new ProcessBuilder();
builder.directory(currentDirectory); //set working directory
//set process to share IO streams with java shell
builder.redirectInput(ProcessBuilder.Redirect.INHERIT);
builder.redirectOutput(ProcessBuilder.Redirect.INHERIT);
builder.redirectError(ProcessBuilder.Redirect.INHERIT);

//parse each token and pull out IO redirection and background characters
List<String> command = new ArrayList<>(parts.length);
for (int i = 0; i < parts.length; i++) {
//Ignore the background character, it has been read or ignored by the calling function
if (i == parts.length - 1 && "&".equals(parts[i])) {
continue; //don't parse an ending "&" as a command parameter
}
String str = parts[i];
//redirect to a file
if (">".equals(str)) {
if (i < parts.length - 1) {
File outFile = new File(currentDirectory, parts[i + 1]);
builder.redirectOutput(outFile);
builder.redirectError(outFile);
}
i++; //make sure to skip the redirected file name
//read in from a file
} else if ("<".equals(str)) {
if (i < parts.length - 1) {
File inFile = new File(currentDirectory, parts[i + 1]);
if (inFile.isFile()) {
builder.redirectInput(inFile);
}
}
i++; //make sure to skip the redirected file name
} else {
command.add(parts[i]);
}
}
builder.command(command);
return builder;
}

最佳答案

管道是命令行解释器的特性。所以你必须选择:

  1. 将带有管道的命令包装到 bash -c 中(因此您将拥有带有 2 个参数的命令 bash)
  2. 通过管道拆分命令,逐行读取一个标准输出并将其发送到第二个标准输入。

如果我理解正确,你不能使用后者,但也许允许使用 first?

关于java - 在管道 ProcessBuilder 中运行的 Grep 永远不会终止,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39428933/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com