
Using /usr/local - vectorpush
http://hivelogic.com/articles/using_usr_local/
======
SkyMarshal
One of the things I love about the Debian ecosystem is that there's a tool
that's even better than what this post recommends. Debian _update-
alternatives_ , available on any Debian-derived distro.

 _update-alternatives_ allows you to compile or unzip software to somewhere
obscure and safe, like /opt, then soft-link it to /usr/local with _update-
alternatives --install_. The benefits:

1\. You can slave all dependencies to the main binary, so that they can all be
removed with _update-alternatives --remove_.

2\. You can install multiple versions simultaneously (including the system
version), flag one as active, and toggle between them easily with _update-
alternatives --config_.

3\. #2 lets you upgrade to a new version (say of Java, Scala, Haskell,
whatever) without uninstalling or overwriting the current version, and if the
new version breaks your app you can toggle back to the known working version
with a quick _update-alternatives --config_.

4\. Keep all the files together in their own directory, like
_/opt/java/jdk/1.7.0_07_ , instead of strewn all across /usr/local, /usr/bin,
/usr/lib, /usr/share, etc. Soft link them instead into their appropriate
locations.

I created _update-alternatives_ install scripts for Haskell Platform [1], Java
[2], and Scala [3] for anyone interested in seeing more how it works.

[1]:
[https://github.com/byrongibson/scripts/tree/master/install/h...](https://github.com/byrongibson/scripts/tree/master/install/haskell)

[2]:
[https://github.com/byrongibson/scripts/tree/master/install/j...](https://github.com/byrongibson/scripts/tree/master/install/java)

[3]:
[https://github.com/byrongibson/scripts/tree/master/install/s...](https://github.com/byrongibson/scripts/tree/master/install/scala)

~~~
peterwwillis
I remember seeing a different tool which takes care of all that for you so you
don't have to write scripts, but I forget its name now. It's definitely a good
idea (slotting software installs) but it needs more automation.

~~~
SkyMarshal
I only use the scripts to slave all the dependent binaries to the main binary.
If you only have one binary, it's just a single line. (I also script literally
everything, even single-liners).

I don't know if there's any way to do something like that without update-
alternatives or your tool having some built-in awareness of the package's
dependencies, but that's not really possible for a tool designed to be able to
handle literally any arbitrary, user-compiled/installed package. Otherwise you
get the system package manager again.

~~~
peterwwillis
The tool I remember would basically do the equivalent of:

    
    
      for file in `find /opt/package_name/version/` ; do
          NEW=`echo $file | sed -e "s/^\/opt\/package_name\/version\//"`
          ln -s $file /usr/local/$NEW
      done
    

Where the base files are installed in /opt/package_name/version/ and all of
them are symlinked into /usr/local/ by default with the option of changing
individual file links. This way you change the entire 'installed' version of a
package without needing application-specific path modifiers. But you can still
build applications against specific versioned directories (if you have an app
which requires BerkeleyDB 4.1 which conflicts with 4.0, for example)

(You can automate that for a pre-existing package if it's got relocatable
code, but hardly as reliable as building it from scratch for the versioned
directory and changing symlinks in /usr/local)

------
masklinn
> Specify the /usr/local Prefix in Scripts

> When writing scripts, specify the full path to the executable you’ve
> installed in the first line of the script.

No. Don't do that. Bad. Even for maintenance and admin scripts, that makes
them severely less portable and harder to keep in sync across machines for
various reasons. Your path is setup correctly, just use that: there are very
few reasons for your shebang lines to be anything other than:

    
    
        #!/usr/bin/env $executable "$options"
    

This will make the shebang work using the normal rules of path-resolution, and
means path-override tools and methods (e.g. python virtual environments, or
`PATH=$somedirectory ./script`) will work correctly.

edit: I am told not all versions of shebang/`env` support passing options to
the $executable, and most notably it doesn't work on Linux. So don't do that,
and i won't in the future. Still, $executable is usually sufficient

~~~
jayferd
+1.

At a previous job, I spent hours rebuilding a ruby gem where someone had
carelessly hard-coded "#!/usr/local/bin/ruby" into all of their executables.

Even if it looks like it works, don't do it! Stick to "#!/usr/bin/env ruby"
for maximum compatibility, please.

~~~
thwest
Coming from a c and python perspective, I'm amazed that you even can specify
which ruby to run it with. Either its a compiled binary, or you call the
interpreter with the code object as an argument. What is the design impetus
for mixing scripting and executable styles this way?

~~~
jayferd
Shebangs (#!) have been around for quite a long time. It's actually really
handy to be able to write a script that you can execute as a command. See
<https://en.wikipedia.org/wiki/Shebang_(Unix)>

------
loeg
I've read better articles on Unix. Just a few thoughts:

1) Software packages should probably install into /usr/local by default, not
/usr as the author suggests. Distributions can always pass an option to
install into /usr in their build scripts. In my experience as a distro
packager, plenty of package-build/install systems install to /usr/local by
default (autotools, python's disttools IIRC, etc).

2) FreeBSD (and likely other *BSD OS) ports install into /usr/local. So, if
you're using the ports system for package management, you might still be
screwed. (Of course, if you, as an admin, don't notice that you're installing
over system packages, your system is going to end up hosed some day anyway.)

At the end of the day, go ahead and use /usr/local. But be aware what your
system does with it, and that other 3rd party packages may randomly scribble
all over it as well.

~~~
ZoFreX
Regarding point 2, the ports system works a little bit differently to typical
package managers, and easily accomodates running customised versions of the
software you need.

Another difference between FreeBSD and (most) Linux distros is the concept of
the "base system". Things in /bin and /usr/bin are part of the base, any
additional packages you install end up in /usr/local. This has the nice effect
of separating things you really, really need to work for the system to be
functional (i.e. boot and log in) and software that is "nice to have" but not
strictly necessary (your webservers and Rubies and what have you). I also find
that /usr/local/etc is generally very small and tidy, which makes
administration and backup a doddle.

I think the author of the post is a little bit muddled on what /usr/local is
for, though - the analogy to installing applications to ~/Applications on OS X
is completely flawed, as in OS X that installs things only for the current
user, whereas /usr/local is available to all.

~~~
anonymous
True, the linux equivalent would be ~/.local . What I usually do for software
I need only for my user is to install it in ~/.local/<package name> and then
symlink what I need into ~/.local/bin,lib,etc.. with bin being on my PATH. If
the binary needs to see its own libs, I write a small script that sets
LD_LIBRARY_PATH prior to execution and use that. This way removing is simply
rm -r ~/.local/<package> and I don't pollute the rest of the system.

------
dfc
I see a lot of comments lamenting the downfall of HN recently and they almost
always focus on poor comments. In my opinion the troublesome trend on HN has
been stories like this (or yesterday's bash redirection cheat sheet) making it
to the front page. This is Hacker News not Un*x For Dummies.

~~~
crazygringo
What is with the complaints about the "downfall" of quality recently? If you
don't like the article, just don't upvote it. Writing a comment for the
article about how it shouldn't be here isn't serving any purpose.

~~~
adri9n
Odd, though, that a 7 year old article can turn up as news.

~~~
vog
This effect isn't odd at all. It is explained quite well in:
<https://xkcd.com/1053/>

------
philsnow
Dumping everything into /usr/local doesn't even work well when you're the only
user on the system: most packages don't define an "uninstall" make target, and
installing multiple versions of things is often not well-defined.

See e.g. checkinstall, GNU stow, encap, and probably several more that I'm
missing for examples of people trying to fix the crappiness of ad-hoc (non-
distribution-based) package management.

~~~
alexchamberlain
On Arch, you can just write your own PKGBUILD.

~~~
emillon
To be fair, you can do that on any distribution, that is their point.

------
pstadler
Don't forget to add the following line to your .bash<whatever> to make the man
pages of your custom software accessible:

    
    
        export MANPATH=/usr/local/share/man:$MANPATH
    

This works for packages installed with homebrew and othe software that follows
the standards.

~~~
pooriaazimi
Thanks! I didn't know there was such a thing as $MANPATH!

But, I don't think it's necessary. I don't have `/usr/local/share/man` in my
$MANPATH (I don't have a $MANPATH at all, as a matter of fact), yet `man sl`
works (and by running `sudo opensnoop` in another shell process I verified
that groff indeed pulled the data from `/usr/local/share/man/man1/sl.1`)

(OS X 10.8.1)

~~~
jasomill
You are correct:

    
    
      $ man man
        . . .
      man uses a sophisticated method of finding manual page files, based  on
      the   invocation   options   and   environment   variables,  the  /pri-
      vate/etc/man.conf configuration file, and some built in conventions and
      heuristics.
        . . .
      $ fgrep local/share/man /private/etc/man.conf 
      MANPATH	/usr/local/share/man
      MANPATH_MAP	/usr/local/bin		/usr/local/share/man
      MANPATH_MAP	/usr/local/sbin		/usr/local/share/man
      $
    

(OS X 10.8. _n_ , for some unannounced future value of _n_ , but AFAIK this
behavior is unchanged since 10.4 Tiger)

------
eli
It's a nice article and a cute history lesson... but unless you're going to be
deploying that website to a production server also running OS X, you will be
_much_ better off in a variety of ways installing Lighttpd and Rails to a
virtual machine and developing against that.

~~~
chipotle_coyote
It's worth noticing the article has a 2005 date on it. I suspect there's a lot
of stuff the author (Dan Benjamin of the 5by5 podcast network) would change
now.

~~~
hivelogic
Ain't that the truth. I should probably write an update at some point.

------
jayferd
With /usr/local, though, you still have to use `sudo` - unless you're crazy
and chown or chmod it appropriately. I've been a longtime advocate for
$HOME/.local, which is (a) obviously writable by you, (b) on your home
partition, so it's backed up with all of your data, and (c) a common enough
standard (see the XDG Base Directory Spec) that it's generally easy enough to
get applications to use it. Just add $HOME/.local/bin to your $PATH and you're
good to go.

------
rwbaskette
Given that homebrew tends to occupy /usr/local, I've grown comfortable with
making my own ~/local folder with src, bin and app/server folders. I tend to
use it for just about everything one might want in a /usr/local directory.

~~~
lloeki
From the homebrew FAQ (<https://github.com/mxcl/homebrew/wiki/FAQ>)

    
    
        Can I install my own stuff to /usr/local?
    
        Yes, brew is designed to not get in your way so you can
        use it how you like.
    
        Install your own stuff, but be aware that if you
        install common libraries, like libexpat yourself, it may
        cause trouble when trying to build certain Homebrew
        formula. As a result brew doctor will warn you about
        this.
    
        Thus it’s probably better to install your own stuff to
        the Cellar and then brew link it. Like so:
    
            $ cd foo-0.1
            $ brew diy
            ./configure --prefix=/usr/local/Cellar/foo/0.1
            $ ./configure --prefix=/usr/local/Cellar/foo/0.1
            [snip]
            $ make && make install
            $ brew link foo
            Linking /usr/local/Cellar/foo/0.1... 17 symlinks created
    

And really, writing your own formula is easy if manual steps are easy, and if
they're hard, well, writing a formula makes you do it only once, since you'll
be able to reuse the formula later.

Anyway brew builds in Cellar, and symlinks in /usr/local but never steps on
what you would have installed manually.

------
peterwwillis
/usr/local is a crutch.

When you're a user installing software, you don't get to write to /usr/local.
You have to use $HOME/usr or something and modify your path.

When you're an admin on a box, you can install software anywhere. You could
totally './configure&&make&&make install' and your software lands in
/usr/local. If you're lucky, there won't be any conflicts with existing
earlier versions in /usr. But there's consequences.

Now you've built a lot of software and some of it depends on stuff you put in
/usr/local. Now you need to upgrade. But is something going to break? What's
the compatibility? How can I track what has been installed? Can I uninstall
anything?

You don't realize how big of a mess you're getting into until you have to
remove _all_ of /usr/local just to get some working apps and start from
scratch. Take the time to learn the package manager for your system, and
package your software before installing. Hell, use checkinstall or some other
tool to automate it.

I use my scripts called slacktools [[https://github.com/psypete/public-
bin/tree/public-bin/src/sl...](https://github.com/psypete/public-
bin/tree/public-bin/src/slacktools)] to automate packaging in Slackware. One
command 'slackpack foo-1.4.5.tar.gz' builds me a Slackware package. Tiny
modifications could make it build rpms, debs, etc. The benefit you get is
actually upgrading old packages do you don't have conflicting versions, a sane
default path, and the ability to remove or upgrade the package when necessary.

------
ralph
Disappointed to see no mention of GNU Stow there, very handy for /usr/local
having multiple version of foo installed and being able to make one of them
current, e.g. rewind if a new one breaks things.
<http://www.gnu.org/software/stow/>

~~~
hivelogic
I don't think Stow existed in 2005, when I wrote the article. Thanks for the
pointer.

~~~
ralph
If definitely existed before 1996 as I recall introducing it to a particular
company's servers. :-)

------
barakm
And BSD users have been doing this forever. I know I've read about why Linux
is divergent, but I forget why.

~~~
morpher
Almost all software I've custom built over the last 13 years of using Linux
has, by default, set the prefix to /use/local. I don't know if ruby is for
some reason different, but installing software outside of /usr/local is not
something to snark at Linux about...

~~~
barakm
No snark intended. I mean only to recognize BSD in the discussion as having
made another choice. And yes, Linux custom-built software goes into /usr/local
without a hitch.

But really, the question comes down to layers of abstraction. Is /bin the base
system? Is /usr/bin? Is /usr/local/bin? Probably not on the last one, but
Linux distros have chosen /usr/bin as where all packages install. And BSD
treats packages as user programs and goes to /usr/local/bin.

I'm not saying one is right. At best, I'm advocating use of "#!/usr/bin/env
foo" instead of some of the assumptions made by some shell scripters.

~~~
npsimons
_But really, the question comes down to layers of abstraction. Is /bin the
base system? Is /usr/bin? Is /usr/local/bin? Probably not on the last one, but
Linux distros have chosen /usr/bin as where all packages install. And BSD
treats packages as user programs and goes to /usr/local/bin._

As I've always understood it, since /usr can be on another partition (to keep
/ small, or keep it from filling up with stuff from /usr, /home, /tmp, and the
like), /bin should contain "essential" binaries for booting that weren't
necessarily "system" tools (those would go in /sbin). Now that I think of it,
I can't really think of binaries essential to booting that aren't "system"
tools, but my Linux boxes typically have about a hundred CLI programs that are
basic, but not essential (AFAICT) to booting in there. They're all from
packages.

~~~
qznc
Apparently most modern Linux distros cannot boot anymore without /usr.
Therefore people suggest to link /bin to /usr/bin etc. /usr/local still has
its place, though.

[http://www.freedesktop.org/wiki/Software/systemd/TheCaseForT...](http://www.freedesktop.org/wiki/Software/systemd/TheCaseForTheUsrMerge)

~~~
npsimons
I'm pretty sure Debian (my Linux of choice) can boot without /usr. And I love
how on that page they bring up BS such as "well Fedora has 450MB (of crap) in
/, so that's not minimal". I've got at least one Debian box packed to the
gills with programming languages, scientific software and who knows what else,
and it clocks in at right around 129MB for /. Maybe Fedora is doing it wrong;
wouldn't surprise me, as I switched from RH to Debian over a decade ago
because of dependency hell.

I'm not sure linking /bin to /usr/bin is a good idea; it may have merits, but
many of the reasons they bring up seem dubious ("Solaris is doing it!", yeah
like Solaris should be the gold standard; "hard coded paths!" - recompile).
I'm not opposed to progress, but some change isn't progress. It's interesting
to me that this initiative is being pushed by Lennart Poettering - well known
for his work on PulseAudio and systemd, two other controverisal Linux
subsystems. While systemd is still unproven (and quite frankly, Poettering's
talk at Linux Plumbers about systemd subsuming more control scared me; it's
like a hydra!), PulseAudio appears to have finally become stable and usable. I
guess time will tell with both systemd and /usr-merging.

Another interesting point from Poettering's talk was that he wanted to take
more after BSD, especially having the one "correct" way to do it. Me, I like
having options, especially in the case of "what if the 'correct' way doesn't
work?" (<http://news.ycombinator.com/item?id=4409768>).

------
mhd
I still wish this wasn't all that hard-coded. A plethora of prefixes, the
whole "/usr" directory from the start (which used to be "/home" back in the
days), _compiling_ software to depend on variant paths, huge PATH variables
and the hassle to define them in the proper place, application data all strewn
about etc.

Yes, there's stow/homebrew like deployment with app-specific directories and
linking to solve some of these problems…

But I really wish _union mounts_ would be more common, both global and on a
per-process basis. Thus you'd just have a /bin directory and just put
everything in there, no matter on what partition or under which "real"
directory it actually is.

------
stouset
> On many UNIX systems, mounting drives has become automatic, and the mount
> points for the drives live in a folder called /mnt.

No, no, no, no, no. This hasn't been the case since at least eight years ago,
when FHS 2.3 (released in Jan 2004) clarified the purpose of `/mnt` and added
the `/media` directory. `/media` is for mountpoints for removable media, and
`/mnt` is for temporarily-mounted filesystems.

~~~
stouset
Ok, the article was written in 2005. I can give it some slack.

------
unhammer
"not knowing, she accepted the default paths at compile time, and the [Ruby]
binary now lives in /usr/bin" wat? Ruby's default is to install to
/usr{/bin,}?? Automake and cmake at least always default to /usr/local{/bin,}
as the prefix in my experience. Other than not mentioning that, yes more
people should know the various prefix conventions, it would save a lot of
installation hassle.

~~~
nspragmatic
No, Ruby's default is to install to /usr/local. It was just an illustrative
example used to demonstrate potential complications from not using /usr/local.
The submission wasn't a guide to building Ruby.

------
antihero
Except doesn't Ubuntu entirely break this by putting packaged files in
/usr/local? I've always use /opt for this purpose.

Then there's stow, which just works nicely.

To be honest, using the Arch Build System and quickly building my own packages
beats all of this.

~~~
viraptor
I don't believe Ubuntu does that. Can you provide some verifiable examples?

------
npsimons
Fairly obvious, if you've been adminning UNIX-type systems for a while, but on
top of this I would add: use stow: <http://www.gnu.org/software/stow/>

------
nathancahill
Wow, excellent write up.

------
njharman
I thought /opt was the new /usr/local, no?

------
Evbn
I remember an argument 10 years ago where a (very knowledgable) coworker swore
to me that /usr/local was supposed to be world writable location for any user
to install software.

He also claimed that he didn't save non-compilng code while he was editing.

