How to retrieve the absolute path of an arbitrary file from the OS X
up vote
18
down vote
favorite
I'm looking for a simple command that can be used within Bash to find the absolute and canonicalized path to a file on an OS X (similar to ``readlink -f'` under Linux).
The following sample bash session describes a [fictitious] utility called ``abspath'` that exhibits the desired behavior:
$ pwd
/Users/guyfleegman
$ ls -lR
drwxr-xr-x 4 guyfleegman crew 136 Oct 30 02:09 foo
./foo:
-rw-r--r-- 1 guyfleegman crew 0 Oct 30 02:07 bar.txt
lrwxr-xr-x 1 guyfleegman crew 7 Oct 30 02:09 baz.txt -> bar.txt
$ abspath .
/Users/guyfleegman
$ abspath foo
/Users/guyfleegman/foo
$ abspath ./foo/bar.txt
/Users/guyfleegman/foo/bar.txt
$ abspath foo/baz.txt
/Users/guyfleegman/foo/baz.txt
As with the last invocation of ``abspath'` in the above example, I'd prefer it didn't automatically resolve symlinks, but I'm not going to be too picky here.
macos osx-snow-leopard bash shell
add a comment |
up vote
18
down vote
favorite
I'm looking for a simple command that can be used within Bash to find the absolute and canonicalized path to a file on an OS X (similar to ``readlink -f'` under Linux).
The following sample bash session describes a [fictitious] utility called ``abspath'` that exhibits the desired behavior:
$ pwd
/Users/guyfleegman
$ ls -lR
drwxr-xr-x 4 guyfleegman crew 136 Oct 30 02:09 foo
./foo:
-rw-r--r-- 1 guyfleegman crew 0 Oct 30 02:07 bar.txt
lrwxr-xr-x 1 guyfleegman crew 7 Oct 30 02:09 baz.txt -> bar.txt
$ abspath .
/Users/guyfleegman
$ abspath foo
/Users/guyfleegman/foo
$ abspath ./foo/bar.txt
/Users/guyfleegman/foo/bar.txt
$ abspath foo/baz.txt
/Users/guyfleegman/foo/baz.txt
As with the last invocation of ``abspath'` in the above example, I'd prefer it didn't automatically resolve symlinks, but I'm not going to be too picky here.
macos osx-snow-leopard bash shell
A similar question at Stack Overflow
– user495470
Aug 21 '12 at 20:11
add a comment |
up vote
18
down vote
favorite
up vote
18
down vote
favorite
I'm looking for a simple command that can be used within Bash to find the absolute and canonicalized path to a file on an OS X (similar to ``readlink -f'` under Linux).
The following sample bash session describes a [fictitious] utility called ``abspath'` that exhibits the desired behavior:
$ pwd
/Users/guyfleegman
$ ls -lR
drwxr-xr-x 4 guyfleegman crew 136 Oct 30 02:09 foo
./foo:
-rw-r--r-- 1 guyfleegman crew 0 Oct 30 02:07 bar.txt
lrwxr-xr-x 1 guyfleegman crew 7 Oct 30 02:09 baz.txt -> bar.txt
$ abspath .
/Users/guyfleegman
$ abspath foo
/Users/guyfleegman/foo
$ abspath ./foo/bar.txt
/Users/guyfleegman/foo/bar.txt
$ abspath foo/baz.txt
/Users/guyfleegman/foo/baz.txt
As with the last invocation of ``abspath'` in the above example, I'd prefer it didn't automatically resolve symlinks, but I'm not going to be too picky here.
macos osx-snow-leopard bash shell
I'm looking for a simple command that can be used within Bash to find the absolute and canonicalized path to a file on an OS X (similar to ``readlink -f'` under Linux).
The following sample bash session describes a [fictitious] utility called ``abspath'` that exhibits the desired behavior:
$ pwd
/Users/guyfleegman
$ ls -lR
drwxr-xr-x 4 guyfleegman crew 136 Oct 30 02:09 foo
./foo:
-rw-r--r-- 1 guyfleegman crew 0 Oct 30 02:07 bar.txt
lrwxr-xr-x 1 guyfleegman crew 7 Oct 30 02:09 baz.txt -> bar.txt
$ abspath .
/Users/guyfleegman
$ abspath foo
/Users/guyfleegman/foo
$ abspath ./foo/bar.txt
/Users/guyfleegman/foo/bar.txt
$ abspath foo/baz.txt
/Users/guyfleegman/foo/baz.txt
As with the last invocation of ``abspath'` in the above example, I'd prefer it didn't automatically resolve symlinks, but I'm not going to be too picky here.
macos osx-snow-leopard bash shell
macos osx-snow-leopard bash shell
asked Oct 30 '10 at 9:53
Michael Wehner
191113
191113
A similar question at Stack Overflow
– user495470
Aug 21 '12 at 20:11
add a comment |
A similar question at Stack Overflow
– user495470
Aug 21 '12 at 20:11
A similar question at Stack Overflow
– user495470
Aug 21 '12 at 20:11
A similar question at Stack Overflow
– user495470
Aug 21 '12 at 20:11
add a comment |
8 Answers
8
active
oldest
votes
up vote
16
down vote
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
add a comment |
up vote
11
down vote
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 '%sn' "$(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
1
I think you're on the right track with the first shell-based approach, but I believe that using another language for doing this somewhat defeats the purpose, as it introduces additional dependencies and is pretty much equivalent to simply compiling GNU's version of `readlink(1)' under OS X (assuming this can be done; I haven't verified it yet).
– Michael Wehner
Nov 1 '10 at 4:47
2
@Michael You're either on a system with GNU readlink, or on OS X -- right? OS X has Python out of the box. In theory it's a new dependency, in practice not. Anyway, it's all I can offer you.
– Daniel Beck♦
Nov 1 '10 at 7:23
The pragmatic approach you're implying is laudable, if overly simplistic. In any case, if we were to take this approach in lieu of anything written purely in bash (which is absolutely doable and doesn't depend on anything else--it just can't easily be done in one line), Python probably isn't the best choice. Both Perl and Ruby (and probably PHP) can do this succinctly on the command line without the need to create an actual script file.
– Michael Wehner
Nov 6 '10 at 9:21
1
@Michael: True, but that's not what I was commenting on. I offer you a 90% solution written in pure bash by Jesse Wilson + the analysis why it's only 90%. If that's no problem for you, that's fine. I also gave you a slightly more complicated, 100% solution in Python. While other scripting languages might be briefer (Perl infamously so :-) ), all require an additional file to store the command. Or do you want to write it out every time you want to use it? That's also why I added the multi-line ability to handle multiple parameters, 1 or 2 lines then don't make a different.
– Daniel Beck♦
Nov 6 '10 at 9:46
2
@Michael, why wouldn't Python be a good choice on OS X? It even ships with commands that are actually Python scripts, likefile /usr/bin/xattr
– Arjan
Dec 5 '10 at 16:24
add a comment |
up vote
8
down vote
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.
add a comment |
up vote
2
down vote
I guess you could do it with either python or ruby.
$ ruby -e 'puts File.expand_path("~/somepath")'
or make it a command with
#!/usr/bin/env ruby
puts File.expand_path(ARGV[0])
My earlier comment on Daniel Beck's answer applies here as well (I'd prefer a purely Bash-y solution), though if I were to resort to using another language achieve this, I like your solution best so far for its brevity. :) I'd also probably wrap the call to ruby (e.g. function abspath () { ruby -e "puts File.expand_path('$1')"; }) and put it into my `.profile'.
– Michael Wehner
Nov 1 '10 at 4:57
add a comment |
up vote
1
down vote
If you have the File::Spec module installed for perl you can just do this:
perl -MFile::Spec -e 'print File::Spec->rel2abs("../however/complex/../you/want/to.get"), "n"'
add a comment |
up vote
0
down vote
For bash/sh scripts you can use this recursive function:
canonical_readlink ()
{
cd `dirname $1`;
__filename=`basename $1`;
if [ -h "$__filename" ]; then
canonical_readlink `readlink $__filename`;
else
echo "`pwd -P`";
fi
}
answer=$(canonical_readlink $0)
Some variables and command substitutions aren't quoted properly. You could use local variables instead of variable names like__filename
. The script currently behaves more likedirname
anyway.
– user495470
Aug 21 '12 at 20:07
add a comment |
up vote
0
down vote
Install the following library for OSX:
brew install coreutils
greadlink -f file.txt
add a comment |
up vote
0
down vote
If installing coreutils is not an option, the following handles combos of symlinks, . and .. and works on files and folders like GNU realpath does:
#!/usr/bin/env bash
realpath()
{
if ! pushd $1 &> /dev/null; then
pushd ${1##*/} &> /dev/null
echo $( pwd -P )/${1%/*}
else
pwd -P
fi
popd > /dev/null
}
But it does not support realpath's --relative-to. This would require https://stackoverflow.com/a/12498485/869951.
add a comment |
8 Answers
8
active
oldest
votes
8 Answers
8
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
16
down vote
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
add a comment |
up vote
16
down vote
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
add a comment |
up vote
16
down vote
up vote
16
down vote
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
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
edited Jun 26 '11 at 10:55
3498DB
15.6k114762
15.6k114762
answered Dec 5 '10 at 16:01
mschrag
1612
1612
add a comment |
add a comment |
up vote
11
down vote
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 '%sn' "$(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
1
I think you're on the right track with the first shell-based approach, but I believe that using another language for doing this somewhat defeats the purpose, as it introduces additional dependencies and is pretty much equivalent to simply compiling GNU's version of `readlink(1)' under OS X (assuming this can be done; I haven't verified it yet).
– Michael Wehner
Nov 1 '10 at 4:47
2
@Michael You're either on a system with GNU readlink, or on OS X -- right? OS X has Python out of the box. In theory it's a new dependency, in practice not. Anyway, it's all I can offer you.
– Daniel Beck♦
Nov 1 '10 at 7:23
The pragmatic approach you're implying is laudable, if overly simplistic. In any case, if we were to take this approach in lieu of anything written purely in bash (which is absolutely doable and doesn't depend on anything else--it just can't easily be done in one line), Python probably isn't the best choice. Both Perl and Ruby (and probably PHP) can do this succinctly on the command line without the need to create an actual script file.
– Michael Wehner
Nov 6 '10 at 9:21
1
@Michael: True, but that's not what I was commenting on. I offer you a 90% solution written in pure bash by Jesse Wilson + the analysis why it's only 90%. If that's no problem for you, that's fine. I also gave you a slightly more complicated, 100% solution in Python. While other scripting languages might be briefer (Perl infamously so :-) ), all require an additional file to store the command. Or do you want to write it out every time you want to use it? That's also why I added the multi-line ability to handle multiple parameters, 1 or 2 lines then don't make a different.
– Daniel Beck♦
Nov 6 '10 at 9:46
2
@Michael, why wouldn't Python be a good choice on OS X? It even ships with commands that are actually Python scripts, likefile /usr/bin/xattr
– Arjan
Dec 5 '10 at 16:24
add a comment |
up vote
11
down vote
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 '%sn' "$(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
1
I think you're on the right track with the first shell-based approach, but I believe that using another language for doing this somewhat defeats the purpose, as it introduces additional dependencies and is pretty much equivalent to simply compiling GNU's version of `readlink(1)' under OS X (assuming this can be done; I haven't verified it yet).
– Michael Wehner
Nov 1 '10 at 4:47
2
@Michael You're either on a system with GNU readlink, or on OS X -- right? OS X has Python out of the box. In theory it's a new dependency, in practice not. Anyway, it's all I can offer you.
– Daniel Beck♦
Nov 1 '10 at 7:23
The pragmatic approach you're implying is laudable, if overly simplistic. In any case, if we were to take this approach in lieu of anything written purely in bash (which is absolutely doable and doesn't depend on anything else--it just can't easily be done in one line), Python probably isn't the best choice. Both Perl and Ruby (and probably PHP) can do this succinctly on the command line without the need to create an actual script file.
– Michael Wehner
Nov 6 '10 at 9:21
1
@Michael: True, but that's not what I was commenting on. I offer you a 90% solution written in pure bash by Jesse Wilson + the analysis why it's only 90%. If that's no problem for you, that's fine. I also gave you a slightly more complicated, 100% solution in Python. While other scripting languages might be briefer (Perl infamously so :-) ), all require an additional file to store the command. Or do you want to write it out every time you want to use it? That's also why I added the multi-line ability to handle multiple parameters, 1 or 2 lines then don't make a different.
– Daniel Beck♦
Nov 6 '10 at 9:46
2
@Michael, why wouldn't Python be a good choice on OS X? It even ships with commands that are actually Python scripts, likefile /usr/bin/xattr
– Arjan
Dec 5 '10 at 16:24
add a comment |
up vote
11
down vote
up vote
11
down vote
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 '%sn' "$(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
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 '%sn' "$(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
answered Oct 30 '10 at 10:49
Daniel Beck♦
91.7k12230284
91.7k12230284
1
I think you're on the right track with the first shell-based approach, but I believe that using another language for doing this somewhat defeats the purpose, as it introduces additional dependencies and is pretty much equivalent to simply compiling GNU's version of `readlink(1)' under OS X (assuming this can be done; I haven't verified it yet).
– Michael Wehner
Nov 1 '10 at 4:47
2
@Michael You're either on a system with GNU readlink, or on OS X -- right? OS X has Python out of the box. In theory it's a new dependency, in practice not. Anyway, it's all I can offer you.
– Daniel Beck♦
Nov 1 '10 at 7:23
The pragmatic approach you're implying is laudable, if overly simplistic. In any case, if we were to take this approach in lieu of anything written purely in bash (which is absolutely doable and doesn't depend on anything else--it just can't easily be done in one line), Python probably isn't the best choice. Both Perl and Ruby (and probably PHP) can do this succinctly on the command line without the need to create an actual script file.
– Michael Wehner
Nov 6 '10 at 9:21
1
@Michael: True, but that's not what I was commenting on. I offer you a 90% solution written in pure bash by Jesse Wilson + the analysis why it's only 90%. If that's no problem for you, that's fine. I also gave you a slightly more complicated, 100% solution in Python. While other scripting languages might be briefer (Perl infamously so :-) ), all require an additional file to store the command. Or do you want to write it out every time you want to use it? That's also why I added the multi-line ability to handle multiple parameters, 1 or 2 lines then don't make a different.
– Daniel Beck♦
Nov 6 '10 at 9:46
2
@Michael, why wouldn't Python be a good choice on OS X? It even ships with commands that are actually Python scripts, likefile /usr/bin/xattr
– Arjan
Dec 5 '10 at 16:24
add a comment |
1
I think you're on the right track with the first shell-based approach, but I believe that using another language for doing this somewhat defeats the purpose, as it introduces additional dependencies and is pretty much equivalent to simply compiling GNU's version of `readlink(1)' under OS X (assuming this can be done; I haven't verified it yet).
– Michael Wehner
Nov 1 '10 at 4:47
2
@Michael You're either on a system with GNU readlink, or on OS X -- right? OS X has Python out of the box. In theory it's a new dependency, in practice not. Anyway, it's all I can offer you.
– Daniel Beck♦
Nov 1 '10 at 7:23
The pragmatic approach you're implying is laudable, if overly simplistic. In any case, if we were to take this approach in lieu of anything written purely in bash (which is absolutely doable and doesn't depend on anything else--it just can't easily be done in one line), Python probably isn't the best choice. Both Perl and Ruby (and probably PHP) can do this succinctly on the command line without the need to create an actual script file.
– Michael Wehner
Nov 6 '10 at 9:21
1
@Michael: True, but that's not what I was commenting on. I offer you a 90% solution written in pure bash by Jesse Wilson + the analysis why it's only 90%. If that's no problem for you, that's fine. I also gave you a slightly more complicated, 100% solution in Python. While other scripting languages might be briefer (Perl infamously so :-) ), all require an additional file to store the command. Or do you want to write it out every time you want to use it? That's also why I added the multi-line ability to handle multiple parameters, 1 or 2 lines then don't make a different.
– Daniel Beck♦
Nov 6 '10 at 9:46
2
@Michael, why wouldn't Python be a good choice on OS X? It even ships with commands that are actually Python scripts, likefile /usr/bin/xattr
– Arjan
Dec 5 '10 at 16:24
1
1
I think you're on the right track with the first shell-based approach, but I believe that using another language for doing this somewhat defeats the purpose, as it introduces additional dependencies and is pretty much equivalent to simply compiling GNU's version of `readlink(1)' under OS X (assuming this can be done; I haven't verified it yet).
– Michael Wehner
Nov 1 '10 at 4:47
I think you're on the right track with the first shell-based approach, but I believe that using another language for doing this somewhat defeats the purpose, as it introduces additional dependencies and is pretty much equivalent to simply compiling GNU's version of `readlink(1)' under OS X (assuming this can be done; I haven't verified it yet).
– Michael Wehner
Nov 1 '10 at 4:47
2
2
@Michael You're either on a system with GNU readlink, or on OS X -- right? OS X has Python out of the box. In theory it's a new dependency, in practice not. Anyway, it's all I can offer you.
– Daniel Beck♦
Nov 1 '10 at 7:23
@Michael You're either on a system with GNU readlink, or on OS X -- right? OS X has Python out of the box. In theory it's a new dependency, in practice not. Anyway, it's all I can offer you.
– Daniel Beck♦
Nov 1 '10 at 7:23
The pragmatic approach you're implying is laudable, if overly simplistic. In any case, if we were to take this approach in lieu of anything written purely in bash (which is absolutely doable and doesn't depend on anything else--it just can't easily be done in one line), Python probably isn't the best choice. Both Perl and Ruby (and probably PHP) can do this succinctly on the command line without the need to create an actual script file.
– Michael Wehner
Nov 6 '10 at 9:21
The pragmatic approach you're implying is laudable, if overly simplistic. In any case, if we were to take this approach in lieu of anything written purely in bash (which is absolutely doable and doesn't depend on anything else--it just can't easily be done in one line), Python probably isn't the best choice. Both Perl and Ruby (and probably PHP) can do this succinctly on the command line without the need to create an actual script file.
– Michael Wehner
Nov 6 '10 at 9:21
1
1
@Michael: True, but that's not what I was commenting on. I offer you a 90% solution written in pure bash by Jesse Wilson + the analysis why it's only 90%. If that's no problem for you, that's fine. I also gave you a slightly more complicated, 100% solution in Python. While other scripting languages might be briefer (Perl infamously so :-) ), all require an additional file to store the command. Or do you want to write it out every time you want to use it? That's also why I added the multi-line ability to handle multiple parameters, 1 or 2 lines then don't make a different.
– Daniel Beck♦
Nov 6 '10 at 9:46
@Michael: True, but that's not what I was commenting on. I offer you a 90% solution written in pure bash by Jesse Wilson + the analysis why it's only 90%. If that's no problem for you, that's fine. I also gave you a slightly more complicated, 100% solution in Python. While other scripting languages might be briefer (Perl infamously so :-) ), all require an additional file to store the command. Or do you want to write it out every time you want to use it? That's also why I added the multi-line ability to handle multiple parameters, 1 or 2 lines then don't make a different.
– Daniel Beck♦
Nov 6 '10 at 9:46
2
2
@Michael, why wouldn't Python be a good choice on OS X? It even ships with commands that are actually Python scripts, like
file /usr/bin/xattr
– Arjan
Dec 5 '10 at 16:24
@Michael, why wouldn't Python be a good choice on OS X? It even ships with commands that are actually Python scripts, like
file /usr/bin/xattr
– Arjan
Dec 5 '10 at 16:24
add a comment |
up vote
8
down vote
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.
add a comment |
up vote
8
down vote
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.
add a comment |
up vote
8
down vote
up vote
8
down vote
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.
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.
edited Feb 14 '13 at 16:52
answered Aug 21 '12 at 20:54
user495470
30.8k586125
30.8k586125
add a comment |
add a comment |
up vote
2
down vote
I guess you could do it with either python or ruby.
$ ruby -e 'puts File.expand_path("~/somepath")'
or make it a command with
#!/usr/bin/env ruby
puts File.expand_path(ARGV[0])
My earlier comment on Daniel Beck's answer applies here as well (I'd prefer a purely Bash-y solution), though if I were to resort to using another language achieve this, I like your solution best so far for its brevity. :) I'd also probably wrap the call to ruby (e.g. function abspath () { ruby -e "puts File.expand_path('$1')"; }) and put it into my `.profile'.
– Michael Wehner
Nov 1 '10 at 4:57
add a comment |
up vote
2
down vote
I guess you could do it with either python or ruby.
$ ruby -e 'puts File.expand_path("~/somepath")'
or make it a command with
#!/usr/bin/env ruby
puts File.expand_path(ARGV[0])
My earlier comment on Daniel Beck's answer applies here as well (I'd prefer a purely Bash-y solution), though if I were to resort to using another language achieve this, I like your solution best so far for its brevity. :) I'd also probably wrap the call to ruby (e.g. function abspath () { ruby -e "puts File.expand_path('$1')"; }) and put it into my `.profile'.
– Michael Wehner
Nov 1 '10 at 4:57
add a comment |
up vote
2
down vote
up vote
2
down vote
I guess you could do it with either python or ruby.
$ ruby -e 'puts File.expand_path("~/somepath")'
or make it a command with
#!/usr/bin/env ruby
puts File.expand_path(ARGV[0])
I guess you could do it with either python or ruby.
$ ruby -e 'puts File.expand_path("~/somepath")'
or make it a command with
#!/usr/bin/env ruby
puts File.expand_path(ARGV[0])
answered Nov 1 '10 at 0:50
Jay
561412
561412
My earlier comment on Daniel Beck's answer applies here as well (I'd prefer a purely Bash-y solution), though if I were to resort to using another language achieve this, I like your solution best so far for its brevity. :) I'd also probably wrap the call to ruby (e.g. function abspath () { ruby -e "puts File.expand_path('$1')"; }) and put it into my `.profile'.
– Michael Wehner
Nov 1 '10 at 4:57
add a comment |
My earlier comment on Daniel Beck's answer applies here as well (I'd prefer a purely Bash-y solution), though if I were to resort to using another language achieve this, I like your solution best so far for its brevity. :) I'd also probably wrap the call to ruby (e.g. function abspath () { ruby -e "puts File.expand_path('$1')"; }) and put it into my `.profile'.
– Michael Wehner
Nov 1 '10 at 4:57
My earlier comment on Daniel Beck's answer applies here as well (I'd prefer a purely Bash-y solution), though if I were to resort to using another language achieve this, I like your solution best so far for its brevity. :) I'd also probably wrap the call to ruby (e.g. function abspath () { ruby -e "puts File.expand_path('$1')"; }) and put it into my `.profile'.
– Michael Wehner
Nov 1 '10 at 4:57
My earlier comment on Daniel Beck's answer applies here as well (I'd prefer a purely Bash-y solution), though if I were to resort to using another language achieve this, I like your solution best so far for its brevity. :) I'd also probably wrap the call to ruby (e.g. function abspath () { ruby -e "puts File.expand_path('$1')"; }) and put it into my `.profile'.
– Michael Wehner
Nov 1 '10 at 4:57
add a comment |
up vote
1
down vote
If you have the File::Spec module installed for perl you can just do this:
perl -MFile::Spec -e 'print File::Spec->rel2abs("../however/complex/../you/want/to.get"), "n"'
add a comment |
up vote
1
down vote
If you have the File::Spec module installed for perl you can just do this:
perl -MFile::Spec -e 'print File::Spec->rel2abs("../however/complex/../you/want/to.get"), "n"'
add a comment |
up vote
1
down vote
up vote
1
down vote
If you have the File::Spec module installed for perl you can just do this:
perl -MFile::Spec -e 'print File::Spec->rel2abs("../however/complex/../you/want/to.get"), "n"'
If you have the File::Spec module installed for perl you can just do this:
perl -MFile::Spec -e 'print File::Spec->rel2abs("../however/complex/../you/want/to.get"), "n"'
answered Aug 10 '14 at 7:18
Dodger
111
111
add a comment |
add a comment |
up vote
0
down vote
For bash/sh scripts you can use this recursive function:
canonical_readlink ()
{
cd `dirname $1`;
__filename=`basename $1`;
if [ -h "$__filename" ]; then
canonical_readlink `readlink $__filename`;
else
echo "`pwd -P`";
fi
}
answer=$(canonical_readlink $0)
Some variables and command substitutions aren't quoted properly. You could use local variables instead of variable names like__filename
. The script currently behaves more likedirname
anyway.
– user495470
Aug 21 '12 at 20:07
add a comment |
up vote
0
down vote
For bash/sh scripts you can use this recursive function:
canonical_readlink ()
{
cd `dirname $1`;
__filename=`basename $1`;
if [ -h "$__filename" ]; then
canonical_readlink `readlink $__filename`;
else
echo "`pwd -P`";
fi
}
answer=$(canonical_readlink $0)
Some variables and command substitutions aren't quoted properly. You could use local variables instead of variable names like__filename
. The script currently behaves more likedirname
anyway.
– user495470
Aug 21 '12 at 20:07
add a comment |
up vote
0
down vote
up vote
0
down vote
For bash/sh scripts you can use this recursive function:
canonical_readlink ()
{
cd `dirname $1`;
__filename=`basename $1`;
if [ -h "$__filename" ]; then
canonical_readlink `readlink $__filename`;
else
echo "`pwd -P`";
fi
}
answer=$(canonical_readlink $0)
For bash/sh scripts you can use this recursive function:
canonical_readlink ()
{
cd `dirname $1`;
__filename=`basename $1`;
if [ -h "$__filename" ]; then
canonical_readlink `readlink $__filename`;
else
echo "`pwd -P`";
fi
}
answer=$(canonical_readlink $0)
answered Aug 21 '12 at 17:52
Gregory Burd
1011
1011
Some variables and command substitutions aren't quoted properly. You could use local variables instead of variable names like__filename
. The script currently behaves more likedirname
anyway.
– user495470
Aug 21 '12 at 20:07
add a comment |
Some variables and command substitutions aren't quoted properly. You could use local variables instead of variable names like__filename
. The script currently behaves more likedirname
anyway.
– user495470
Aug 21 '12 at 20:07
Some variables and command substitutions aren't quoted properly. You could use local variables instead of variable names like
__filename
. The script currently behaves more like dirname
anyway.– user495470
Aug 21 '12 at 20:07
Some variables and command substitutions aren't quoted properly. You could use local variables instead of variable names like
__filename
. The script currently behaves more like dirname
anyway.– user495470
Aug 21 '12 at 20:07
add a comment |
up vote
0
down vote
Install the following library for OSX:
brew install coreutils
greadlink -f file.txt
add a comment |
up vote
0
down vote
Install the following library for OSX:
brew install coreutils
greadlink -f file.txt
add a comment |
up vote
0
down vote
up vote
0
down vote
Install the following library for OSX:
brew install coreutils
greadlink -f file.txt
Install the following library for OSX:
brew install coreutils
greadlink -f file.txt
answered Apr 5 '15 at 4:53
anh_ng8
1113
1113
add a comment |
add a comment |
up vote
0
down vote
If installing coreutils is not an option, the following handles combos of symlinks, . and .. and works on files and folders like GNU realpath does:
#!/usr/bin/env bash
realpath()
{
if ! pushd $1 &> /dev/null; then
pushd ${1##*/} &> /dev/null
echo $( pwd -P )/${1%/*}
else
pwd -P
fi
popd > /dev/null
}
But it does not support realpath's --relative-to. This would require https://stackoverflow.com/a/12498485/869951.
add a comment |
up vote
0
down vote
If installing coreutils is not an option, the following handles combos of symlinks, . and .. and works on files and folders like GNU realpath does:
#!/usr/bin/env bash
realpath()
{
if ! pushd $1 &> /dev/null; then
pushd ${1##*/} &> /dev/null
echo $( pwd -P )/${1%/*}
else
pwd -P
fi
popd > /dev/null
}
But it does not support realpath's --relative-to. This would require https://stackoverflow.com/a/12498485/869951.
add a comment |
up vote
0
down vote
up vote
0
down vote
If installing coreutils is not an option, the following handles combos of symlinks, . and .. and works on files and folders like GNU realpath does:
#!/usr/bin/env bash
realpath()
{
if ! pushd $1 &> /dev/null; then
pushd ${1##*/} &> /dev/null
echo $( pwd -P )/${1%/*}
else
pwd -P
fi
popd > /dev/null
}
But it does not support realpath's --relative-to. This would require https://stackoverflow.com/a/12498485/869951.
If installing coreutils is not an option, the following handles combos of symlinks, . and .. and works on files and folders like GNU realpath does:
#!/usr/bin/env bash
realpath()
{
if ! pushd $1 &> /dev/null; then
pushd ${1##*/} &> /dev/null
echo $( pwd -P )/${1%/*}
else
pwd -P
fi
popd > /dev/null
}
But it does not support realpath's --relative-to. This would require https://stackoverflow.com/a/12498485/869951.
answered Nov 28 at 21:28
Oliver
1317
1317
add a comment |
add a comment |
Thanks for contributing an answer to Super User!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fsuperuser.com%2fquestions%2f205127%2fhow-to-retrieve-the-absolute-path-of-an-arbitrary-file-from-the-os-x%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
A similar question at Stack Overflow
– user495470
Aug 21 '12 at 20:11