2011-08-9, 09:24(+00), Stephane CHAZELAS:
> 2011-08-9, 11:44(+10), Jon Seymour:
>> Has anyone ever come across an equivalent to Linux's readlink -f that
>> is implemented purely in bash?
>>
>> (I need readlink's function on AIX where it doesn't seem to be available).
> [...]
>
> What about:
>
> readlink_f() (
>   link=$1 max_iterations=40
>   while [ "$max_iterations" -gt 0 ]; do
>     max_iterations=$(($max_iterations - 1))
>     dir=$(dirname -- "$link") || exit
>     base=$(basename -- "$link") || exit
>     dir=$(cd -P -- "$dir" && pwd -P) || exit
>     link=${dir%/}/$base
>     if [ ! -L "$link" ]; then
>       printf '%s\n' "$link"
>       exit
>     fi
>     link=$(ls -ld -- "$link") || exit
>     link=${link#* -> }
>   done
>   printf >&2 'Loop detected\n'
>   exit 1
> )

Sorry, it's wrong if there are relative paths in symlinks (or
trailing newlines).

fixed_cmd_subst() {
  eval '
    '"$1"'=$('"$2"'; ret=$?; echo .; exit "$ret")
    set -- "$1" "$?"
    '"$1"'=${'"$1"'%??}
  '
  return "$2"
}

readlink_f() (
  link=$1 max_iterations=40
  while [ "$max_iterations" -gt 0 ]; do
    max_iterations=$(($max_iterations - 1))
    fixed_cmd_subst dir 'dirname -- "$link"' || exit
    fixed_cmd_subst base 'basename -- "$link"' || exit
    cd -P -- "$dir" || exit
    link=${PWD%/}/$base
    if [ ! -L "$link" ]; then
      printf '%s\n' "$link"
      exit
    fi
    fixed_cmd_subst link 'ls -ld -- "$link"' || exit
    link=${link#* -> }
  done
  printf >&2 'Loop detected\n'
  exit 1
)

-- 
Stephane

Reply via email to