ruby picture

RCR 212: cat fileutil.

Submitted by cyent (Wed Feb 11 23:02:46 UTC 2004)

Abstract

Add class method cat to file utils to mimic in a portable fashion the unix `cat` program,

Problem

Often I do....
  string = File.open('filename') {|i| i.sysread(i.stat.size)}
To get a smallish file into a string.

I could also do...

  file = `cat filename`

Which is actually quite cute. That allows me to do...

  string = `cat filename.1 filename.2 filename.3`

But there are a couple of things I don't like about that.

  1) It's non-portable, (it assumes the existence of a 'cat' program)
  2) It actually invokes bash to do the PATH look up and globbing.

I would like to add 'cat' to fileutils.rb so I can do... string = FileUtils.cat( 'filename.1', 'filename.2')

Proposal

Add to fileutils.rb

T...

  'filename.1
  def cat(*name)
    result = ''
    name.each {|n|  
      File.open('filename') {|i| 
        result += i.sysread(i.stat.size)}}
    result
  end

Analysis

This implementation fails if filename refers to a named pipe. It should be extended to detect named pipes and iteratively suck on them until dry (hit eof).

Possibly it should detect if a block is passed so you can do...

FileUtils.cat( 'file.1', 'file.2') do |line|

  do stuff with line
end

Should also handle names pipes correctly.

Implementation

#!/usr/local/bin/ruby -w module FileUtils
  #
  # Like the unix 'cat' programs, reads all the files named
  # and concatenates them into one long string.
  #
  def cat(*file_names)
    if block_given?
      puts "block"
      file_names.each do |file_name|
        File.open( file_name) do |inf|
          inf.each do |line|
            yield line
          end
        end
      end
    else
      result = ''
      file_names.each do |file_name|
        File.open( file_name) do |inf|
          if inf.stat.file?
            result += inf.sysread( inf.stat.size)
          else
            begin
              result += inf.sysread( 65536) while true
            rescue EOFError
            end
          end
        end
      end
      return result
    end
  end
end

  1. # eof - now for unit tests
if $0 == __FILE__

  require 'test/unit'
  include FileUtils
  class TC_FileCat < Test::Unit::TestCase
    def test_cat
      assert_equal( '', FileUtils::cat())
      assert( FileUtils::cat( $0) =~ %r{ module\ FileUtils  }x)
    end
  end  # class TC_FileCat

end # if $0 == __FILE__

ruby picture
Comments Current voting

Do you really need concatenation? If you want to read whole single file,

  File.read(path)

is much simpler.

-- matz.


Strongly opposed 0
Opposed 3
Neutral 0
In favor 1
Strongly advocate 0
ruby picture
If you have registered at RCRchive, you may now sign in below. If you have not registered, you may sign up for a username and password. Registering enables you to submit new RCRs, and vote and leave comments on existing RCRs.
Your username:
Your password:

ruby picture

Powered by .