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.
- A Perl one-liner is used instead (Python would also be an option).
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
}