带子进程的双向管道
Posted
技术标签:
【中文标题】带子进程的双向管道【英文标题】:bidirectional pipe with children process 【发布时间】:2020-08-04 20:09:23 【问题描述】:我想运行一个可以从/向父进程读取数据和向父进程写入数据的子进程,其方式是子进程使用标准 stdin/stdout,并且不使用命名管道。
我编写了简单的测试程序,这是它应该做的:
父母启动孩子,然后听它; 孩子向父母发送start
;
父母向孩子发送一个介于 1 和 5 之间的随机数;
孩子读取这个号码,如果号码等于3
,则发送yes
给父母,否则发送no
;
父母读取答案,如果收到yes
则退出,否则向孩子发送另一个随机数;
将日志打印到文件中以便更好地理解。
parent.sh
#!/usr/bin/env bash
# Usage: parent.sh ./child.sh
INPUT="/tmp/input"
OUTPUT="/tmp/output"
LOG_FILE="./logger"
echo "[parent] Start" >> $LOG_FILE
rm -f $INPUT $OUTPUT
mkfifo $INPUT $OUTPUT
echo "[parent] Starting child" >> $LOG_FILE
$1 > $INPUT < $OUTPUT &
echo "[parent] Reading child output..." >> $LOG_FILE
while read answer; do
echo "[parent] Received from child: $answer" >> $LOG_FILE
if [ "$answer" = "yes" ]; then
break
else
number=$(( ( RANDOM % 5 ) + 1 ))
echo "[parent] Sending to child: $number" >> $LOG_FILE
echo "$number" > $OUTPUT
fi
done < "$INPUT"
echo "[parent] end" >> $LOG_FILE
child.sh
#!/usr/bin/env bash
LOG_FILE="./logger"
SECRET_NUMBER=3
echo "[child] Start" >> $LOG_FILE
echo "start"
while read line; do
echo "[child] Received from parent: $line" >> $LOG_FILE
if [ "$line" == "$SECRET_NUMBER" ]; then
answer="yes"
else
answer="no"
fi
echo "[child] Sending to parent: $answer" >> $LOG_FILE
echo $answer
done
echo "[child] End" >> $LOG_FILE
我以子脚本作为参数 (parent.sh ./child.sh
) 执行父脚本,然后在另一个终端 (tail -f ./logger
) 中打开记录器。
似乎永远不会执行孩子:
[parent] Start
[parent] Starting child
[parent] Reading child output...
为什么?
如果我将$1 > $INPUT < $OUTPUT &
行替换为$1 > $INPUT &
,脚本会执行,但不会进入主循环就结束。
编辑:修复了echo answer
错误
【问题讨论】:
你说你不想使用命名管道,但你正在使用mkfifo
。
将“回显答案”更改为echo $answer
另外,您可能希望将父级的重定向移出循环并写入:... done < $INPUT > $OUTPUT
@Barmar 我不想在子脚本中使用命名管道,但在父脚本中可以。
@WilliamPursell 谢谢!这是公认的答案。
【参考方案1】:
有两个问题。一个是次要的:在孩子身上,你不小心写了echo answer
而不是echo $answer
。另一个很重要。通过在父级中写入echo $number > $OUTPUT
,您将在循环的每次迭代中关闭并重新打开fifo。相反,您希望保持打开状态并将重定向移到循环之外。那就是:
while read answer; do
echo "[parent] Received from child: $answer" >> $LOG_FILE
if [ "$answer" = "yes" ]; then
break
else
number=$(( ( RANDOM % 5 ) + 1 ))
echo "[parent] Sending to child: $number" >> $LOG_FILE
echo "$number"
fi
done < "$INPUT" > $OUTPUT
【讨论】:
【参考方案2】:我不能代表其他任何人,但如果我需要做这样的事情,我会运行一个本地 IRC 服务器并编写两个机器人(编程客户端;基本上使用脚本运行 XChat)代表父级和孩子。这将是我能想到的最简单的方法。
使用 IRC,您可以使用聊天频道或传入的私人消息作为事件触发器。因此,当孩子向他们所在的频道发送“开始”时,父母会立即检测到它。您可以使用这些触发器在 IRC 客户端本身之外执行代码。
【讨论】:
感谢您的建议。我想使用标准输入和标准输出,因为它们是简单的概念,并且子脚本必须尽可能易于访问,因为它们将由其他用户编写。以上是关于带子进程的双向管道的主要内容,如果未能解决你的问题,请参考以下文章