【问题标题】:Bash script redirecting stdin to program and its output to another programBash 脚本将标准输入重定向到程序并将其输出重定向到另一个程序
【发布时间】:2016-05-22 16:42:39
【问题描述】:

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

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

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

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

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

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

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

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

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

-从标准输入读取行

-“发送”该行到 gui 程序和 comp_player 的输入

-“读取”来自 comp_player 的输出并将其写入标准输出,并将其“发送”到 gui 输入

【问题讨论】:

    标签: bash redirect io pipe fifo


    【解决方案1】:

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

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

    echo "A very important message" &gt; mypipe

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

    cat mypipe

    您将从第一个终端打印出存储在管道中的“非常重要的消息”。请注意,管道现在是空的,您根本无法再次从中获取消息。


    现在您已经了解了命名管道的工作原理,下面是一个非常简单的示例,说明三个玩家如何进行通信。请注意,我们不能对所有文件都使用单个文件,而是创建单独的管道来通信 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
    


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

    【讨论】:

    • 非常感谢您提供非常全面的解释!当然 gui 和 AI 是独立的程序(在 C 中),我只需要在一个脚本中完成所有事情,但是感谢您的回答,我知道命名管道是如何工作的以及如何实现它。
    • 很高兴为您提供帮助。作为旁注,我只是注意到没有必要等待使用那个奇怪的while循环将某些内容写入管道文件,您可以尝试从中读取,并且执行将暂停,直到将某些内容写入其中。因此,如果您使用其中任何一个,则可以删除这些循环。我将编辑代码以供将来参考。
    • 今天我开始继续我的项目。使用如上所示的管道对我来说是可以的。但是我在运行程序前仍然有问题。 ./my_prog 或两个不是 bash 脚本并通过管道连续发送文本并从中读取。例如,我可以(我在文件描述符 3 中放置管道)回显“某事”>&3 然后 ./my_prog &3,但没有任何反应
    • 我应该怎么做才能将“某事”(它现在读取)发送到我正在运行的程序,在我的脚本中执行其他操作(程序等待),然后发送“另一件事”作为下一个我正在运行的程序的输入(它现在再次读取它)?
    • 您可能会遇到错误,因为 echo 会在写入内容后关闭管道文件,因此您的外部 C 程序将不断运行到 EOF。我能想到的唯一解决方案(我刚刚对其进行了测试并且它有效)是在您读取某些内容后也关闭 C 中的文件描述符,然后在您再次需要它时重新打开它。这不是最有效的解决方案,因此您可能需要谷歌搜索一种在 bash 中保持文件打开的方法以避免这种情况。如果你仍然想以“慢”的方式来做,那么就像:while(1) { open(pipe);读取(管道);关闭(管道); } 应该可以工作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-07-24
    • 1970-01-01
    • 2011-10-10
    • 1970-01-01
    • 2012-11-20
    • 1970-01-01
    • 2023-03-10
    相关资源
    最近更新 更多