Converting relative path into absolute path?
I'm not sure if these paths are duplicates. Given the relative path, how do I determine absolute path using a shell script?
Example:
relative path: /x/y/../../a/b/z/../c/d
absolute path: /a/b/c/d
Solution 1:
The most reliable method I've come across in unix is readlink -f
:
$ readlink -f /x/y/../../a/b/z/../c/d
/a/b/c/d
A couple caveats:
- This also has the side-effect of resolving all symlinks. This may or may not be desirable, but usually is.
-
readlink
will give a blank result if you reference a non-existant directory. If you want to support non-existant paths, usereadlink -m
instead. Unfortunately this option doesn't exist on versions of readlink released before ~2005.
Solution 2:
From this source comes:
#!/bin/bash
# Assume parameter passed in is a relative path to a directory.
# For brevity, we won't do argument type or length checking.
ABS_PATH=`cd "$1"; pwd` # double quotes for paths that contain spaces etc...
echo "Absolute path: $ABS_PATH"
You can also do a Perl one-liner, e.g. using Cwd::abs_path
Solution 3:
Using bash
# Directory
relative_dir="folder/subfolder/"
absolute_dir="$( cd "$relative_dir" && pwd )"
# File
relative_file="folder/subfolder/file"
absolute_file="$( cd "${relative_file%/*}" && pwd )"/"${relative_file##*/}"
-
${relative_file%/*}
is same result asdirname "$relative_file"
-
${relative_file##*/}
is same result asbasename "$relative_file"
Caveats: Does not resolve symbolic links (i.e. does not canonicalize path ) => May not differentiate all duplicates if you use symbolic links.
Using realpath
Command realpath
does the job. An alternative is to use readlink -e
(or readlink -f
). However realpath
is not often installed by default. If you cannot be sure realpath
or readlink
is present, you can substitute it using perl (see below).
Using perl
Steven Kramer proposes a shell alias if realpath
is not available in your system:
$ alias realpath="perl -MCwd -e 'print Cwd::realpath(\$ARGV[0]),qq<\n>'"
$ realpath path/folder/file
/home/user/absolute/path/folder/file
or if you prefer using directly perl:
$ perl -MCwd -e 'print Cwd::realpath($ARGV[0]),qq<\n>' path/folder/file
/home/user/absolute/path/folder/file
This one-line perl command uses Cwd::realpath
. There are in fact three perl functions. They take a single argument and return the absolute pathname. Below details are from documentation Perl5 > Core modules > Cwd.
-
abs_path()
uses the same algorithm asgetcwd()
. Symbolic links and relative-path components (.
and..
) are resolved to return the canonical pathname, just likerealpath
.use Cwd 'abs_path'; my $abs_path = abs_path($file);
-
realpath()
is a synonym forabs_path()
use Cwd 'realpath'; my $abs_path = realpath($file);
-
fast_abs_path()
is a more dangerous, but potentially faster version ofabs_path()
use Cwd 'fast_abs_path'; my $abs_path = fast_abs_path($file);
These functions are exported only on request => therefore use Cwd
to avoid the "Undefined subroutine" error as pointed out by arielf. If you want to import all these three functions, you can use a single use Cwd
line:
use Cwd qw(abs_path realpath fast_abs_path);