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