Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 58 additions & 44 deletions realpath
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
17 changes: 16 additions & 1 deletion realpath-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,19 @@ it_fails_for_relative_home_paths() {
out=$(set +e ; ./realpath "$rel_path" >/dev/null ; echo $?)

test $out -gt 0
}
}

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"
}