For the last 5 years, I have used linux as my everyday OS for performing scientific computing. My work recently gave me a Mac that I will be the primary user for the next few months. I keep running into conflicts between the Free-BSD bash environment on the Mac and the GNU environment I am used to, both with bash scripts I have setup and as I try to run bash commands (coreutils
, findutils
, etc). I do not want to switch completely to the Free-BSD utilies as all my other computers as well as our HPC's use linux with the GNU utilities. I want to avoid having to maintain two sets of bash scripts and also having to remember the nuances of the differing flags and functionalities between the two systems. I also do not want to break any of Mac's gui utilites etc that other users will use (either in the next few months or when it is given to someone else). Additionally, responses to this related question warn against completely replacing the Mac Free-BSD utilities with GNU ones.
Is it possible to install/setup a separate bash environment to use only the GNU utilities while leaving the system Free-BSD ones in place? My expect the most promising option is setting up my $PATH
variable to point to a directory containing the GNU executables (with their standard names) while ignoring the Free-BSD ones. How could I apply this to my cross-platform bash scripts? Are there alternative options worth considering?
Best Answer
First, this is about a lot more than just
coreutils
. The BSD equivalent to GNUfindutils
is also quite different, pretty much every command related to dynamic linkage is different, etc.And then on top of that, you have to deal with versioning differences: OS X still ships a lot of older software to remain on GPL2 instead of GPL3, such as Bash 3.x instead of Bash 4.x. The autotools are also often outdated with respect to bleeding-edge Linux distros.
The answer to the core part of your question is, "Sure, why not?" You can use Homebrew to install all of these alternative GNU tools, then put
$(brew --prefix coreutils)/libexec/gnubin
and/usr/local/bin
first in yourPATH
to make sure they're found first:If for some reason
brew
installs a package to another location, also include that in thePATH
variable.If you would rather only replace a few packages, the tricky bit is dealing with all the name changes. Whenever
brew
installs a program that already has an implementation in the core OS, such as when installing GNUcoreutils
, it names its version differently so that you can run either, depending on your need at the time. Instead of renaming all of these symlinks¹, I recommend that you fix all of this up with a layer of indirection:Once you're happy with your new environment, you can put
export PATH=$HOME/linux:$PATH
into your~/.bash_profile
.That takes care of interactive use, either with bulk replacement or single application replacement.
Unfortunately, it does not completely solve the shell script problem, because sometimes shell scripts get their own environment, such as when launched from
cron
. In that case, you could modify thePATH
at the top of each cross-platform shell script:You do not need to make it conditional, since it is just offering the shell another place to look for programs.
Footnotes
/usr/local/bin/gmv
→../Cellar/coreutils/$version/bin/gmv
Related Posts