在 bash 中打开命名管道,而不读取或写入它

Posted

技术标签:

【中文标题】在 bash 中打开命名管道,而不读取或写入它【英文标题】:Opening a named pipe in bash, without reading or writing to it 【发布时间】:2014-07-14 06:21:49 【问题描述】:

我想在 bash 中使用命名管道而不读取或写入它,直到发生事件。我需要在 shell 脚本运行的整个过程中保持这个管道打开。我会在需要的时候阅读它。意思是,可以这样做:

open(<$NAMED_PIPE>, "r+")
--do something--
--call child ruby script, which will write to named pipe--
--do something more---
read line < $NAMED_PIPE

这在 bash 中可行吗?

我正在使用以下代码: ../红宝石 |-- try1.rb `--try2.sh

try1.rb如下:

#!/usr/bin/ruby

require 'optparse'

puts 'Hello World!, This is my first ruby program'

options = 

optparse = OptionParser.new do|opts|

  opts.banner = "Featbuild minimal trial script for command line parsing"

  options[:cpl] = nil
  opts.on('--cpl SWITCH_STATE', 'compile on or off') do|cplopt|
      options[:cpl] = cplopt
      OPT_CPL=cplopt
      puts cplopt
  end

  opts.on('-h', '--help', 'Display this screen') do
    puts opts
    exit
  end
end

optparse.parse!

output = open("mypipe", "w+")

output.puts OPT_CPL
output.flush

还有 try2.sh 脚本(调用 ruby​​ 脚本):

#!/bin/sh



mkfifo mypipe
exec 4< /home/yusufh/Ruby/mypipe

OPT=$*
./try1.rb $OPT


#read -ru 4 line
read line <&4

echo $line


exec 4<&- #close FIFO my_pipe

rm mypipe

@konsolebox,当我使用普通文本文件从 ruby​​ 脚本复制数据时,您的解决方案有效,并且 bash 脚本本身会从那里获取它。 但是,在尝试使用命名管道时,bash 脚本会在执行以下语句后阻塞:exec 4&lt; /home/yusufh/Ruby/mypipe。控制不涉及生成 ruby​​ 脚本进程,将在其中生成数据,之后 bash 脚本的实际等待/阻塞必须在此行完成:read line &lt;&amp;4。 因此,我想要实现的目标没有发生。此外,当 bash 在获取 FIFO 的 fd 时等待时,如果我在重复终端上的命名管道中回显某些内容,它就会退出等待并继续进行。但是在这种情况下,从 Ruby 脚本返回的数据也没有写入 FIFO,正如我所观察到的。这是调试模式下脚本的输出:

[yusufh@verigybuild6 Ruby]$ bash -xv try2.sh --cpl on &
[1] 2777
[yusufh@verigybuild6 Ruby]$ #!/bin/sh



mkfifo mypipe
+ mkfifo mypipe
exec 4< /home/yusufh/Ruby/mypipe
+ exec

[yusufh@verigybuild6 Ruby]$ echo "Hello World" > mypipe
[yusufh@verigybuild6 Ruby]$
OPT=$*
+ OPT='--cpl on'
./try1.rb $OPT
+ ./try1.rb --cpl on
Hello World!, This is my first ruby program
on


#read -ru 4 line
read line <&4
+ read line

echo $line
+ echo Hello World
Hello World


exec 4<&- #close FIFO my_pipe
+ exec

rm mypipe
+ rm mypipe



[1]+  Done                    bash -xv try2.sh --cpl on
[yusufh@verigybuild6 Ruby]$

关于为什么这失败的任何想法?我很感激这些努力! :-)

【问题讨论】:

@Nehal 我已经搜索了关于堆栈溢出和谷歌的解决方案,但找不到令人满意的答案,所以在这里特别问...... @YusufHusainy 在运行exec 以打开命名管道之前,您应该首先调用您的ruby 脚本(很可能在后台)。自然地打开命名管道会阻止任何这样做的进程。 另外我不记得你可以打开一个命名管道来读写。您只能在一端进行读取或写入:output = open("mypipe", "w+") 中的 w+ 可能应该只是 w @konsolebox。是的,这很有效,非常感谢。 w+ 用于告诉 ruby​​ 我们是非阻塞写入。参考这个[链接] [链接]:pauldix.net/2009/07/… 我不确定这是否正确。请参阅open modes in ruby-doc。或者也许你指的是不同的开放?顺便说一句,欢迎。 【参考方案1】:

使用 Bash 非常简单:

# Open the named pipe with a custom fd for input
exec 4< /path/to/named_pipe

# Do other things
:

# Read a line from pipe
read -ru 4 line

# Or
read -r line <&4

# Just make this consistent and close it when you're done. May not be necessary at exit but still a good practice.
exec 4<&-
使用read 读取输入时,最好使用-r 来防止反斜杠转义任何字符 在 IFS 未设置 (IFS= read ...) 的情况下运行 read 也可能有助于防止修剪前导和尾随空格。

类似的概念也适用于写作:

exec 4> /path/to/named_pipe
echo something >&4
exec 4>&-

奖励:您还可以在 whileforifuntil 等块的范围内打开命名管道。关闭文件描述符:


    # Do reads and other things
    ...
 4< /path/to/named_pipe

【讨论】:

【参考方案2】:

在没有关于您的脚本权限如何管道的信息的情况下,这是我能想到的一种可能的选择。

1) 打开管道mkfifo /path/to/pipe

2) 做点什么echo test1

3) 调用子 ruby​​ 脚本,它将写入命名管道(假设脚本可执行)/path/to/script &gt;&gt; /path/to/pipe &amp;

4) 做更多的事情echo test2

5) 从管道read pipeddata &lt; /path/to/pipe读取行

【讨论】:

以上是关于在 bash 中打开命名管道,而不读取或写入它的主要内容,如果未能解决你的问题,请参考以下文章

如何写入命名管道而不等待读取管道

sh 等效于从命名管道读取的 bash 命令

c中的命名管道

Linux:打开命名管道进行写入时超时

程序打开同一个命名管道并用 C 多次写入

我需要刷新命名管道吗?