Bash 将标准输入重定向到程序并将其输出重定向到另一个程序的脚本

Bash script redirecting stdin to program and its output to another program

我正在学习 bash 脚本。这是我第一次必须将输出重定向到另一个程序,但我不知道该怎么做。

我必须编写一个连接 GUI 程序的脚本,以及零个、一个或两个程序 - 我需要两个玩家,都可以是计算机或人类。 GUI 从两个程序(或人类,我的意思是来自标准输入)获得输出。

假设有一个人和一个comp_player。人类使用 stdin 发出命令,此命令必须重定向到 运行 GUI 程序和 运行 comp_player,两者都需要输入。然后,comp_player 的输出必须重定向到 GUI(如果有第二台计算机播放器,也有必要将此输出重定向到第二台计算机播放器的输入)。回合结束。

我知道如何创建一个文件来读写和重定向输入或输出。例如:

echo "anything" >&3
exec 3<>sometextfile
read line <&3
echo $line

但我不知道如何重定向,例如,我刚读到的行到 运行 需要输入并捕获其输出的程序,我可以将其重定向到 GUI 和另一个程序。

我知道它不像上面的代码那么简单,我必须使用名为命名管道的东西,但我试图阅读一些教程,但未能编写工作脚本。

你能给我一个脚本片段的例子吗,比如:

(gui程序和电脑播放器程序是运行)

-从标准输入读取行

-"sends" gui 程序和 comp_player 输入的行

-"reads" 从 comp_player 输出并将其写入标准输出并且 "sends" 将其写入 gui 输入

命名管道是一种特殊的文件,用于连接两个完全独立的程序的输入和输出。可以把它想象成一个临时缓冲区,或者一个在两个互不了解的程序之间共享的数组。这使它们成为在两个程序之间共享消息并使它们非常有效地进行通信的绝佳工具。

作为查看命名管道如何工作的简单测试,在同一目录中打开两个终端,然后在第一个终端中键入 mkfifo mypipe 以创建文件。现在,要使用它,只需向其中写入一些内容,例如:

echo "A very important message" > mypipe

现在消息存储在管道文件中,您会看到终端被阻塞,就好像 echo 还没有完成。转到第二个终端并使用以下命令获取管道的内容:

cat mypipe

您将从第一个终端打印出存储在管道中的 "very important message" 。请注意管道现在是空的,您根本无法从中再次获取消息。


既然您知道了命名管道的工作原理,下面是一个非常简单的示例,说明三个玩家如何进行通信。请注意,我们不能为所有这些使用单个文件,而是创建单独的管道来通信 player1 和 player2、player1 和 gui,以及 player2 和 gui。我猜 gui 程序是用另一种语言编写的,但我会把它留给你。

玩家 1(人类)

player2pipe="pipe1"
guipipe="pipe2"

#First make sure we have our files
if [ ! -p $player2pipe ]; then
    mkfifo $player2pipe
fi

if [ ! -p $guipipe ]; then
    mkfifo $guipipe
fi


while true; do #Or until the game ends
    echo -n "Do something: "
    read move
    # Send our move to the other two players
    echo $move > $player2pipe
    echo $move > $guipipe

    playermove=$(cat $player2pipe) # Read other player's move from the pipe file. The execution will pause until there's something to read

    # Do something about that move here

done

PLAYER2(电脑)

player1pipe="pipe1"
guipipe="pipe3"


if [ ! -p $player1pipe ]; then
    mkfifo $player1pipe
fi

if [ ! -p $guipipe ]; then
    mkfifo $guipipe
fi


while true; do

    playermove=$(cat $player1pipe)

    # Do something about that move here

    move="A very good move made by a computer" #Obviously you will have to generate a new move
    echo $move > $player1pipe
    echo $move > $guipipe

done

界面

player1pipe="pipe2"
player2pipe="pipe3"

if [ ! -p $player1pipe ]; then
    mkfifo $player1pipe
fi

if [ ! -p $player1pipe ]; then
    mkfifo $player1pipe
fi


while true; do #Or until the game ends

    # Read other players' move from the pipe files. Notice the order here, if player2 moved before player1 the execution would be locked until the pipe is emptied
    player1move=$(cat $player1pipe)
    player2move=$(cat $player2pipe)

    #Print out their move or whatever you need to do with it.
    echo $player1move
    echo $player2move

    # Do whatever else you need to do about those moves
done


将这三个文件保存在同一个目录下,从三个不同的终端执行它们,看看它们是如何工作的。 希望我有所帮助。