APLawrence.com -  Resources for Unix and Linux Systems, Bloggers and the self-employed

Use and Abuse of /usr/local/bin

© January 2000 Tony Lawrence
January 2000

It starts when some poor soul has written a script to do some thing or another, and happens to mention that it was called "/usr/bin/whatever".

Of course the hapless poster usually had no real reason to mention its path, that was just an accident, or it appeared in some other script that was being posted for examination. No matter, the damage is done, for immediately some defender of the faith is going to chide the poster and sanctimoniously inform them that the proper place for home grown scripts is /usr/local/bin. In some cases, that's all the poor person gets: whatever the question originally was is forgotten and only the placement issue is discussed.

Sometimes the original poster will object, especially when it seems that their honor has been impugned and the respondent seems to be looking down a very long nose at any person who would dare to place scripts other than the One Holy Place. That's a mistake, because defenders of the faith run in packs, and once the faith has been questioned, they pile on in depth to convert the sinner. Those who endure such attacks often end up converted themselves, and will joyfully join in the next time someone wanders in spreading false gospel. I call such people Localists.

But the truth is: it's all B.S. and the Localists preach a false religion.

Yep, you heard me. It's crapola. Yes, you'll hear this nonsense spouted by some of the most illustrious names in Unixdom, you'll see it in the best books, and the arguments that are trotted out will cause much sage head nodding and stroking of chins. Nonetheless, it is all crap.

The reason it's crap is not because the arguments against putting your scripts in /usr/bin are specious. They aren't, or at least aren't entirely so. The basic argument is this: the stuff in /usr/bin was supplied by the OS vendor. If you put stuff in there, then when it comes time to upgrade, it's harder to do. But if your stuff was in /usr/local/bin, we could just save that directory and life would be wonderful. That argument by itself doesn't really hold water, because it is trivial to restore your scripts by restoring non-destructively- that is, don't replace anything from the backup that's already there, but do bring back anything that isn't. However, the Localists then warn (correctly) that commands may move from release to release: what was in /usr/bin/ may now be in /bin. So? That only requires a more intelligent restoration; I have scripts that check for such conditions in my Upgrades article, and the concept can be adopted to fit any circumstance.

The Localists aren't done yet, though. Their final card is that some new OS command might happen to use the same name as your local command, so the intelligent restoration fails, and when some other script happens to call that name, it will now fail. Sounds convincing now? Nope. Because in most cases, having it in /usr/local/bin wouldn't have helped: that would usually be later in the PATH, so the command would probably fail anyway. And who says that some package you bring down from the net won't accidentally use the same name as your command? So none of the Localist arguments really work.

Just the same, it's probably NOT the best idea to put your commands in /usr/bin. Organizationally, it makes better sense to have them elsewhere, and it does help (a minor boost, but what the heck) during upgrades. And if we get unlucky and the new OS usurps our command's name for its own use, we're ahead of the game if it already lives somewhere else. But that somewhere else should NOT be /usr/local/bin!

The Localists Fallacy

The problem is simply that in this day and age, /usr/local/bin suffers from the same problem that /usr/bin has. Anything you get from the net invariably installs to /usr/local/bin. At the time I wrote this article, my /usr/local/bin had 560 files in it- and most of them aren't really "local"- somebody else wrote them, I just installed them. When I upgrade, I usually have to upgrade those things also. So every argument against putting your home grown scripts in /usr/bin applies just as much to /usr/local/bin- same problems, same arguments.

Therefor, I suggest that you put your home grown scripts in your own directory structure: /usr/mystuff/bin or whatever, and further that you NEVER assume that it is in $PATH in calling scripts, but rather call it explicitly: /usr/mystuff/bin/whatever. This prevents the theft of "whatever" by another set of programs, and if some person upgrades the server years from now when you are long gone, and does not notice /usr/mystuff/bin, the calling scripts failure will immediately point them to the remedy.

It's fine to have your special place in $PATH; just be sure to be explicit in any other scripts you write.

This protocol could also be a source of great fun. If you get creative with your names (/usr/boopy/bin?), and happen to accidentally include the full path in a newsgroup post, it's bound to attract the attention of the Localists, but what can they say? Perhaps, if you are lucky, they'll sniff that /usr/local/bin is the "proper" place for your command, and then you can have some fun tying them up with their own ropes. Personally, I think that could be a lot of fun!

Bill Vermillion had some comments:

You mention you had 560 files in /usr/local/bin. The BSD world makes great use of /usr/local. The more I work with this the more I like it.

root@bilver # pwd
root@bilver # find . -print | wc
   26724   26724 1016763            <<*** beats your 560!!!

