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