# How can I trim top of file w/o disrupting other writers?

**URL:** <https://www.ruby-forum.com/t/how-can-i-trim-top-of-file-w-o-disrupting-other-writers/167360>\
**Category:** Ruby\
**Created:** [May 7, 2009, 1:35am UTC](https://www.ruby-forum.com/t/how-can-i-trim-top-of-file-w-o-disrupting-other-writers/167360 "2009-05-07T01:35:43Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![bradjpeek](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/a183cd/32.png) [@bradjpeek](https://www.ruby-forum.com/u/bradjpeek)\
**Post date:** [May 7, 2009, 1:35am UTC](https://www.ruby-forum.com/t/how-can-i-trim-top-of-file-w-o-disrupting-other-writers/167360/1 "2009-05-07T01:35:43Z")

</div>

As a way to learn ruby, I wrote a method to trim the first “n” lines  
from a log file. I had planned to use it on a series of log files  
that are constantly growing. However, some of the programs that are  
appending to these logs don’t tolerate the somewhat brute-force method  
I’m using, which is:

1. Write the lines I want to keep to a temp file
2. Rename the temp file to the original log file name

This works fine for some log files, but others stop receiving log data  
after I run my program. I suspect it is because they have the file  
open and don’t notice that the inode (or some other pointer to the log  
file) has been pulled out from underneath them.

I realize this is more of a Linux/UNIX question, but I’d still like to  
implement the solution as a ruby method if possible.

For what it’s worth, my current method is (please excuse the lack of  
ruby-ness)

# Trims a file down to last “n” number of lines.

# If save\_orig == TRUE then the trimmed lines are

# appended to a file suffixed with \_saved. Otherwise

# the trimmed lines are discarded.

# 

def trim\_file (file\_name, nbr\_lines\_to\_keep = 5000, save\_orig = FALSE)

# The file to be trimmed must be writable by the process owner

# 

if File.writable?(file\_name)

```
# The file to be trimmed must either be owned by the process owner
# (i.e. same account that is running this program) or the process
# owner needs to be root (or running as root via sudo).
#
if (File.stat(file_name).owned?) || (Process.euid == 0)

   # get current uid and gid of the file (in case it
   # isn't same as default)
   #
   f_uid = File.stat(file_name).uid
   f_gid = File.stat(file_name).gid

   all_lines = IO.readlines(file_name)
   nbr_lines = all_lines.size
   if nbr_lines > nbr_lines_to_keep

     start_line = nbr_lines - nbr_lines_to_keep
     tmpfilename = file_name + "_temptrimfile"

     tmpfile_nst = File.new(tmpfilename, "w")
     tmpfile_nst.puts(all_lines[start_line..nbr_lines])
     tmpfile_nst.close

     if save_orig == TRUE
         savefile_nst = File.new(file_name + "_saved", "a")
         savefile_nst.puts(all_lines[0..start_line-1])
         savefile_nst.close
         File.chown(f_uid, f_gid, file_name + "_saved")
     end

     File.rename(tmpfilename, file_name)
     # This script *could* be running as root or via sudo
     # in which case we need to preserve the original uid
     # and gid of the file. Otherwise the trimmed and/or
     # saved file would be owned by root
     File.chown(f_uid, f_gid, file_name)
     print "#{file_name} => trimmed to #{nbr_lines_to_keep} lines.

```

"  
print "First #{start\_line} lines "  
print “appended to #{file\_name}\_saved\n” if save\_orig == TRUE  
print “discarded\n” if save\_orig ==  
FALSE  
else  
print "File #{file\_name} not trimmed. Nbr lines (#  
{nbr\_lines}) "  
print “not greater than #{nbr\_lines\_to\_keep}.\n”  
end  
else  
puts “File #{file\_name} not trimmed. You are not file owner or  
root”  
end  
else  
puts “File #{file\_name} not trimmed. Not writable or doesn’t  
exist.”  
end  
end # end method trim\_file

---

<div class="post-metadata">

**Author:** ![bradjpeek](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/a183cd/32.png) [@bradjpeek](https://www.ruby-forum.com/u/bradjpeek)\
**Post date:** [May 7, 2009, 4:16am UTC](https://www.ruby-forum.com/t/how-can-i-trim-top-of-file-w-o-disrupting-other-writers/167360/2 "2009-05-07T04:16:53Z")

</div>

On 07/05/2009, at 9:35 AM, bradjpeek [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> after I run my program. I suspect it is because they have the file  
> open and don’t notice that the inode (or some other pointer to the log  
> file) has been pulled out from underneath them.

Why can’t you simply open the file itself for read write then replace  
the contents? That’s worked fine for me before

Blog: [http://random8.zenunit.com/](http://random8.zenunit.com/)  
Learn: [http://sensei.zenunit.com/](http://sensei.zenunit.com/)  
Twitter: [http://twitter.com/random8r](http://twitter.com/random8r)

---

<div class="post-metadata">

**Author:** ![bradjpeek](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/a183cd/32.png) [@bradjpeek](https://www.ruby-forum.com/u/bradjpeek)\
**Post date:** [May 7, 2009, 8:40pm UTC](https://www.ruby-forum.com/t/how-can-i-trim-top-of-file-w-o-disrupting-other-writers/167360/3 "2009-05-07T20:40:52Z")

</div>

On May 6, 9:15 pm, Julian L. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> > This works fine for some log files, but others stop receiving log data  
> > after I run my program. I suspect it is because they have the file  
> > open and don’t notice that the inode (or some other pointer to the log  
> > file) has been pulled out from underneath them.
> 
> Why can’t you simply open the file itself for read write then replace  
> the contents? That’s worked fine for me before

That worked. Thanks for the embarassingly obvious answer.

Actually, that occurred to me when I first wrote the script and I  
can’t remember why I chose the rename approach.
