diff --git a/realpath b/realpath index a931b57..fdbf363 100755 --- a/realpath +++ b/realpath @@ -63,51 +63,65 @@ function realpath() if [ -z "$path" ]; then success=false else - # start with the file name (sans the trailing slash) - path="${path%/}" + while $success; do + # start with the file name (sans the trailing slash) + path="${path%/}" + + # if we stripped off the trailing slash and were left with nothing, that means we're in the root directory + if [ -z "$path" ]; then + path="/" + fi + + # get the basename of the file (ignoring '.' & '..', because they're really part of the path) + local file_basename="${path##*/}" + if [[ ( "$file_basename" = "." ) || ( "$file_basename" = ".." ) ]]; then + file_basename="" + fi + + # extracts the directory component of the full path, if it's empty then assume '.' (the current working directory) + local directory="${path%$file_basename}" + if [ -z "$directory" ]; then + directory='.' + fi + + # attempt to change to the directory + if ! cd "$directory" &>/dev/null ; then + success=false + fi + + if $success; then + # does the filename exist? + if [[ ( -n "$file_basename" ) && ( ! -e "$file_basename" ) ]]; then + success=false + fi + + # get the absolute path of the current directory & change back to previous directory + local abs_path="$(pwd -P)" + cd "-" &>/dev/null - # if we stripped off the trailing slash and were left with nothing, that means we're in the root directory - if [ -z "$path" ]; then - path="/" - fi - - # get the basename of the file (ignoring '.' & '..', because they're really part of the path) - local file_basename="${path##*/}" - if [[ ( "$file_basename" = "." ) || ( "$file_basename" = ".." ) ]]; then - file_basename="" - fi - - # extracts the directory component of the full path, if it's empty then assume '.' (the current working directory) - local directory="${path%$file_basename}" - if [ -z "$directory" ]; then - directory='.' - fi - - # attempt to change to the directory - if ! cd "$directory" &>/dev/null ; then - success=false - fi - - if $success; then - # does the filename exist? - if [[ ( -n "$file_basename" ) && ( ! -e "$file_basename" ) ]]; then - success=false - fi - - # get the absolute path of the current directory & change back to previous directory - local abs_path="$(pwd -P)" - cd "-" &>/dev/null - - # Append base filename to absolute path - if [ "${abs_path}" = "/" ]; then - abs_path="${abs_path}${file_basename}" - else - abs_path="${abs_path}/${file_basename}" - fi - - # output the absolute path - echo "$abs_path" - fi + local abs_path_bak="$abs_path" + + # Append base filename to absolute path + if [ "${abs_path}" = "/" ]; then + abs_path="${abs_path}${file_basename}" + else + abs_path="${abs_path}/${file_basename}" + fi + + # If is a symlink, follow the symlink and try again with the newly discovered path + if [ -L "$abs_path" ]; then + path="$( readlink "$abs_path" )" + if [[ "$path:0:1" != '/' ]]; then + path="$abs_path_bak/$path" + fi + continue + fi + + # output the absolute path + echo "$abs_path" + break + fi + done fi $success diff --git a/realpath-test.sh b/realpath-test.sh index 8b9eab4..78a64aa 100755 --- a/realpath-test.sh +++ b/realpath-test.sh @@ -83,4 +83,19 @@ it_fails_for_relative_home_paths() { out=$(set +e ; ./realpath "$rel_path" >/dev/null ; echo $?) test $out -gt 0 -} \ No newline at end of file +} + +it_follows_symlink() { + cmd="$(pwd)/realpath" + dir="$(mktemp -d)" + cd "$dir" + mkdir -p tmp + ln -s .. ./tmp/symlink + cwd="$(pwd)" + + rel_path="tmp/symlink" + abs_path="${cwd}" + out_path="$("$cmd" "$rel_path")" + + test "$out_path" = "$abs_path" +}