bash 与 java 的子进程交谈?

Posted

技术标签:

【中文标题】bash 与 java 的子进程交谈?【英文标题】:bash talking to a sub-process of java? 【发布时间】:2011-09-22 00:43:38 【问题描述】:

我正在尝试制作一个 bash 脚本,该脚本将与一个通过 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 次,并且通常需要几分钟的服务器启动并运行命令才能使用(否则为垃圾),有时可能永远不会在当前服务器中存在命令运行,或几天)。我可以在终端中使用脚本进行对话时写入文件,因此主脚本不会很难,但处理程序脚本中会包含什么?

最终工作脚本

运行.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

我还没有通过严格的测试,但它应该会继续工作

【问题讨论】:

我认为一个管道就足够了 那么,管道可以吗?谷歌在这方面对我帮助不大。我如何通过终端获取回显命令以供用户查看并回显(?)到管道(我会说正常回显) 【参考方案1】:

一种方法是结合使用 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.sh) 输入的示例 shell 程序

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

运行:

    创建一个空的 input.txt 文件(触摸 input.txt) 在一个终端窗口中运行 java-wrapper.pl 在另一个终端窗口中运行 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

EDIT2: 正如OP提到的,正确的命令应该是

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' 有什么帮助吗? 它仍然没有进入java,我将它改为:“gnome-terminal -x java -jar server.jar | tail -f input.txt &” 因为我发现服务器是在我的程序之前获取输入,我将在完成这部分后查看tail命令... 我得到了它的工作,我会用结果更新问题 我的错。 tail 应该在 java 之前而不是之后。我认为它是通过查看tail而不是java的输出来工作的。很高兴你知道了。 没关系,我们都会在某些时候犯错,此外,你让我得到了答案,对此我很感激【参考方案2】:

interesting_command_generating_script.sh | java net.vzybilly.MyCoolClass

interesting_command_generating_script.sh 会偶尔(如果它认为合适)将字符串写入其标准输出(例如,echo)。

MyCoolClass 然后将从标准输入中读取。您可以为此使用InputStreamReader。

【讨论】:

但是如何将一些输出也发送到终端呢? (两个出局) 如果您正在谈论 java 将输出写入终端,它可以使用 System.out 来完成。如果您的意思是有趣的命令...写入终端,那么是的,该管道最终会将其发送到 java 类。您真正的问题可能是定义这两个元素中的每一个的角色,并确保每个元素只做一件事。这就是 UNIX 管道擅长的地方:“做一件事,做好”。 我做了一个编辑(总共花了 40 分钟),更好地解释了需要发生的事情,不过感谢您的帮助,vzybilly

以上是关于bash 与 java 的子进程交谈?的主要内容,如果未能解决你的问题,请参考以下文章

在bash脚本中获取命令的子进程

使用 asyncio 将 bash 作为 Python 的子进程运行,但 bash 提示被延迟

实时打印使用 Python 中的子进程启动的 bash 命令的结果

go - 如何在go中打印正在运行的子进程的实时输出?

持久的子进程管道 - 没有读取标准输出

Supervisor的作用与配置:实现对异常中断的子进程的自动重启