# Getting to the last file in a chain of symlinks

**URL:** <https://www.ruby-forum.com/t/getting-to-the-last-file-in-a-chain-of-symlinks/88346>\
**Category:** Ruby\
**Created:** [March 9, 2007, 10:05pm UTC](https://www.ruby-forum.com/t/getting-to-the-last-file-in-a-chain-of-symlinks/88346 "2007-03-09T22:05:14Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![danielb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/c57346/32.png) [@danielb](https://www.ruby-forum.com/u/danielb)\
**Post date:** [March 9, 2007, 10:05pm UTC](https://www.ruby-forum.com/t/getting-to-the-last-file-in-a-chain-of-symlinks/88346/1 "2007-03-09T22:05:14Z")

</div>

Hi all,

Here’s a little code snippet I thought I’d share. It follows a chain  
of symlinks until you get down to the “real” file. Anyone got a better  
approach?

# On Solaris 10, Sunblade 150

# 

# /dev/fd0 -\> fd0c

# /dev/fd0c -\> diskette0

# /dev/diskett0 -\> …/devices/pci@1f,0/isa@7/dma@0,0/floppy@0,3f0:c

# 

file = ‘/dev/fd0’

while true  
Dir.chdir(File.dirname(file))  
file = File.expand\_path(File.readlink(file))  
break unless File.symlink?(file)  
end

puts file # /devices/pci@1f,0/isa@7/dma@0,0/floppy@0,3f0:c

Regards,

Dan

---

<div class="post-metadata">

**Author:** ![danielb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/c57346/32.png) [@danielb](https://www.ruby-forum.com/u/danielb)\
**Post date:** [September 25, 2007, 11:04pm UTC](https://www.ruby-forum.com/t/getting-to-the-last-file-in-a-chain-of-symlinks/88346/2 "2007-09-25T23:04:05Z")

</div>

On Mar 9, 12:44 pm, “AdSR” [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> > # On Solaris 10, Sunblade 150
> > 
> > file = File.expand\_path(File.readlink(file))
> 
> puts Pathname.new(‘/dev/fd0’).realpath

Oh, dang, forgot about that.

> I didn’t check what would happen for cyclic dependencies.

> ls -l  
> lrwxrwxrwx 1 djberge other 5 Mar 9 12:25 link1 → link2  
> lrwxrwxrwx 1 djberge other 5 Mar 9 12:23 link2 → link1  
> -rw-r–r-- 1 djberge other 57 Mar 9 12:45 test.rb

/usr/local/lib/ruby/1.8/pathname.rb:415:in `realpath_rec': Number of symbolic links encountered during path name traversal exceeds MAXSYMLINKS - /export/home/djberge/workspace/ruby_test/lib/test/link2 (Errno::ELOOP) from /usr/local/lib/ruby/1.8/pathname.rb:425:in `realpath\_rec’  
from /usr/local/lib/ruby/1.8/pathname.rb:453:in `realpath’  
from test.rb:2

Dunno what happens on other platforms.

Regards,

Dan

---

<div class="post-metadata">

**Author:** ![danielb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/c57346/32.png) [@danielb](https://www.ruby-forum.com/u/danielb)\
**Post date:** [September 25, 2007, 11:05pm UTC](https://www.ruby-forum.com/t/getting-to-the-last-file-in-a-chain-of-symlinks/88346/3 "2007-09-25T23:05:30Z")

</div>

On Mar 9, 12:10 pm, “Daniel B.” [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> # /dev/diskett0 → …/devices/pci@1f,0/isa@7/dma@0,0/floppy@0,3f0:c
> 
> puts file # /devices/pci@1f,0/isa@7/dma@0,0/floppy@0,3f0:c  
> Alright, here’s a modified File.readlink method. This is an improved  
> version of the algorithm above in that it uses the block form of  
> Dir.chdir and handles circular symlinks:

class File  
class \<\< self  
private

```
  alias readlink_orig readlink

  public

  # Returns the given symbolic link as a string. If +recursive+ is

```

set  
# to true then it will follow symbolic links until it gets to  
the final  
# file in the chain. The default is false, i.e. non-recursive.  
#  
# If circular symlinks are encountered, it will return the last  
link  
# that it has not already encountered.  
#  
def readlink(file, recursive=false)  
if recursive  
visited = {} # Used to avoid circular references  
while true  
Dir.chdir(File.dirname(file)){  
file = File.expand\_path(File.readlink(file))  
}

```
           if File.symlink?(file) || visited[file]
              break
           end

           visited[file] = true
        end
        file
     else
        readlink_orig(file)
     end
  end

```

end  
end

---

<div class="post-metadata">

**Author:** ![danielb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/c57346/32.png) [@danielb](https://www.ruby-forum.com/u/danielb)\
**Post date:** [September 25, 2007, 11:10pm UTC](https://www.ruby-forum.com/t/getting-to-the-last-file-in-a-chain-of-symlinks/88346/4 "2007-09-25T23:10:38Z")

</div>

On 9 Mar, 20:10, “Daniel B.” [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> # /dev/diskett0 → …/devices/pci@1f,0/isa@7/dma@0,0/floppy@0,3f0:c
> 
> puts file # /devices/pci@1f,0/isa@7/dma@0,0/floppy@0,3f0:c
> 
> Regards,
> 
> Dan

require ‘pathname’

puts Pathname.new(‘/dev/fd0’).realpath

I didn’t check what would happen for cyclic dependencies.

Regards,  
AdSR