/usr/local has all this besides just bin

total 77168
drwxr-xr-x  23 root      wheel          512 Nov 20 06:56 .
drwxr-xr-x  23 root      wheel          512 Mar 26 09:12 ..
drwxr-xr-x   6 root      wheel          512 Jul  4  2000 Acrobat4
dr-xr-xr-x   8 root      wheel          512 Aug  8  2000 apsfilter
drwxr-xr-x   2 root      wheel        15872 Apr  3 21:14 bin
drwxr-xr-x   4 root      wheel          512 Jan 30 18:22 bind
drwxr-xr-x   2 root      wheel          512 Jul  2  2000 cgi-bin
drwxr-xr-x   3 root      wheel          512 Aug 20  2000 doc
drwxr-xr-x   4 root      wheel          512 Jun 25  2000 domtools
drwxr-xr-x  11 root      wheel         1024 Apr  2 11:37 etc
drwxr-xr-x  22 root      wheel         5120 Apr  3 21:14 include
drwxr-xr-x   2 root      wheel         1536 Feb 24 22:37 info
drwxr-xr-x  24 root      wheel         5632 Apr  3 21:14 lib
drwxr-xr-x   4 root      wheel          512 Apr  2 11:37 libexec
drwxr-xr-x   8 majordom  majordom       512 Jan 10 10:39 majordomo
drwxr-xr-x  26 root      wheel          512 Aug  6  2000 man
drwxrwxr-x   7 news      bin           1024 Apr  5 11:04 news
drwxr-xr-x   2 root      wheel          512 Aug  7  2000 newsspool
dr-x------   2 root      wheel          512 Aug  8  2000 private
drwxr-xr-x   8 root      wheel          512 Aug  7  2000 samba
drwxr-xr-x   2 root      wheel         1024 Mar 23 08:25 sbin
drwxr-xr-x  46 root      wheel         1024 Feb 24 22:37 share
drwxr-xr-x   5 root      wheel          512 Jun 25  2000 www

Not the lib, libexec, man, etc. In this arena local means that they just aren't part of the base OS. And the old routines about OS upgrades needing to change some of these isn't quite true.

I just upgraded the OS on a server remoted. I cvsuped the sources, made them all, and performed 'buildworld' which remakes every system program, because a lot of the times there are new libraries. Then there is a 'mergemaster' which merges all the startup files so you can edit as you go, replace or hold them off. A reboot and you are running. The system was lightly used, but live.

What I also like is the way the rc.d stuff runs. There is small file used to override the system defaults, but under /usr/local/etc there is an rc.d directory, which executes anything that is executeable AND has an extension .sh. This ensure that all local things are run only after the system is up. I like this better than the Sys V Sxx numbering system.

Heres the /usr/local/etc

total 274
drwxr-xr-x  11 root  wheel    1024 Apr  2 11:37 .
drwxr-xr-x  23 root  wheel     512 Nov 20 06:56 ..
-rw-r--r--   1 root  wheel    5496 Mar 12  2000 Muttrc
-r--r--r--   1 root  wheel    2518 Jul  4  2000 a2ps-site.cfg
-r--r--r--   1 root  wheel   12878 Jul  4  2000 a2ps.cfg
drwxr-xr-x   2 root  wheel     512 Oct 21 17:19 apache
drwxr-xr-x   2 root  wheel     512 Jun 25  2000 cal
drwxr-xr-x   2 root  wheel     512 Jun 25  2000 codepages
-r--r--r--   1 root  wheel    4993 Mar 12  2000 enscript.cfg
-r--r--r--   1 root  wheel      77 Mar 12  2000 esd.conf
-rw-r--r--   1 bin   bin       404 Mar 11  2000 ftpaccess.example
-rw-r--r--   1 bin   bin       534 Mar 11  2000 ftpconversions.example
-rw-r--r--   1 bin   bin        37 Mar 11  2000 ftpgroups.example
-rw-r--r--   1 bin   bin       190 Mar 11  2000 ftphosts.example
-rw-r--r--   1 bin   bin        69 Mar 11  2000 ftpusers.example
-rw-r--r--   1 root  wheel     756 Mar 11  2000 ipfm.conf
-rw-r--r--   1 root  wheel      33 Mar 12 15:30 line
-r--r--r--   1 root  wheel   97203 Mar 16  2000 lynx.cfg
-r--r--r--   1 root  wheel   97203 Mar 16  2000 lynx.cfg.default
drwxr-xr-x   2 root  wheel     512 Jun 29  2000 lynx_doc
-rw-r--r--   1 root  wheel    1898 Mar 12  2000 mime.types
-r--r--r--   1 root  wheel    4441 Aug  6  2000 mtools.conf
-rw-r--r--   1 root  wheel    1883 Mar 11  2000 muttzilla.conf
drwx------   2 pop   daemon    512 Apr  2 11:37 popper
drwxr-xr-x   2 root  wheel     512 Jul  4  2000 raddb
drwxr-xr-x   2 root  wheel     512 Oct 22  1996 rc.d
drwxr-xr-x   2 root  wheel     512 Aug 25  2000 rpm
lrwxr-xr-x   1 root  wheel      26 Aug 25  2000 rpmpopt -> /usr/local/etc/rpm/rpmpopt
lrwxr-xr-x   1 root  wheel      24 Aug 25  2000 rpmrc -> /usr/local/etc/rpm/rpmrc
-rw-r--r--   1 root  wheel     729 Mar 12 15:30 smb.conf
-rw-r--r--   1 root  wheel    9250 Mar 11  2000 smb.conf.default
-r--r--r--   1 root  wheel    6471 Mar 12  2000 sockd.conf.example
-r--r--r--   1 root  wheel    3079 Mar 12  2000 socks.conf.example
drwxr-xr-x   2 root  wheel     512 Oct 21 09:45 ssh2
-r--r-----   1 root  wheel     294 Mar 23 08:17 sudoers
-r--r--r--   1 root  wheel     716 Sep 11  2000 trafshow
-r--r--r--   1 root  wheel    3313 Aug 17  2000 wgetrc
-r--r--r--   1 root  wheel     200 Dec 20 17:43 xmlConf.sh

And the /usr/local/etc/rc.d


total 8
drwxr-xr-x   2 root  wheel   512 Oct 22  1996 .
drwxr-xr-x  11 root  wheel  1024 Apr  2 11:37 ..
-rwxr-x--x   1 root  wheel   111 Mar 11  2000 apache.sh.hold
-rwxr-x---   1 root  wheel    51 Mar 12  2000 mysql-client.sh.hold
-rwxr-x---   1 root  wheel   133 Mar 12  2000 mysql-server.sh.hold
-rwxr-x--x   1 root  wheel   374 Mar 11  2000 rwhoisd.sh.sample
-r-xr-xr-x   1 root  wheel   392 Aug  8  2000 samba.sh
-r-xr-xr-x   1 root  wheel   392 Mar 11  2000 samba.sh.sample

As long as the file ends in .sh it executes. A quick rename makes them be on or off at next boot.

Publish your articles, comments, book reviews or opinions here!

Got something to add? Send me email.

(OLDER)    <- More Stuff -> (NEWER)    (NEWEST)   

Printer Friendly Version

-> Use and Abuse of /usr/local/bin


Inexpensive and informative Apple related e-books:

Take Control of Numbers

Take Control of High Sierra

iOS 10: A Take Control Crash Course

Take Control of Automating Your Mac

Take Control of Apple Mail, Third Edition

More Articles by © Tony Lawrence

Wed Sep 16 16:07:30 2009: 6918   jtimberman

The correct answer of where to store all that stuff is in a software version control system like Git, Subversion, CVS or any of the other SCM/VCS tools out there. Then that should all be deployed to systems using a configuration management tool, whether that is Chef, Puppet, cfengine, Makefiles, Rakefiles, Capfiles or a homegrown ssh-for-loop solution.

Then it doesn't matter if you (or your client) wants to install in /usr/local, /opt, or /my_monkeys_play_here. You point things to the right path, and go. When the system is upgraded, you redeploy again, and everything goes into the correct location.

Wed Sep 16 16:14:08 2009: 6919   TonyLawrence

That doesn't answer the overwrite problem. Yes, you get your scripts back, but if they have overwritten newly born vendor scripts, you may break something else - and may have a heck of a time figuring out why.

If your redeploy is intelligent enough to recognize an overwrite, that helps, but then you still have to go chase the loose ends.

Better to put it in /my_monkeys_play_here


Printer Friendly Version

Have you tried Searching this site?

This is a Unix/Linux resource website. It contains technical articles about Unix, Linux and general computing related subjects, opinion, news, help files, how-to's, tutorials and more.

Contact us

Printer Friendly Version

Why bother with subroutines when you can type fast? (Vaughn Rokosz)

Linux posts

Troubleshooting posts

This post tagged:



Unix/Linux Consultants

Skills Tests

Unix/Linux Book Reviews

My Unix/Linux Troubleshooting Book

This site runs on Linode