How to retrieve the absolute path of an arbitrary file from the OS X
Solution 1:
function abspath() { pushd . > /dev/null; if [ -d "$1" ]; then cd "$1"; dirs -l +0; else cd "`dirname \"$1\"`"; cur_dir=`dirs -l +0`; if [ "$cur_dir" == "/" ]; then echo "$cur_dir`basename \"$1\"`"; else echo "$cur_dir/`basename \"$1\"`"; fi; fi; popd > /dev/null; }
Examples:
abspath / => /
abspath /.DS_Store => /.DS_Store
abspath ~ => /Users/mschrag
cd /tmp; abspath . => /tmp
cd /; abspath .DS_Store => /.DS_Store
Solution 2:
I don't think there's a buildin command that does this. Jesse Wilson wrote a bash script for this:
#!/bin/bash
cd -P -- "$(dirname -- "$1")" &&
printf '%s\n' "$(pwd -P)/$(basename -- "$1")"
However, it does not work well for paths directly below /
, such as /etc
(printing //etc
), as well as .
and ..
(printing /cwd/.
in both cases). I tried modifying it, but my unsufficient bash-fu failed me.
Here's my suggestion:
#!/usr/bin/env python
import os.path
import sys
for arg in sys.argv[1:]:
print os.path.abspath(arg)
Save as /usr/bin/abspath
or something like that and make it executable. Sample output:
Servus08:~ danielbeck$ abspath .
/Users/danielbeck
Servus08:~ danielbeck$ abspath /tmp
/tmp
Servus08:~ danielbeck$ abspath Documents
/Users/danielbeck/Documents
Servus08:~ danielbeck$ abspath . /tmp Documents
/Users/danielbeck
/tmp
/Users/danielbeck/Documents
If you do want symlink resolution, change the print
line like this:
print os.path.realpath(os.path.abspath(arg))
to get this:
Servus08:~ danielbeck$ abspath . /tmp Documents
/Users/danielbeck
/private/tmp
/Users/danielbeck/Documents
Solution 3:
One option would be to just install coreutils and use greadlink -f
. It resolves symlinks and it works with /Foo/
or ~/foo.txt
if they don't exist, but not with /Foo/foo.txt
if /Foo/
doesn't exist.
$ brew install coreutils
$ greadlink -f /etc
/private/etc
$ greadlink -f ~/Documents/
/Users/lauri/Documents
$ greadlink -f ..
/Users
$ greadlink -f //etc/..////
/private
$ greadlink -f /Foo
/Foo
$ greadlink -f /Foo/foo.txt
$
This doesn't resolve symlinks, and it doesn't work with /Foo/foo.txt
either.
abspath() {
if [ -d "$1" ]; then
( cd "$1"; dirs -l +0 )
else
( cd "$(dirname "$1")"; d=$(dirs -l +0); echo "${d%/}/${1##*/}" )
fi
}
abspath /etc # /etc
abspath ~/Foo/foo.txt # doesn't work
abspath ~/Foo # works
abspath .
abspath ./
abspath ../
abspath ..
abspath /
abspath ~
abspath ~/
abspath ~/Documents
abspath /\"\ \'
abspath /etc/../etc/
abspath /private//etc/
abspath /private//
abspath //private # //private
abspath ./aa.txt
abspath aa.tar.gz
abspath .aa.txt
abspath /.DS_Store
abspath ~/Documents/Books/
dirs -l
performs tilde expansion. dirs +0
prints only the topmost directory if there are other directories in the stack.