[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

ln and relative paths

From: Nicolai Langfeldt
Subject: ln and relative paths
Date: Wed, 28 Nov 2001 14:10:27 +0100


Firstly, thanks for all the great work on the gnu utils.

Secondly, two feature requests.

- ln does not have a option to generate relative symlinks paths from
absolute paths.   This seems a odd omission in a execlent program :-) 
So I wrote a bash function to satisfy my immediate needs, I have
appended it for inspiration :-)  I belive gnu tar has some paths to do
such conversions.
- It would also be nice with a 'do what I said' option.  Given

  ln -s /foo/bar /gazonk/bar-link

to symlink the directory /gazonk/bar-link -> /foo/bar this works as I
said the first time, the second time it creates /gazonk/bar-link/bar
alias /foo/bar/bar because it decuces that I want to create a link to
bar inside bar-link since bar-link exists and is a directory.  Getting
around this in a shell script in a robust way takes a bit too much
effort it seems.

rln () {
    # Oddly GNU ln does not have an option to link with relative path.
    # So here we Calculate the relative path.  Paths with space in will
    # not work, but paths with . and .. in are handled
    ARG="$1"; shift || exit 1
    LINK="$1"; shift || exit 1
    NEW="$1"; shift || exit 1

    # echo Transform ln $ARG $LINK $NEW

    # Check if $FROM is absolute, and has no spaces
    case $LINK in
        *\ *) exit 1;;   # NO SPACES!
        /*) :;;
        *)  ln $ARG "$LINK" "$NEW"

    # Check that the new name has no spaces
    case $NEW in
        *\ *) exit 1;;

    test -e "$LINK" || return

    # Find common leading path elements, replace / in paths with ' '
    # and put in array for processing.  Remove /../ and /./ in the
    # process.
    ALINK=($(echo "$LINK" | 
             sed -e 's~/[^/]*/\.\./~/~g' -e 's~/./~/~g' | 
             tr '/' ' '))
    ANEW=($(echo "$NEW" | 
            sed -e 's~/[^/]*/\.\./~/~g' -e 's~/./~/~g' |
            tr '/' ' '))

    while [ "${ALINK[$I]}" = "${ANEW[$I]}" ] ; do
        unset ALINK[$I]
        unset ANEW[$I]
        I=$(($I + 1))

    # Now the task left is to count how many directory levels we have to
go up
    ALINK="$(echo address@hidden | tr ' ' /)"
    ANEW="$(echo address@hidden | tr ' ' /)"

    # echo "Non common paths are $ALINK $ANEW"

    ANEW="$(dirname $ANEW)"
    while [ "$ANEW" != . ] ; do
       ANEW="$(dirname $ANEW)"

    # echo ln $ARG "$ALINK" "$NEW"
    ln $ARG "$ALINK" "$NEW"

reply via email to

[Prev in Thread] Current Thread [Next in Thread]