【问题标题】:Two way communication with process与进程的两种方式通信
【发布时间】:2016-09-27 22:29:53
【问题描述】:

我给出了一些编译好的程序。我想通过程序 stdin 和 stdout 从我的 bash 脚本与它通信。我需要双向沟通。程序不能在信息交换之间被杀死。我怎么能这样做? 简单例子:

让该程序编译为部分求和 (C++),脚本结果将是该总和的平方。程序:

int main() {
    int num, sum = 0;
    while(true) {
        std::cin >> num;
        sum += num;
        std::cout << sum << std::endl;
    }
}

我的脚本应该是这样的:

for i in 1 2 3 4; do
    echo "$i" > program
    read program to line;
    echo $((line * line))
done

如果在程序中我有for(int i = 1; i &lt;= 4; ++i),那么我可以这样做:

exec 4< <(./program); # Just read from program

for i in 1 2 3 4; do
    read <&4 line;
    echo "sh: $((line * line))";
done

更多请看here。另一方面,如果在程序中我有std::cout &lt;&lt; sum * sum;,那么解决方案可能是:

exec &3> >(./program); # Write to program

for i in 1 2 3 4; do
    echo "$i" > &3
done

我的问题是与其他进程/程序的双向通信。我不必使用 exec。我无法安装第三方软件。仅 Bash 的解决方案,没有文件,会很好。

如果我运行其他进程,最好知道 pid 在脚本结束时杀死它。

我考虑在未来与两个或三个进程进行通信。第一个程序的输出可能取决于第二个程序的输出,也取决于第二个程序的输出。就像进程的沟通者。

但是,我无法重新编译程序并更改某些内容。我在程序中只有标准输入和标准输出通信。

【问题讨论】:

  • 我猜你的 C++ 程序应该支持 POSIX 管道。检查这个答案stackoverflow.com/a/2789967/524743
  • 重定向(使用&gt;&lt;)不能这样工作。你想要的绝对是管道
  • @Samuel 谢谢你的回答。如果我可以编辑 Cpp 程序,那么我知道如何在两个进程之间进行通信。但是重新编译程序并改变它是不可能的。我在程序中只有标准输入和标准输出通信。
  • 如果您可以安装其他软件,您可以使用 [expect|linux.die.net/man/1/expect]。这样您就可以编写一个交互式过程的脚本。
  • @cb0 Program Expect (5.45) 安装在目标机器上。我会读到它。谢谢。

标签: linux bash


【解决方案1】:

如果您的 bash 版本高于 4.0,则可以使用 coproc

但是,不要忘记您要传达的命令的输入/输出可能会被缓冲。

在这种情况下,您应该使用 stdbuf -i0 -o0 之类的东西来包装命令

参考:How to make output of any shell command unbuffered?

这是一个例子

#!/bin/bash
coproc mycoproc {
  ./a.out # your C++ code
}
# input to "std::cin >> num;"
echo "1" >&${mycoproc[1]}
# get output from "std::cout << sum << std::endl;"
# "-t 3" means that it waits for 3 seconds
read -t 3 -u ${mycoproc[0]} var 
# print it
echo $var

echo "2" >&${mycoproc[1]}
read -t 3 -u ${mycoproc[0]} var
echo $var

echo "3" >&${mycoproc[1]}
read -t 3 -u ${mycoproc[0]} var
echo $var

# you can get PID
kill $mycoproc_PID

输出将是

1
3
6

如果你的 bash 早于 4.0,使用 mkfifo 可以做同样的事情:

#!/bin/bash
mkfifo f1 f2
exec 4<> f1
exec 5<> f2
./a.out < f1 > f2 &

echo "1" >&4
read -t 3 -u 5 var
echo $var

rm f1 f2

【讨论】:

    【解决方案2】:

    考虑到您的 C++ 程序从标准输出读取并打印到标准输出,很容易将其放入一个简单的管道链中:

    command_that_writes_output | your_cpp_program | command_that_handle_output
    

    在您的特定情况下,您可能需要修改程序以仅处理一个输入并编写一个输出,并删除循环。因为那样你就可以很简单地做到这一点,就像这样:

    for i in 1 2 3 4; do
        result=`echo $i | ./program`
        echo $((result * result))
    done
    

    【讨论】:

    • 感谢您的回答,但在我未简化的问题中,第二个数字给程序依赖于程序的早期输出,甚至其他程序输出,所以我不能那样做。
    • @Tacet 然后继续管道链?这就是在 POSIX 世界中将一个程序的输出作为输入链接到另一个程序的方式。
    猜你喜欢
    • 1970-01-01
    • 2019-05-10
    • 1970-01-01
    • 2013-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-15
    • 1970-01-01
    相关资源
    最近更新 更多