Some Useful Unix, part 1

I work at the terminal a lot, but have only in the last year or so started making a concerted effort to learn more than the basics, the commands specific to my workflow, and the random bits I retained from my undergraduate CS minor. In this and the next post I’m going to cover some of the bits of unix knowledge I’ve found most useful (and a couple that are just fun). I will assume some comfort with ubiquitous commands such as ls and cd, but start at a pretty basic level for the sake of self-containment. I’m assuming a bash shell here; if you’re using the Terminal on a Mac that’s what you’ll get. Most of this should translate to other unix flavors.

man and help

“Man pages” are in-terminal manuals for commands. Run man ls to see the alphabet of options available for ls, an explanation of its output, and other related information. A lot of man pages even have examples. Sometimes you will run into a command that is so basic it doesn’t have a man page, though; these are called “builtins” and to see their information you use the command “help”. For example, man cd will just get you a list of builtins and an explanation of what that means, whereas help cd will give you a paragraph of cd-specific information and options. Help files are not as extensive as man pages but they’ll get you somewhere.

Of course some commands don’t have man pages but are also not builtins; those would typically be commands defined by something extra installed in your system rather than by bash.

.bashrc, .bash_profile, and source

.bashrc and .bash_profile are both shell configuration files. If you are on a Macintosh, when you open Terminal it will execute the contents of .bash_profile; if you open a subshell (via the command bash, or for a different flavor of unix) it will execute .bashrc. The difference is that the Mac automatically logs you in when you open Terminal, and .bash_profile is run for login shells; there’s no separate login for subshells, and .bashrc is run for non-login interactive shells. Different online tutorials for making changes to your configuration will tell you different files in which to make them; on the Mac you’re generally safe making all changes to .bash_profile.

However, you can have them track each other. First a moment on the source command: source <filename> reads and executes all commands from <filename>, so if you change .bash_profile you can source it instead of closing and reopening Terminal to get the changes in your configuration. So, to get .bashrc to track .bash_profile so you can make all changes to the latter, make the contents of .bashrc the following:

if [ -f ~/.bash_profile ]; then
   source ~/.bash_profile
fi

And of course, you can reverse that if desired, and source .bashrc inside .bash_profile. This great trick came from Kevin Skoglund’s Unix for Mac OS X Users class on lynda.com. As a plug, I’ve now watched Lynda classes by Kevin on Unix, Git, PHP/MySQL, and regular expressions and found all of them incredibly interesting and educational.

One additional note: bash reads lines beginning with # (pound sign) as comments.

PATH, export, which, whereis

PATH is an environmental variable, part of your configuration of bash, that tells the system where to look for the meaning of a command you’ve typed. It is a list of directories separated by colons, and the system will look in each one in order until it finds an executable file that matches your command. You can see your current PATH with echo $PATH or cat $PATH.

When you need the system to look in a new spot, such as your node_modules/.bin folder, you have to add that directory to the path. In this case you would probably do
PATH="./node_modules/.bin:${PATH}"
export PATH
Export tells bash all commands executed later should see and use this version of PATH (but see [1], below). You can also augment your PATH in one line via
export PATH="./node_modules/.bin:${PATH}"

What is going on with PATH, $PATH, ${PATH}? PATH is the variable name; in bash you define variables by typing the name, equals with no space on either side, and then the value. To use a variable you must “substitute” it – that is, get bash to give you the value of the variable. The full command for variable substitution is ${variable_name}, which has the shorthand of $variable_name – you’ll most often see the shorthand but the full version is more error-proof. So that command says to change the value of the variable PATH to the string “./node_modules/.bin:” followed by the current value of PATH.

PATH is important to understand because it is not uncommon to have more than one version of a program. For example, even the Mac documentation recommends you install your own version of Python despite there being a pre-installed version. I had some PATH-related problems from Python 2 vs 3 – I needed to use v2 to execute a script, but an outside program had added a directory for its installation of Python 3 to the beginning of my PATH. Even if I executed the Python I wanted, via giving the full /path/to/python in the command line, the additional packages would be the wrong version and error out. In that case I just commented out the offending PATH redefinition, but I could also potentially have moved it to the end:
replace
export PATH="/offending/path:$PATH"
with
export PATH="$PATH:/offending/path"

In my Python case I knew the problem was related to versioning and hence had an approach to diagnosing and fixing it. Relevant to our PATH discussions and troubleshooting are the commands which and whereis. Running whereis python will tell you the “fundamental” version of python – the version located in standard binary directories (see also [2], below). To determine which version of python you’re actually going to get if you type python, run which python. This will look through the PATH in the same way bash does when it executes python, stopping at the first location with an executable for python. In this case, though, the path to that executable is printed (rather than the python executable being run).

[1] export: whether you actually need export to share variables will depend on your version of bash, but it will never be bad to include it so it’s good to be in the habit. See using the export builtin (bourne shell).

[2] whereis: on my Mac I have yet to see a whereis response of more than one path. However, in other unix versions it may give all locations in which an executable is found, including perhaps in your customized $PATH.

That’s enough for one post. Next time we’ll cover alias and other ways to rerun commands, jobs and processes, and a little bit of fun.


“Ancient Unix” screenshot from Wikimedia Commons.

Leave a Reply

Your email address will not be published. Required fields are marked *