Skip to content

Instantly share code, notes, and snippets.

@esycat
Last active October 30, 2023 10:52
Show Gist options
  • Save esycat/5279354 to your computer and use it in GitHub Desktop.
Save esycat/5279354 to your computer and use it in GitHub Desktop.
How to get GNU's readlink -f behavior on OS X.

readlink.sh is a pure shell implementation that uses dirname, basename, readlink and pwd utils. Note that you cannot rename it to just readlink as then the script will call itself instead of the system utility.

realpath script simply calls Python's os.path.realpath. Python is provided in OS X and major Linux distributions. You can use instead of the system utility by making a symlink: ln -s realpath readlink.

Another way is to install coreutils package via Homebrew or MacPorts and use greadlink.

The code is taken from the following page on StackOverflow: http://goo.gl/Yw9OY

#!/usr/bin/env python
import os,sys
print os.path.realpath(sys.argv[1])
@dasgoll
Copy link

dasgoll commented Sep 29, 2017

There is a command called 'realpath' you can use on MacOS

@ayrtondumas
Copy link

ayrtondumas commented Jul 16, 2018

which python3
prints this:
/Library/Frameworks/Python.framework/Versions/3.7/bin/python3

@felixrabe
Copy link

felixrabe commented May 3, 2019

@dasgoll: No, there is not: (macOS 10.13)

$ which realpath
$ realpath
-bash: realpath: command not found

@AndrewDDavis
Copy link

As I commented on SO, this needs cd -P, otherwise it will break on paths like this/is/a/link/..

@USSX-Hares
Copy link

USSX-Hares commented Oct 30, 2023

I use the following script to create symlinks for my precious GNU packages on MacOS.
It checks every executable in /bin & /usr/bin if there is GNU alternative for it, and if it is, creates symlink in /usr/local/bin.
Also, note the echo at line 23 (function process-executable, then statement). DO NOT remove it on the first (dry) run. Check what the script outputs. Only then you are allowed to remove it.

#!/usr/bin/env bash

# =============================
# P R E R E Q U I S I T E S
# 
# $ brew install coreutils
# $ brew install findutils
# =============================

function process-executable()
{
    local executable="${1:?"Missing required parameter 'executable'"}"
    local name
    local target
    local link_name
    
    name="$(basename "${executable}" 2> /dev/null)"
    target="$(which "g${name}")"
    link_name="/usr/local/bin/${name}"
    
    # ToDo: remove 'echo' here
    if [[ -x "${target}" ]] && [[ ! -x "${link_name}" ]]
    then echo ln -sv "${target}" "${link_name}"
    fi
}

function search()
{ gfind -P /bin /usr/bin -xtype f -executable -exec bash "$0" {} \; ; }

function error()
{
    echo "ERROR:" "$@" >&2
    exit 1
}

function main()
{
    set -eu
    local nargs="$#"
    
    if (( "${nargs}" == 0 ))
    then search
    elif (( "${nargs}" == 1 ))
    then process-executable "$@"
    else error "Too many arguments!"
    fi
}

if [[ "${BASH_SOURCE[0]}" == "${0}" ]]
then main "$@"
fi

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment