Skip to content

Recursive readlink without canonicalizing #114

@stevecj

Description

@stevecj

Feature proposal

Please let me know if there is a more appropriate place to submit this.

I have recently needed a form of link reading that is not directly supported by readlink (and I implemented in a bash function) then realized that if this is useful to me, then it might also be useful for others and might be a good feature to add to readlink.

Basically, I need to recursively follow a symbolic link without also following links in earlier path parts. The option for this might be called --recurse, and it would be a no-op when used with -e, -f``, or -m` since those are always recursive. When used by itself, however, it would recurse without canonicalizing.

I also realized that, although I don't need it today, there would be a legitimate use for recursively following a symbolic link in this way, but to its penultimate link (the last in a chain of symlinks). This would be so that a script can determine what it was intended to be called as (its symlinked name) when that might be reached through additional symlinks. This could be supported using something like a --limited-recurse=<n> where <n> could be a positive or negative number indicating how many links to traverse or how many links to leave un-recursed at the end of the chain. I'm not sure whether/how this should apply in conjunction with -e, -f``, or -m`, so perhaps that would be an invalid combination of options.

The following bash script (not yet fully tested) handles my current need and always produces an absolute path. Perhaps, it would be meaningful for a formal implementation within readlink to return a path relative to the given path (if all links in the chain are relative) unless an --absolutize argument is supplied. If an --absolutize option is added, then that would be a no-op when used with -e, -f``, or -m` but would be applicable whenever none of those options is also provided, I think.

function readlink_recurs {
    # returns the absolute (but not canonicalized) path to the
    # given file, repeatedly following symbolic links if/as
    # necessary to get to the path of the file.
    #
    # The resulting path may include parts that are symbolic
    # links, though the final path part will never be a symbolic
    # link.  This is different behavior than `readlink -e` or
    # `readlink -f`.
    local targetpath targetdir targetbase linkpath linkdir linkbase
    targetpath=$1

    # Absolutize the given path.                                           
    targetdir=$(dirname "$targetpath")                                      
    targetbase=$(basename "$targetpath")                                    
    targetpath=$(cd "$targetdir" && pwd)/$targetbase || exit                
                                                                            
    # Recusrively follow the symlink if symlinked.
    while linkpath=$(readlink "$targetpath"); do
        targetdir=$(dirname "$targetpath")
        linkdir=$(dirname "$linkpath")
        linkbase=$(basename "$linkpath")
        targetpath=$(cd "$targetdir"/"$linkdir" && pwd)/$linkbase || exitd
    doned

    echo "$targetpath"
} 

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions