Skip to content

Instantly share code, notes, and snippets.

@thinkerbot
Last active August 29, 2015 14:06
Show Gist options
  • Save thinkerbot/5dc190f2c2145c29b086 to your computer and use it in GitHub Desktop.
Save thinkerbot/5dc190f2c2145c29b086 to your computer and use it in GitHub Desktop.
Hold open a fifo from both ends, allowing input from external processes
#!/usr/bin/env ruby
begin
require 'optparse'
options = {
:direction => "in"
}
OptionParser.new do |opts|
opts.banner = %{
usage: pipe-exec [options] FIFO_FILE COMMAND....
Executes the command with stdin reading from the fifo and FD 3 holding open
the fifo on the write side. As a result other processes can write to the
fifo, and thereby to the command, without the fifo closing. It's a
persistent pipe.
Use the --direction option to do the same but flipping stdin with stdout.
options:
}.lstrip
opts.on("-d", "--direction IN_OR_OUT", "the direction of the pipe (#{options[:direction]})") do |value|
options[:direction] = value
end
opts.on("-h", "--help", "print this help") do
puts opts
exit
end
end.parse!
case ARGV.length
when 0
$stderr.puts "no fifo specified"
exit
when 1
$stderr.puts "no command specified"
exit
end
fifo = ARGV.shift
# The trick here is using NONBLOCK and opening the fifo for read first such
# that the process will not deadlock with a fifo open for write, waiting for
# the reader that will never open.
#
# See http://man7.org/linux/man-pages/man7/fifo.7.html
# Or better 'The Linux Programming Interface' p917
case options[:direction].downcase
when "in" then exec(*ARGV, 0 => [fifo, File::RDONLY | File::NONBLOCK], 3 => [fifo, File::WRONLY])
when "out" then exec(*ARGV, 3 => [fifo, File::RDONLY | File::NONBLOCK], 1 => [fifo, File::WRONLY])
else raise "invalid direction: #{options[:direction]} (should be 'in' or 'out')"
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment