Forget about readlink
and realpath
which may or may not be installed on your system.
Expanding on dogbane's answer above here it is expressed as a function:
#!/bin/bashget_abs_filename() { # $1 : relative filename echo "$(cd "$(dirname "$1")"&& pwd)/$(basename "$1")"}
you can then use it like this:
myabsfile=$(get_abs_filename "../../foo/bar/file.txt")
How and why does it work?
The solution exploits the fact that the Bash built-in pwd
command will print the absolute path of the current directory when invoked without arguments.
Why do I like this solution ?
It is portable and doesn't require neither readlink
or realpath
which often does not exist on a default install of a given Linux/Unix distro.
What if dir doesn't exist?
As given above the function will fail and print on stderr if the directory path given does not exist. This may not be what you want. You can expand the function to handle that situation:
#!/bin/bashget_abs_filename() { # $1 : relative filename if [ -d "$(dirname "$1")" ]; then echo "$(cd "$(dirname "$1")"&& pwd)/$(basename "$1")" fi}
Now it will return an empty string if one the parent dirs do not exist.
How do you handle trailing '..' or '.' in input ?
Well, it does give an absolute path in that case, but not a minimal one. It will look like:
/Users/bob/Documents/..
If you want to resolve the '..' you will need to make the script like:
get_abs_filename() { # $1 : relative filename filename=$1 parentdir=$(dirname "${filename}") if [ -d "${filename}" ]; then echo "$(cd "${filename}"&& pwd)" elif [ -d "${parentdir}" ]; then echo "$(cd "${parentdir}"&& pwd)/$(basename "${filename}")" fi}