Converting absolute symbolic links to relative?

Converting absolute symbolic links to relative?

Post by Ian P. Springe » Sun, 18 Mar 2001 02:06:19



That script converts from relative to absolute.  He wants to convert from
absolute to relative.



> > Can anyone provide some hints on how to convert absolute symbolic
> > links to relative?

> I read (and reread and reread :) your previous post here on your
> dtksh script, and although I can say I don't have any clear idea
> of what you are trying to accomplish -- which is not to say that
> it hasn't been acceptably described -- then perhaps a function to
> turn relative pathnames into absolute pathname, with optional
> resolution of symbolic links and/or path lookup.... Does this help
> you in your problem?

> =Brian

> P.S. BTW, why are you using sed(1) instead of builtin pattern substitution
> in ksh93?! (${var//pattern/string}). Why are you using expr(1)
> instead of builtin arithmetic?! (heck, floating-point even!) Why
> awk(1) when you can use ${#var} and word-separation parsing?! The
> ratio of execution can be as high as 10000 (not a typo) times
> faster!

> #! /bin/echo error: only source
> #*TAG:42576 4:Jan 9 1973:0755:resolvepath:

> # Copyright: (c) 2000
> # Description: resolve and canonicize full pathname of arguments
> # Name: resolvepath
> # Requires:

> # See-also: File-PathConvert-0.4.tar (perl)
> # Usage: resolvepath [-hlp] path...
> # Version: 1.08

> #01
> function resolvepath # [-hlp] path...
> { set -o noglob
> # Ksh Bug: OPTIND cannot be declared integer!
> typeset -i rc
> typeset IFS OPTARG arg dir fn headers= symlink= oarg opt usepath=
> while getopts :HhLlPp opt
> do case $opt in
> (h) headers=ON ;;
> (+h|H) headers=OFF ;;
> (l) symlink=ON ;;
> (+l|L) symlink= ;;
> (p) usepath=ON ;;
> (+p|P) usepath= ;;
> ([:?]) print -ru2 "usage: $0 [-hlp] path...
> -h - prepend the output with argument header
> -l - show logical path with symlinks resolved [physical path]
> -p - apply path lookup, if applicable"
> return 2 ;;
> esac
> done
> shift OPTIND-1
> if [[ $headers = OFF ]]
> then headers=
> else (($#>1)) && headers=ON
> fi
> for arg
> do oarg=$arg
> if [[ $usepath = ON && ! -d $arg ]]
> then # Ksh Bug: "whence" cannot handle args with spaces
> arg=$(whence -p "$arg") ||
> { print -ru2 'resolvepath: whence: error:' \
> "\"$oarg\" not found"
> rc=rc+1 continue
> }
> fi
> [[ -a $arg ]] ||
> { print -ru2 "resolvepath: error: \"$arg\" not found"
> rc=rc+1 continue
> }
> [[ $arg != */* ]] && arg="./$arg"
> if [[ -d $arg ]]
> then dir=$arg fn=
> else dir=${arg%/*} fn=${arg##*/}
> fi
> ${DIAG:+print -ru2 "[ $0: dirpart=\"$dir\", filepart=\"$fn\" ]"}
> # Ksh Bug: "cd -P dir" works, but "cd -P -- dir" does not!
> [[ $dir = -* ]] && dir="./$dir" # work-around for above bug
> \cd ${symlink:+-P} "$dir" || rc=rc+1 continue
> print -r -- "${headers:+$oarg: }${PWD%/}/$fn" # <= TAB
> \cd - >&-
> done
> return $rc
> }

> #02 EMBEDDED MAN-PAGE FOR "src2man"
> : '
> #++
> NAME
> resolvepath - resolve and canonicize the full pathname of argument

> SYNOPSIS
> resolvepath [-hlp] path...

> OPTIONS
> -h - Prepend the output with argument header.
> -l - Show logical path with symlinks resolved. [physical path]
> -p - Apply path lookup, if applicable.

> DESCRIPTION
> ...

> If and only if the path is a directory, the output is guaranteed
> to be terminated with a slash ("/").

> RETURN CODE
> Returns 0 if successful, 2 for options parsing errors, otherwise
> the number of arguments in error.

> EXAMPLE
> $ resolvepath .
> /home/brian/side/lib/

> $ resolvepath cat
> resolvepath: error: "cat" not found
> $ resolvepath -p cat
> /bin/cat
> $ resolvepath -lp cat
> /usr/bin/cat

> $ resolvepath /
> /
> $ resolvepath //
> /
> $ resolvepath /..
> /
> $ resolvepath /.//..///.////../////.//////..///////.////////..
> /

> ENVIRONMENT
> PATH

> SEE ALSO
> predictshell(3S), stat(3S)

> AUTHOR

> CAVEATS
> The algorithm that is used requires the directory component of
> the resolved argument to be executable; i.e. you must have
> permission to chdir to it.

> BUGS
> Filenames with embedded spaces will be failed to be recognized;
> this is a bug in the ksh builtin "whence", not resolvepath(3S).

> #--
> '

 
 
 

Converting absolute symbolic links to relative?

Post by Dani » Sun, 18 Mar 2001 04:28:48


Nevermind, I've implemented the following and it works for me:

        SOURCE=${CLIP_FROM}
        SOURCE_FIELDS=$(echo $SOURCE | awk -F/ {print NF})
        echo "Source: $SOURCE = $SOURCE_FIELDS fields"

        set -A SOURCE_ARRAY ${CLIP_FROM//\// }

        XUget $DIRECTORY value:current_dir

        TARGET=$current_dir
        TARGET_FIELDS=$(echo $TARGET | awk -F/ {print NF})
        echo "Target: $TARGET = $TARGET_FIELDS fields"

        set -A TARGET_ARRAY ${TARGET//\// }

        field=0
        while true
        do
                if [[ ${SOURCE_ARRAY[$field]} == ${TARGET_ARRAY[$field]} ]]; then
                        echo "field $field matches ${SOURCE_ARRAY[$field]}"
                        BASE=${SOURCE#*${SOURCE_ARRAY[$field]}/}
                else
                        echo "field $field does not match ${TARGET_ARRAY[$field]}" ; break
                fi
                (( field+=1 ))
        done

        DOTS=$(($TARGET_FIELDS - $SOURCE_FIELDS + 1))

        dots=1
        RELATIVE=$(
        until (( dots > DOTS ))
        do
                echo "../\c"
                (( dots+=1 ))
        done
        )

        for i in $CLIP_ITEMS
        do
                \ln -s $RELATIVE$BASE$i .  
        done

--
Regards,

Daniel E. Lincoln - Ford Motor Company
R&VT Vehicle CAD Process & Methods
http://ae0581.pd8.ford.com/vcpm

 
 
 

Converting absolute symbolic links to relative?

Post by Dani » Sat, 17 Mar 2001 03:39:05


Can anyone provide some hints on how to convert absolute symbolic links to relative?

--
Regards,

Daniel E. Lincoln - Ford Motor Company
R&VT Vehicle CAD Process & Methods

 
 
 

Converting absolute symbolic links to relative?

Post by Ian P. Springe » Sat, 17 Mar 2001 09:22:13


It would be a real pain to do with a script, but, if you really want to,
here's the pseudo-code:

- get the full pathname for the directory where the symlink is located:
  - cd `dirname $symlink`
  - dir=`/bin/pwd`
  - $base=`basename $symlink`
- get the symlink's target by parsing the "ls -l" output or calling Perl's
readlink function
  - see the attached script for an example of how to do this
- if the target name doesn't start w/ a slash, you're done; just return
$target
- else get the full pathname for the directory where the target is located:
  - cd `dirname $target`
  - target_dir=`/bin/pwd`
  - target_base=`basename $target`
- CASE 1: $dir _begins_ with $target_dir (ie - "/opt/perl5/bin/$base" ->
"/opt/$target_base")
  - newdir=[$dir with $target_dir chopped off of beginning] (so for above
example, newdir="/perl5/bin")
  - count the number of slashes in the new value of $dir - this is how many
pairs of ".." you need to construct a relative target
  - so in our example, the relative target dir becomes "../.."; let's call
this $reldir
  - goto END
- else CASE 2: $target_dir _begins_ with $dir (ie - "/$base" ->
"/home/bob/stuff/$target_base")
  - reldir=[$target_dir with $dir chopped off of beginning] (ie - for above
example, reldir="home/bob/stuff")
  - goto END
- else: neither CASE 1 or CASE 2 is true (ie - "/foo/bar/$base" ->
"/junk/crap/$target_base")
  - really kind of silly to use a relative symlink in this case, but in case
you really want to...
  - count the number of slashes in $dir - this is how many pairs of ".." you
need to prepend to $target_dir to construct a relative target
  - so in our example, the relative target dir becomes "../../junk/crap";
let's call this $reldir
- END: remove & recreate the symlink w/ the new relative target:
  - $new_target=$reldir/$target_base
  - cd $dir
  - rm $symlink
  - ln -s $new_target $symlink

Uggh..  I think this task is easier to do manually..



Quote:> Can anyone provide some hints on how to convert absolute symbolic links to
relative?

> --
> Regards,

> Daniel E. Lincoln - Ford Motor Company
> R&VT Vehicle CAD Process & Methods

 
 
 

Converting absolute symbolic links to relative?

Post by brian hile » Sat, 17 Mar 2001 09:08:26



Quote:> Can anyone provide some hints on how to convert absolute symbolic
> links to relative?

I read (and reread and reread :) your previous post here on your
dtksh script, and although I can say I don't have any clear idea
of what you are trying to accomplish -- which is not to say that
it hasn't been acceptably described -- then perhaps a function to
turn relative pathnames into absolute pathname, with optional
resolution of symbolic links and/or path lookup.... Does this help
you in your problem?

=Brian

P.S. BTW, why are you using sed(1) instead of builtin pattern substitution
in ksh93?! (${var//pattern/string}). Why are you using expr(1)
instead of builtin arithmetic?! (heck, floating-point even!) Why
awk(1) when you can use ${#var} and word-separation parsing?! The
ratio of execution can be as high as 10000 (not a typo) times
faster!

#! /bin/echo error: only source
#*TAG:42576 4:Jan 9 1973:0755:resolvepath:

# Copyright: (c) 2000
# Description: resolve and canonicize full pathname of arguments
# Name: resolvepath
# Requires:

# See-also: File-PathConvert-0.4.tar (perl)
# Usage: resolvepath [-hlp] path...
# Version: 1.08

#01
function resolvepath # [-hlp] path...
{       set -o noglob
        # Ksh Bug: OPTIND cannot be declared integer!
        typeset -i rc
        typeset IFS OPTARG arg dir fn headers= symlink= oarg opt usepath=
        while getopts :HhLlPp opt
        do      case $opt in
                (h)     headers=ON ;;
                (+h|H)  headers=OFF ;;
                (l)     symlink=ON ;;
                (+l|L)  symlink= ;;
                (p)     usepath=ON ;;
                (+p|P)  usepath= ;;
                ([:?])  print -ru2 "usage: $0 [-hlp] path...
-h      - prepend the output with argument header
-l      - show logical path with symlinks resolved [physical path]
-p      - apply path lookup, if applicable"
                        return 2 ;;
                esac
        done
        shift OPTIND-1
        if [[ $headers = OFF ]]
        then    headers=
        else    (($#>1)) && headers=ON
        fi
        for arg
        do      oarg=$arg
                if [[ $usepath = ON && ! -d $arg ]]
                then    # Ksh Bug: "whence" cannot handle args with spaces
                        arg=$(whence -p "$arg") ||
                        {       print -ru2 'resolvepath: whence: error:' \
                                "\"$oarg\" not found"
                                rc=rc+1 continue
                        }
                fi
                [[ -a $arg ]] ||
                {       print -ru2 "resolvepath: error: \"$arg\" not found"
                        rc=rc+1 continue
                }
                [[ $arg != */* ]] && arg="./$arg"
                if [[ -d $arg ]]
                then    dir=$arg fn=
                else    dir=${arg%/*} fn=${arg##*/}
                fi
${DIAG:+print -ru2 "[ $0: dirpart=\"$dir\", filepart=\"$fn\" ]"}
                # Ksh Bug: "cd -P dir" works, but "cd -P -- dir" does not!
                [[ $dir = -* ]] && dir="./$dir"       # work-around for above bug
                \cd ${symlink:+-P} "$dir" || rc=rc+1 continue
                print -r -- "${headers:+$oarg:     }${PWD%/}/$fn"     # <= TAB
                \cd - >&-
        done
        return $rc

Quote:}

#02 EMBEDDED MAN-PAGE FOR "src2man"
: '
#++
NAME
        resolvepath - resolve and canonicize the full pathname of argument

SYNOPSIS
        resolvepath [-hlp] path...

OPTIONS
        -h      - Prepend the output with argument header.
        -l      - Show logical path with symlinks resolved. [physical path]
        -p      - Apply path lookup, if applicable.

DESCRIPTION
        ...

        If and only if the path is a directory, the output is guaranteed
        to be terminated with a slash ("/").

RETURN CODE
        Returns 0 if successful, 2 for options parsing errors, otherwise
        the number of arguments in error.

EXAMPLE
        $ resolvepath .
        /home/brian/side/lib/

        $ resolvepath cat
        resolvepath: error: "cat" not found
        $ resolvepath -p cat
        /bin/cat
        $ resolvepath -lp cat
        /usr/bin/cat

        $ resolvepath /
        /
        $ resolvepath //
        /
        $ resolvepath /..
        /
        $ resolvepath /.//..///.////../////.//////..///////.////////..
        /

ENVIRONMENT
        PATH

SEE ALSO
        predictshell(3S), stat(3S)

AUTHOR

CAVEATS
        The algorithm that is used requires the directory component of
        the resolved argument to be executable; i.e. you must have
        permission to chdir to it.

BUGS
        Filenames with embedded spaces will be failed to be recognized;
        this is a bug in the ksh builtin "whence", not resolvepath(3S).

#--
'

 
 
 

Converting absolute symbolic links to relative?

Post by Dani » Sat, 17 Mar 2001 22:44:38


Maybe this will help clarify what I'm looking for:

I need a conversion function that converts...
Absolute symbolic link:  lrwxrwxrwx   1 user sys       66 Jan 26 14:28 nsmail -> /etc/dt/bin/nsmail
to:
Relative symbolic link:  lrwxrwxrwx   1 user sys       66 Jan 26 14:28 nsmail -> ../../../etc/dt/bin/nsmail

I'm still learning the power of ksh93 so I don't have all my external system calls converted yet.
I know it's easier to do this manually but it's for a file manager GUI that I'm working on.
(e.g. for users who don't know how to do it manually)

brian hiles wrote:

> In comp.unix.shell Lincoln, D. E. (Daniel) <dlinc...@ford.com> wrote:
> > Can anyone provide some hints on how to convert absolute symbolic
> > links to relative?

> I read (and reread and reread :) your previous post here on your
> dtksh script, and although I can say I don't have any clear idea
> of what you are trying to accomplish -- which is not to say that
> it hasn't been acceptably described -- then perhaps a function to
> turn relative pathnames into absolute pathname, with optional
> resolution of symbolic links and/or path lookup.... Does this help
> you in your problem?

> =Brian

> P.S. BTW, why are you using sed(1) instead of builtin pattern substitution
> in ksh93?! (${var//pattern/string}). Why are you using expr(1)
> instead of builtin arithmetic?! (heck, floating-point even!) Why
> awk(1) when you can use ${#var} and word-separation parsing?! The
> ratio of execution can be as high as 10000 (not a typo) times
> faster!

> #! /bin/echo error: only source
> #*TAG:42576 4:Jan 9 1973:0755:resolvepath:
> # Author: Brian Hiles <b...@iname.com>
> # Copyright: (c) 2000
> # Description: resolve and canonicize full pathname of arguments
> # Name: resolvepath
> # Requires:
> # Sccs: @(#)resolvepath.sh 1.8 1997/12 b...@iname.com (Brian Hiles)
> # See-also: File-PathConvert-0.4.tar (perl)
> # Usage: resolvepath [-hlp] path...
> # Version: 1.08

> #01
> function resolvepath # [-hlp] path...
> {       set -o noglob
>         # Ksh Bug: OPTIND cannot be declared integer!
>         typeset -i rc
>         typeset IFS OPTARG arg dir fn headers= symlink= oarg opt usepath=
>         while getopts :HhLlPp opt
>         do      case $opt in
>                 (h)     headers=ON ;;
>                 (+h|H)  headers=OFF ;;
>                 (l)     symlink=ON ;;
>                 (+l|L)  symlink= ;;
>                 (p)     usepath=ON ;;
>                 (+p|P)  usepath= ;;
>                 ([:?])  print -ru2 "usage: $0 [-hlp] path...
> -h      - prepend the output with argument header
> -l      - show logical path with symlinks resolved [physical path]
> -p      - apply path lookup, if applicable"
>                         return 2 ;;
>                 esac
>         done
>         shift OPTIND-1
>         if [[ $headers = OFF ]]
>         then    headers=
>         else    (($#>1)) && headers=ON
>         fi
>         for arg
>         do      oarg=$arg
>                 if [[ $usepath = ON && ! -d $arg ]]
>                 then    # Ksh Bug: "whence" cannot handle args with spaces
>                         arg=$(whence -p "$arg") ||
>                         {       print -ru2 'resolvepath: whence: error:' \
>                                 "\"$oarg\" not found"
>                                 rc=rc+1 continue
>                         }
>                 fi
>                 [[ -a $arg ]] ||
>                 {       print -ru2 "resolvepath: error: \"$arg\" not found"
>                         rc=rc+1 continue
>                 }
>                 [[ $arg != */* ]] && arg="./$arg"
>                 if [[ -d $arg ]]
>                 then    dir=$arg fn=
>                 else    dir=${arg%/*} fn=${arg##*/}
>                 fi
> ${DIAG:+print -ru2 "[ $0: dirpart=\"$dir\", filepart=\"$fn\" ]"}
>                 # Ksh Bug: "cd -P dir" works, but "cd -P -- dir" does not!
>                 [[ $dir = -* ]] && dir="./$dir" # work-around for above bug
>                 \cd ${symlink:+-P} "$dir" || rc=rc+1 continue
>                 print -r -- "${headers:+$oarg:  }${PWD%/}/$fn"  # <= TAB
>                 \cd - >&-
>         done
>         return $rc
> }

> #02 EMBEDDED MAN-PAGE FOR "src2man"
> : '
> #++
> NAME
>         resolvepath - resolve and canonicize the full pathname of argument

> SYNOPSIS
>         resolvepath [-hlp] path...

> OPTIONS
>         -h      - Prepend the output with argument header.
>         -l      - Show logical path with symlinks resolved. [physical path]
>         -p      - Apply path lookup, if applicable.

> DESCRIPTION
>         ...

>         If and only if the path is a directory, the output is guaranteed
>         to be terminated with a slash ("/").

> RETURN CODE
>         Returns 0 if successful, 2 for options parsing errors, otherwise
>         the number of arguments in error.

> EXAMPLE
>         $ resolvepath .
>         /home/brian/side/lib/

>         $ resolvepath cat
>         resolvepath: error: "cat" not found
>         $ resolvepath -p cat
>         /bin/cat
>         $ resolvepath -lp cat
>         /usr/bin/cat

>         $ resolvepath /
>         /
>         $ resolvepath //
>         /
>         $ resolvepath /..
>         /
>         $ resolvepath /.//..///.////../////.//////..///////.////////..
>         /

> ENVIRONMENT
>         PATH

> SEE ALSO
>         predictshell(3S), stat(3S)

> AUTHOR
>         Brian Hiles <b...@iname.com>

> CAVEATS
>         The algorithm that is used requires the directory component of
>         the resolved argument to be executable; i.e. you must have
>         permission to chdir to it.

> BUGS
>         Filenames with embedded spaces will be failed to be recognized;
>         this is a bug in the ksh builtin "whence", not resolvepath(3S).

> #--
> '

--
Regards,

Daniel E. Lincoln - Ford Motor Company
R&VT Vehicle CAD Process & Methods
http://ae0581.pd8.ford.com/vcpm