Edit each line in a file in Ruby

后端 未结 5 961
隐瞒了意图╮
隐瞒了意图╮ 2020-12-14 02:52

I\'m trying to find a simple way of editing each line in a file, and I\'m having some trouble understanding how to use the File class to do so.

The file

相关标签:
5条回答
  • 2020-12-14 03:27

    File processing using code differs substantially from what we are doing when we, for example, edit the file in a text editor. File operations offered by operating systems are quite limited in that matter (due to numerous, partly historical reasons - think magnetic tapes).

    In short, you should probably create another file and write data to it (Mike provided code for that), or load entire file in memory (which can be bad idea if your file is huge) and overwrite it with processed data.

    Just for practice, here's how you could actually edit file in-place. As you can see, not the prettiest sight:

    File.open('foo', 'r+') do |file|
      write_pos = 0
      file.each do |line|
        word = line.chomp.split(',').first
        read_pos = file.pos
        file.pos = write_pos
        file.puts word
        write_pos = file.pos
        file.pos = read_pos
      end
      file.truncate write_pos
    end
    
    0 讨论(0)
  • 2020-12-14 03:29

    I think you misunderstand what this line

    file.each_line { |line| line = line.split(",")[0].to_s }
    

    really does. It takes a line, splits it on a comma, takes the first value, turns it to a string (which it was already), assigns the result to the block-local variable 'line'. And then?
    It goes on to the next line, and nothing is done with the previous one - it's all gone. See the other answers how to remedy this.

    0 讨论(0)
  • 2020-12-14 03:42

    The problem with the accepted answer is that it modifies file permissions and ownership (pay attention to that).

    Another approach is to use inplace editing inside Ruby (not from the command line):

    #!/usr/bin/ruby
    
    def inplace_edit(file, bak, &block)
        old_stdout = $stdout
        argf = ARGF.clone
    
        argf.argv.replace [file]
        argf.inplace_mode = bak
        argf.each_line do |line|
            yield line
        end
        argf.close
    
        $stdout = old_stdout
    end
    
    inplace_edit 'test.txt', '.bak' do |line|
        line = line.gsub(/search1/,"replace1")
        line = line.gsub(/search2/,"replace2")
        print line unless line.match(/something/)
    end
    

    If you don't want to create a backup then change '.bak' to ''.

    0 讨论(0)
  • 2020-12-14 03:47

    Another way to modify the file inplace is to use the -i switch

    ruby -F"," -i.bak -ane 'puts $F[0]' file
    
    0 讨论(0)
  • 2020-12-14 03:51

    The one of the better solutions(and safest) is to create a temporary file using TempFile, and move it to the original location(using FileUtils) once you are done:

       require 'fileutils'
       require 'tempfile'
    
        t_file = Tempfile.new('filename_temp.txt')
        File.open("filename.txt", 'r') do |f|
          f.each_line{|line| t_file.puts line.split(",")[0].to_s }
        end
        t_file.close
        FileUtils.mv(t_file.path, "filename.txt")
    
    0 讨论(0)
提交回复
热议问题