Bash FIFOs没有按预期工作-如何调试它



我得到了以下任务。我们有一个预先构建的二进制GUI,保存在$GAME_BIN中。我必须编写一个脚本,将GUI与AI引擎连接起来。这是我的代码,非常自我描述。在这种情况下,我们有:GAME_BIN=./sredniowiecze_guiai1=./idle_ai.shai2=./idle_ai.sh

#!/bin/bash
# arguments parsing and setting $args - not posting this here
gui_outpipe=$(mktemp -u)
gui_inpipe=$(mktemp -u)
ai1_outpipe=$(mktemp -u)
ai1_inpipe=$(mktemp -u)
ai2_outpipe=$(mktemp -u)
ai2_inpipe=$(mktemp -u)
mkfifo $gui_outpipe $gui_inpipe $ai1_outpipe $ai1_inpipe $ai2_inpipe $ai2_outpipe
printinit 1 > $ai1_inpipe &
printinit 2 > $ai2_inpipe &
$GAME_BIN $args < $gui_inpipe &
$ai1 < $ai1_inpipe > $ai1_outpipe &
$ai1 < $ai2_inpipe > $ai2_outpipe &
while true; do
echo "Started the loop"
while true; do
read line < $ai1_outpipe || echo "Nothing read"
echo $line
if [[ $line ]]; then
echo "$line" > $gui_inpipe
echo "$line" > $ai2_inpipe
if [[ "$line" == "END_TURN" ]]; then
break
fi
fi
done
sleep $turndelay
while true; do
read line < $ai2_outpipe || echo "nothing read"
echo $line
if [[ $line ]]; then
echo "$line" > $gui_inpipe
echo "$line" > $ai2_inpipe
if [[ "$line" == "END_TURN" ]]; then
break
fi
fi
done
sleep $turndelay
done
wait

我创建了一个包含在idle_ai.sh中的简单空闲AI

#!/bin/sh
while true; do
echo END_TURN
done

然后根本没有接收到来自GUI的END_TURN消息。另一方面,第(*)行中的第二个END_TURN没有被脚本接收到。如果我使用我自己的C编写的AI——非常长的代码,而不是在这里发布,那么在while循环的第二次运行中不会收到来自AI的信息

我完全不知道如何调试它。

由于我不急于运行未装箱的二进制文件,所以我通过firejail ./game.sh [irrelevant parameters]调用该脚本

编辑添加set -x后,输出为

INIT 10 3 1 1 1 3 9
+ [[ -n ./idle_ai.sh ]]
+ [[ -n '' ]]
+ [[ -n ./idle_ai.sh ]]
+ printinit 1
+ ./sredniowiecze_gui -human2
+ true
+ echo 'Started the loop'
Started the loop
+ true
+ read line
+ ./idle_ai.sh
+ echo 'INIT 10 3 1 1 1 3 9'
+ echo END_TURN
END_TURN
+ [[ -n END_TURN ]]
+ echo END_TURN
+ [[ END_TURN == END_TURN ]]
+ break
+ true
+ read line
+ echo MOVE 5 9 5 8
MOVE 5 9 5 8
+ [[ -n MOVE 5 9 5 8 ]]
+ echo 'MOVE 5 9 5 8'

在AI与AI模式下:

INIT 10 3 1 1 1 3 9
+ [[ -n ./idle_ai.sh ]]
+ [[ -n ./idle_ai.sh ]]
+ printinit 1
+ printinit 2
+ ./sredniowiecze_gui
+ ./idle_ai.sh
+ true
+ echo 'Started the loop'
Started the loop
+ echo 'INIT 10 3 1 1 1 3 9'
+ true
+ read line
+ ./idle_ai.sh
+ echo 'INIT 10 3 2 1 1 3 9'
+ echo END_TURN
END_TURN
+ [[ -n END_TURN ]]
+ echo END_TURN
+ echo END_TURN
+ [[ END_TURN == END_TURN ]]
+ break
+ sleep 1
+ true
+ read line
+ echo END_TURN
END_TURN
+ [[ -n END_TURN ]]
+ echo END_TURN
+ echo END_TURN
+ [[ END_TURN == END_TURN ]]
+ break
+ sleep 1
+ true
+ echo 'Started the loop'
Started the loop
+ true
+ read line

EDIT2我做了建议的更改,现在我的代码是:

printinit 1 > $ai1_inpipe &
printinit 2 > $ai2_inpipe &
$GAME_BIN $args < $gui_inpipe &
$ai1 < $ai1_inpipe > $ai1_outpipe &
echo $!
$ai2 < $ai2_inpipe > $ai2_outpipe &
echo $!
while true; do
echo "Started the loop"
while true; do
read -u3 line || echo "Nothing read"
echo $line
if [[ $line ]]; then
echo "$line" > $gui_inpipe
echo "$line" > $ai2_inpipe
if [[ "$line" == "END_TURN" ]]; then
break
fi
fi
done
sleep $turndelay
while true; do
read -u4 line || echo "nothing read"
echo $line
if [[ $line ]]; then
echo "$line" > $gui_inpipe
echo "$line" > $ai1_inpipe
if [[ "$line" == "END_TURN" ]]; then
break
fi
fi
done
sleep $turndelay
done 3<$ai1_outpipe 4<$ai2_outpipe

现在,尽管$ai2进程仍在运行,但脚本仍停留在echo "$line" > $ai1_inpipe行。

编辑3。现在set -x的日志是

INIT 10 3 1 1 1 3 9
+ [[ -n ./idle_ai.sh ]]
+ [[ -n ./idle_ai.sh ]]
+ printinit 1
+ printinit 2
+ ./sredniowiecze_gui
+ echo 26
26
+ ./idle_ai.sh
+ echo 'INIT 10 3 1 1 1 3 9'
+ echo 27
27
+ ./idle_ai.sh
+ echo 'INIT 10 3 2 1 1 3 9'
+ true
+ echo 'Started the loop'
Started the loop
+ true
+ read -u3 line
+ echo END_TURN
END_TURN
+ [[ -n END_TURN ]]
+ echo END_TURN
+ echo END_TURN
+ [[ END_TURN == END_TURN ]]
+ break
+ sleep 1
+ true
+ read -u4 line
+ echo END_TURN
END_TURN
+ [[ -n END_TURN ]]
+ echo END_TURN
+ echo END_TURN

如果您在通话前后添加echo FOO,如下所示:

echo FOO
echo "$line" > $ai1_inpipe
echo BAR

则CCD_ 14被执行而CCD_。

您使用的是read < input,它吸收了所有输入,只使用了第一行。相反,您应该从打开的文件描述符中读取read,如下所示:

EDIT:与使用echo写入fifo文件相同

while true; do
echo "Started the loop"
while true; do
read -u3 line || echo "Nothing read"
...
echo "$line" >&5
echo "$line" >&6
...
done
sleep $turndelay
while true; do
read -u4 line || echo "nothing read"
...
echo "$line" >&5
echo "$line" >&7
...
sleep $turndelay
done 3<$ai1_outpipe 4<$ai2_outpipe 5>$gui_inpipe 6>$ai2_inpipe 7>$ai1_inpipe

有关以下主题的更多帮助,请参阅以下链接:

  • BashGuide命名管道
  • BashFAQ 085

相关内容

  • 没有找到相关文章

最新更新