By default, macOS is packaged with the BSD versions of many common CLI utilities such as grep, sed, awk, and more. These are not the same ones that can be found on most Linux distributions, and the slight differences between them can be confusing when working with both systems at the same time.
Thankfully, most of these can be installed through Homebrew. There are some caveats, but for the most part, they can be treated as a one-to-one replacement. The coreutils package is commonly cited, but over time, I have compiled a larger list of other non-GNU utilities that can be replaced.
installation
The full list of default mac packages that I’ve replaced are:
1 | brew install \ |
configuration
Since the BSD and GNU utils have the same names, these new utils are usually installed with a g prefix. Additionally, their manpages may not be properly pointed to the installed application either. As a result, you’ll have to redefine the PATH and MANPATH shell variables for a number of these tools.
However, it may not be clear which ones are necessary to set. I will provide a full list of these paths below, but this is the strategy I followed to build it.
First, I made sure there were no PATH or MANPATH variables set in my ~/.zshrc or remaining ZSH environment. Then, I closed out all ZSH sessions that might exist in the user environment, including tmux sessions and the terminal. Then, I reopened my terminal and echo‘d the path variables to get a clear list of the default paths that macOS uses:
1 | $ echo $PATH | tr ':' '\n' |
Next, I added the PATH for coreutils that was recommended during installation. (You can also re-print the message by running brew info coreutils):
1 | export PATH="/opt/homebrew/opt/coreutils/libexec/gnubin:$PATH" |
The MANPATH location usually follows 2 directory conventions. They are located under either:
1 | /opt/homebrew/opt/<APPLICATION NAME>/libexec/gnuman |
For coreutils, diffutils and findutils, the PATH and MANPATH values were fairly straightforward:
1 | # coreutils |
The other applications are not as clear. I first added man, following the guide here.
1 | # man |
This makes the next step simpler, which is to identify the default binary and manpath location. By running which <APPLICATION NAME> and man --path <APPLICATION NAME>, I can identify where they are located. Homebrew installs everything underneath /opt/homebrew/, so if the path doesn’t start there, then I know it needs to be reconfigured.
In these three examples, awk is not configured automatically at all, gzip only has its binary in PATH, and git is automatically configured correctly for both its PATH and MANPATH:
1 | $ which awk && man --path awk |
The remaining list of values that need to be configured after man are:
1 | # awk |
For logical separation, I place all of these configurations in a file called gnu-coreutils.sh, and source it in ~/.zshrc:
1 | # GNU coreutils, diffutils and findutils |
exclusions
There are some notable exclusions from this list of programs. Specifically, openssh, unzip and tar. The reason for this is that the default versions bundled with macOS have been modified to recognize macOS-specific extended attributes/additional functionality, which the GNU versions do not recognize.
For example, the coreutils tools mv and cp tools do not preserve tags. unzip and tar also reportedly do not recognize macOS metadata. I’ve found that the bundled OpenSSH has a configuration option UseKeychain that can cache your SSH key in macOS’s Keychain.
There may be many more examples, but these are the only ones I am aware of. I have re-aliased mv & cp, and haven’t updated the PATH/MANPATH for unzip and gnu-tar:
1 | #... |
I also haven’t found a reason to replace the bundled zsh as of yet.
resources
- Older guide for installing
coreutils:
https://www.topbug.net/blog/2013/04/14/install-and-use-gnu-command-line-tools-in-mac-os-x/ - Stackexchange guide for installing
coreutils:
https://apple.stackexchange.com/a/69332 - Warning regarding tag preservation failure:
https://brettterpstra.com/2014/07/03/mavericks-tags-and-coreutils-a-warning/ - Good guide on ZSH configuration for macOS:
https://scriptingosx.com/2019/06/moving-to-zsh-part-2-configuration-files/