Bash如何与Java的子进程通信?

3
我正在尝试编写一个bash脚本,用于与等待我的命令的Java程序进行通信。该Java程序作为服务器运行,具有非常有限的GUI界面,因此我正在努力为其制作基本UI,以增加其功能。如果您对此主题有任何帮助,将不胜感激。 目前我尝试启动它的方法如下:
INPUTFD=258
#exec "$INPUTFD"> >(exec java -Xmx512M -Xms512M -jar server.jar)

使用类似以下命令:

(echo "kick ${user}") >&"$INPUTFD"

而我现在正在使用的

java -Xmx512M -Xms512M -jar server.jar & echo "Started"

pid=$!

但我在谷歌上找不到任何有助于使用echo或类似方法来帮助这里的内容。

我想使用管道可能会起作用,但我认为我必须将一大块脚本移动到另一个文件中使用管道,然后我的脚本中的echo命令似乎不再起作用,所以,我对任何想法都持开放态度。谢谢vzybilly

编辑:(第二次输入此内容,如果现在不是全部都有意义,很抱歉)在谷歌搜索和深入思考这个想法后,我发现了一个更好的提问方式。脚本(现在应称为主程序或主脚本)将与用户交互,并根据用户告诉主程序的内容告诉java程序某些东西,有时它将与用户输入相同,在其他情况下,它将是主程序自己根据用户对主程序说的内容制作的东西。主程序将处理两个输出和一个输入(终端双向,只有一种方式到java程序)

我认为可能有效的一种方法是在主脚本和java程序之间有一个文件和另一个脚本,另一个脚本将被命名为server_handler.sh(我们将其称为处理脚本),它的工作方式是在主脚本中像这样的命令来启动它:

server_handler.sh | java -jar server.jar

然后,当我们想从主脚本向服务器发送信息时,我们这样做:

echo "what we want to tell the sever" >> cmd.tmp
通过这种方式,处理程序脚本所做的一切就是从文件中读取并通过管道将其回显到Java程序中。我遇到的问题是,即使在读取时向文件添加了内容,如何让处理程序脚本知道它已经读取了什么或删除它已经读取的行?(有些命令会连续放入27次,在服务器运行后通常需要几分钟才能使用命令(否则无效),有时可能永远没有命令在当前运行的服务器上,或者要等好几天)。我可以在脚本中在终端对话时写入文件,因此主要脚本不难编写,但处理程序脚本中会有什么呢? 最终工作脚本: run.sh:
#!/bin/bash
tail -f input.txt | java server.jar &
echo "Do Not Close This Window Or Press Enter Till Server Is Off Line,"
read -p "  Doing So Will Force Close The Server, Please press enter when done."

主脚本调用:

gnome-terminal -x ./run.sh

向服务器发出命令:

echo "command to server" >> input.txt

我还没有经过严格测试,但它应该能够保持正常工作。


我认为一个管道就足够了。 - Dimitri
那么,使用管道可以实现吗?在这方面,谷歌对我帮助不大。我该如何将echo命令传递到终端以供用户查看,并通过管道进行回显(我会说是普通的echo)? - vzybilly
2个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
2

一种方法是使用perl和shell脚本的组合。但理想的选项是将服务器实现为Socket服务器,这样您就可以从任何地方连接。使用netcat命令,您甚至可以从shell脚本向套接字服务器发送消息。

这里有一个perl/shell脚本选项的示例。Java应用程序从文件input.txt获取输入,该文件可以在运行时追加。

EchoServer.java

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class EchoServer {
    public static void main(String[] args) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        String input = null;
        System.out.println("EchoServer started");
        while((input = reader.readLine()) != null) {
            System.out.println("Input: " + input);

            if("exit".equalsIgnoreCase(input)) {
                System.exit(0);
            }
        }
    }
}

Java应用的Perl封装(java-wrapper.pl)

#!/usr/bin/perl -w
use strict;

open DATA, "java EchoServer | tail -f input.txt |"   or die "Couldn't execute program: $!";
while(my $line = <DATA>) {
  chomp($line);
  print "$line\n";
}
close DATA;

一个发送输入给Java应用程序的示例Shell程序(shell.sh)

for i in 1 2 3 4 5 6;
do
  echo "sending $i" >> input.txt;
  sleep 1;
done

操作步骤:

  1. 创建一个空的 input.txt 文件(touch input.txt)
  2. 在一个终端窗口中运行 java-wrapper.pl
  3. 在另一个终端窗口中运行 shell.sh

输出结果:

$ ./java-wrapper.pl
sending 1
sending 2
sending 3
sending 4
sending 5
sending 6

编辑: 我刚刚意识到,你不需要PERL部分。你只需调用以下代码即可,

java EchoServer | tail -f input.txt

从主脚本中使用echo命令追加input.txt文件。

$ java EchoServer | tail -f input.txt
sending 1
sending 2
sending 3
sending 4
sending 5
sending 6

编辑2:正如原帖所提到的,正确的命令应该是

tail -f input.txt | java EchoServer

$ tail -f input.txt |java EchoServer
EchoServer started
Input: sending 1
Input: sending 2
Input: sending 3
Input: sending 4
Input: sending 5
Input: sending 5

我觉得这个已经接近了,但还是没有运气,我也希望能够全部在bash中完成,但如果它能工作,那就行了。我认为问题在于我无法编辑server.jar本身,而且当我像这样调用它时,perl脚本似乎会同时输出到服务器和主脚本:'./handler' 有什么帮助吗? - vzybilly
还是无法进入Java,我将其更改为以下内容:“gnome-terminal -x java -jar server.jar | tail -f input.txt &”,因为我发现服务器在我的程序之前获取了输入,完成此部分后,我将查看tail命令... - vzybilly
我已经让它工作了,我会更新问题并附上结果。 - vzybilly
我的错,tail 应该在 java 之前而不是之后。我以为它能工作,因为看到了 tail 的输出而没有检查 java 的输出。很高兴你找出来了。 - Jeesmon
没关系,我们都会在某个时候犯错,而且你帮我找到了答案,我很感激。 - vzybilly

2

interesting_command_generating_script.sh | java net.vzybilly.MyCoolClass

这个命令将会执行一个有趣的脚本 interesting_command_generating_script.sh 并将其输出传递给 Java 程序 net.vzybilly.MyCoolClass

interesting_command_generating_script.sh 会在需要时向标准输出中写入字符串(例如使用 echo 命令)。

MyCoolClass 将从标准输入中读取数据。你可以使用 InputStreamReader 来实现。


但是,还有没有将一些输出显示到终端上呢?(两个输出) - vzybilly
如果你在谈论Java写输出到终端,那么它可以使用System.out来实现。如果你的意思是说interesting_command...写入终端,那么是的,这个管道最终会将其发送到Java类。你真正的问题可能是定义每个元素的角色,并确保每个元素只做一件事。这就是UNIX管道的优势所在:“做一件事情,做好它”。 - joeslice
我进行了编辑(总共花费了过去40分钟的时间),更好地解释了需要发生的事情,感谢您的帮助,vzybilly。 - vzybilly

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,