Reputation: 22620
realpath
is very nice in that it gives you a simple way to get the real path of a file, but I can't figure out a way to satisfy my needs (without doing my own string manipulation, and therefore potentially missing the corner cases that a dedicated utility presumably has found and solved). In a nutshell, I want to include ~
in the path that it returns, so it can be valid across machines.
So if I'm in ~/bin
and I type realpath --some-option script.sh
I want it to return ~/bin/script.sh
instead of bin/script.sh
, which is what I get if the option I use is --relative-base=$HOME
, and instead of /Users/brandon/bin/script.sh
, which is what I get if I use no options.
Is there some way to get what I want from realpath
, or is there some other utility that does what I want in a simple way? Or is the only real option to just pipe through sed
to get what I want?
(P.S. I'm on OS X, but I've got GNU utilities installed, in case those are needed... I'm not sure if that's where realpath
came from or if it's now installed by default on more recent versions of OS X.)
Upvotes: 1
Views: 699
Reputation: 438813
Even the current version of OSX (10.11.3) does not come with a realpath
utility, so yours must indeed come from the GNU coreutils
Homebrew package.
In fact, you can easily verify that with realpath
itself; e.g.:
$ realpath "$(which realpath)"
/usr/local/Cellar/coreutils/8.24/bin/grealpath
Using --relative-base="$HOME"
and simply prepending ~/
, as in Bujiraso's helpful answer is the simplest solution in your case.
Let me propose an alternative that:
Makes do without realpath
, because its presence cannot be assumed on OSX machines.
Uses $HOME
instead of ~
, as basing a path on $HOME
is the safer choice (assuming a shell expands the path):
$HOME
is safer, because it allows the entire path string to be double-quoted when it is passed to the shell, without having to worry about individually quoting (escaping) embedded spaces and other shell metacharacters; by contrast, with a ~
-prefixed path you'd either have to quote individual characters in the path or selectively leave the ~/
prefix unquoted (~/"path/..."
).absPath=$(perl -MCwd -le 'print Cwd::abs_path(shift)' "script.sh")
abstractPath="\$HOME${absPath#"$HOME"}"
The result would be something like literal $HOME/bin/script.sh
, which, when interpreted by the shell, would expand to a then-current-user-specific path.
If you define an abstractHomePath()
bash
function as printed below, you can use:
abstractPath=$(abstractHomePath "script.sh") # -> '$HOME/bin/script.sh'
abstractHomePath
Bash function:
# Given a relative or absolute path, returns an absolute path in which the path
# prefix that is the current user's home directory is replaced with literal
# '$HOME' so as to yield an abstract path that can later be expanded in a
# different user's context to get the analogous path.
#
# If the input path resolves to an absolute path that is *not* prefixed with
# the current user's home diretory path, the absolute path is returned as -is.
#
# Note that any symlinks in the path are resolved to their ultimate targets
# first and that the path is normalized.
#
# Examples:
# abstractHomePath ~ # -> '$HOME'
# abstractHomePath /Users/jdoe/Downloads # -> '$HOME/Downloads'
# abstractHomePath /tmp # -> '/private/tmp' - symlink resolved, but no $HOME prefix
# Prerequisites:
# Requires Perl v5+
abstractHomePath() {
local absPath=$(perl -MCwd -le 'print Cwd::abs_path(shift)' "$1")
if [[ $absPath == "$HOME"* ]]; then
printf '%s\n' "\$HOME${absPath#"$HOME"}"
else
printf '%s\n' "$absPath"
fi
}
Upvotes: 2