Skip to content

Instantly share code, notes, and snippets.

@lincheney
Last active February 4, 2016 04:22
Show Gist options
  • Save lincheney/3e5fcd45db81ffbb4e85 to your computer and use it in GitHub Desktop.
Save lincheney/3e5fcd45db81ffbb4e85 to your computer and use it in GitHub Desktop.
SIGKILL cannot be trapped
# input-multiplexer.rb stdout=file1 stdout=name_2=file2 stderr=name_3=file3 ...
# Merges the specified files together into stdout or stderr (as specified)
#
# Example output:
# file1| first line from file1
# file1| the next line from file1
# name_3| first line from line3
# name_2| first line from line2
# file1| the next line from file1
# ...
#
# Uses select(), so files should be pipes/FIFOs etc.
# If you need `tail -f` style output on a normal file, make a pipe:
# input-multiplexer.rb stdout=file=<(tail -f file) ...
if __FILE__ == $0
if ARGV.empty? or ARGV.include?('--help') or ARGV.include?('-h')
puts File.readlines(__FILE__).take_while{|i| i.start_with?('#')}
exit
end
%w[ INT TERM CHLD ].each{|sig| Signal.trap(sig, 'EXIT') }
args = ARGV.map{|a| a.split('=', 3)}
stream = args.map(&:first)
names = args.map{|a| a[2] ? a[1] : File.basename(a[1])}
files = args.map(&:last)
stream = {'stdout'=>STDOUT, 'stderr'=>STDERR}.values_at(*stream)
raise "Missing stdout= or stderr=" unless stream.all? and stream.any?
colours = (31..36).to_a + (91..96).to_a
width = names.map(&:length).max
io = files.map{|f| open(f, File::NONBLOCK)}
mapping = Hash[io.zip(files.zip(names, stream, colours.cycle))]
loop do
IO.select(io)[0].each do |r|
path, name, out, col = mapping[r]
if r.eof?
r.close
r.reopen(path, File::NONBLOCK)
else
out.printf("\x1b[%im%*s|\x1b[m %s\n", col, width, name, r.gets.chomp)
out.flush
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment