Living Without Sudo

Friday, November 29, 2013 · 4 min read

You should not trust me with matches, knives, expensive cars, and sudo: the command that makes you a god-like user with root powers. I'm the kind of person who accidentally rm -rf's his Desktop (by the way, the sporadically disappearing icons are both hilarious and mortifying). So whenever I'm asked to sudo something, I get both worried and suspicious. And over the years, I have perfected the art of installing things without sudo. You can follow along this tutorial with just a shell.

Why sudo?

The first thing to realize here is that 99% of the time, the only reason we need to use sudo is to make that program accessible to everyone. That's it. When you run a UNIX program, you're saying execute this file; and when you sudo you essentially say everyone can access this file from everywhere.

For example, suppose I want to install a program called easy that acts like the classic Staples Easy Button and executes say that was easy (I actually do have this on my computer, and yes, I use it a lot). It's not too tough:

echo "say that was easy" > ~/Desktop/easy # create the file "easy" with our contents
chmod +x ~/Desktop/easy # tell your computer that it's ok to execute this file
~/Desktop/easy # run it!

Now I can run my script by typing ~/Desktop/easy. But I don't want to have to type that huge thing each time I do something awesome—I want easy to be one-step executable just like vim. This is where sudo comes in.

Bash reads a variable called $PATH, which contains a list of various directories separated by colons. When you type a command on the shell, Bash searches each of these directories for that file, one by one. You can see this list right now with echo $PATH. These directories contain important system files, and are accessible by everyone. So it makes sense not to let mortals like me to mess with them. When you install a package, most of the time you're just moving the script files to one of these directories so it's easy to run, and Bash asks you for sudo to make sure you know what you're doing.


If we could tack on our own directory to the $PATH, we could dump our junk in there without messing with anything sudo-ey, right? Right. To modify $PATH, you need another UNIX trick: a file called ~/.profile.

.profile is another script file that's executed before your shell loads, so that you can customize it. The dot in front makes it invisible to Finder, so you can only mess with it using a shell. You can do all sorts of neat things with .profile: print a friendly message on top of the Terminal when you start it up, customize your prompt, and mess with your $PATH.

Since it's a hidden file, you should create it using the command line:

cd ~/ # go to your home directory
touch .profile # create the file
open -a TextEdit .profile # open with TextEdit (you can also use pico/vim/emacs)
…and you should have TextEdit open up with a blank .profile. Now we can create our new $PATH by tacking on ~/my_bin to it. Add the following to the .profile: export PATH=$PATH:~/my_bin. Save, and quit; and then refresh your Terminal (you can just close this window and open a new one). This forces the profile to be run. If you want a sanity check, try echo $PATH and see if it changed from last time.

We just told Bash that ~/my_bin contains executable files. We have not created that directory yet, so let's got do that: mkdir my_bin. And, just for fun, dump easy in there.

Now you can test it out: type easy. If all went well, there shouldn't be any errors. (If something exploded, feel free to drop a comment below.)

Using your powers.

That's actually all you need. To install a package, download it and look for its binaries (they will probably in a directory called bin). Alias the commands you care about to ~/my_bin. And then have fun.

If you use Python, you may want to add the following line to your profile: export PYTHONPATH=$PYTHONPATH:~/my_bin/. This lets you simply copy Python modules to your ~/my_bin. Also take a look at `virtualenv`.

On a Mac, it's worth installing Homebrew this way—almost everything works when locally compiled with it.

Some packages need configuration files to work right from a foreign directory. For example, npm needs you to create .npmrc and add a prefix, or the directory which you want to isolate all node stuff in. Mine simply reads prefix = "~/my_bin/node_stuff".

Finally: if you mess up your profile, you may have unpleasantries with your terminal (what if you accidentally clear your $PATH? Bash won't find any executables whatsoever…). To fix this, always remember that you can reference a command from its full path. Your last resort should be /usr/bin/rm ~/.profile, which will wipe out the profile file, and let you start fresh.

Good luck, and hack on!

◊ ◊ ◊