CLI Magic: Customizing your bash environment

114

Author: Cameron Newham and Bill Rosenblatt

An environment is a collection of concepts that express the things a computer system does in terms designed to be understandable and coherent, and a look and feel that is comfortable. Unix shells present you with such concepts as files, directories, and standard input and output, while Unix itself gives you tools to work with these, such as file manipulation commands, text editors, and print queues. There are also more sophisticated ways of customizing your shell environment.

This article is excerpted from the recently published book “Learning the bash Shell.”

The.bash_profile,.bash_logout, and.bashrc files

Three files in your home directory have a special meaning to bash, providing a way for you to set up your account environment automatically when you log in and when you invoke another bash shell, and allowing you to perform commands when you log out. These files may already exist in your home directory, depending on how your system administrator has set up your account. If they don’t exist, your account is using only the default system file/etc/profile. You can easily create your own bash files using your favorite text editor.

The most important bash file,.bash_profile, is read and the commands in it executed by bash every time you log in to the system. If you examine your.bash_profile you will probably see lines similar to:

PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/bin
SHELL=/bin/bash
MANPATH=/usr/man:/usr/X11/man
EDITOR=/usr/bin/vi

PS1='h:w$ '
PS2='> '
export EDITOR

These lines define the basic environment for your login account. When editing your.bash_profile, just add your new lines after the existing ones.

Note that whatever you add to your.bash_profile won’t take effect until the file is re-read by logging out and then logging in again. Alternatively, you can also use the source command. For example:

source.bash_profile

source executes the commands in the specified file, in this case.bash_profile, including any commands that you have added.

bash allows two synonyms for.bash_profile:.bash_login, derived from the C shell’s file named.login, and.profile, derived from the Bourne shell and Korn shell files named.profile. Only one of these three is read when you log in. If.bash_profile doesn’t exist in your home directory, then bash will look for.bash_login. If that doesn’t
exist it will look for.profile.

One advantage of bash‘s ability to look for either synonym is that you can retain your.profile if you have been using the Bourne shell. If you need to add bash-specific commands, you can put them in.bash_profile followed by the command source.profile. When you log in, all the bash-specific commands will be executed, and bash will source.profile, executing the remaining commands. If you decide to switch to using the Bourne shell you don’t have to modify your existing files. A similar approach was intended for.bash_login and the C shell.login, but due to differences in the basic syntax of the shells, this is not a good idea.

.bash_profile is read and executed only by the login shell. If you start up a new shell (a subshell) by typing bash on the command line, it will attempt to read commands from the file.bashrc. This scheme allows you the flexibility to separate startup commands needed at login time from those you might need when you run a subshell. If you need to have the same commands run regardless of whether it is a login shell or a subshell, you can just use the source command from within.bash_profile to execute.bashrc. If.bashrc doesn’t exist then no commands are executed when you start up a subshell.

The file.bash_logout is read and executed every time a login shell exits. It is provided to round out the capabilities for customizing your environment. If you wanted to execute some commands that remove temporary files from your account or record how much time you have spent logged in to the system then you would place the commands in.bash_logout. This file doesn’t have to exist in your account — if it isn’t there when you log out, then no extra commands are executed.

Aliases

If you have used Unix for any length of time you will have noticed that there are many commands available and that some of them have cryptic names. Sometimes the commands you use the most have a string of options and arguments that need to be specified. Wouldn’t it be nice if there were a feature that let you rename the commands or allowed you to type in something simple instead of half a dozen options? Fortunately, bash provides such a feature: the alias.

Aliases can be defined on the command line, in your.bash_profile, or in your.bashrc, using this form:

alias name=command

This syntax specifies that name is an alias for command. Whenever you type name as a command, bash will substitute command in its place when it executes the line. Notice that there are no spaces on either side of the equal sign (=); this is the required syntax.

There are a few basic ways to use an alias. The first, and simplest, is as a more mnemonic name for an existing command. Many commonly used Unix commands have names that are poor mnemonics and are therefore excellent candidates for aliasing, the classic example being:

alias search=grep

grep, the Unix file-searching utility, was named as an acronym for something like “Generalized Regular Expression Parser.” This acronym may mean something to a computer scientist, but not to the office administrator who has to find Fred in a list of phone numbers. If you have to find Fred and you have the word search defined as an alias for grep, you can type:

$ search Fred phonelist

Some people who aren’t particularly good typists like to use aliases for typographical errors they make often. For example:

alias emcas=emacs
alias mali=mail
alias gerp=grep

This can be handy, but we feel you’re probably better off suffering with the error message and getting the correct spelling under your fingers. Another common way to use an alias is as a shorthand for a longer command string. For example, you may have a directory to which you need to go often. It’s buried deep in your directory hierarchy, so you want to set up an alias that will allow you to cd there without typing (or even remembering) the entire pathname:

alias cdvoy='cd sipp/demo/animation/voyager'

Notice the quotes around the full cd command; these are necessary if the string being aliased consists of more than one word.

As another example, a useful option to the ls command is -F: it puts a slash (/) after directory files and an asterisk (*) after executable files. Since typing a dash followed by a capital letter is inconvenient, many people define an alias like this:

alias lf='ls -F'

A few things about aliases are important to remember. First, bash makes a textual substitution of the alias for that which it is aliasing; it may help to imagine bash passing your command through a text editor or word processor and issuing a “change” or “substitute” command before interpreting and executing it. Any special characters (such as wildcards like * and ?) that result when the alias is expanded are interpreted properly by the shell. For example, to make it easier to print all of the files in your directory, you could define the alias:

alias printall='pr * | lpr'

Second, keep in mind that aliases are recursive, which means that it is possible to alias an alias. A legitimate objection to the previous example is that the alias, while mnemonic, is too long and doesn’t save enough typing. If we want to keep this alias but add a shorter abbreviation, we could define:

alias pa=printall

With recursive aliasing available it would seem possible to create an infinite loop:

alias ls='ls -l'

bash ensures that this loop cannot happen, because only the first word of the replacement text is checked for further aliasing; if that word is identical to the alias being expanded, it is not expanded a second time. The above command will work as expected (typing ls produces a long list with permissions, sizes, owners, etc.), while in more meaningless situations such as:

alias listfile=ls
alias ls=listfile

the alias listfile is ignored.

Aliases can be used only for the beginning of a command string — albeit with certain exceptions. In the cd example above, you might want to define an alias for the directory name alone, not for the entire command. But if you define:

alias anim=sipp/demo/animation/voyager

and then type cd anim, bash will probably print a message like anim: No such file or directory.

An obscure feature of bash‘s alias facility — one not present in the analogous C shell feature — provides a way around this problem. If the value of an alias (the right side of the equal sign) ends in a blank, then bash tries to do alias substitution on the next word on the command line. To make the value of an alias end in a blank, you need to surround it with quotes.

Here is how you would use this capability to allow aliases for directory names, at least for use with the cd command. Just define:

alias cd='cd '

This causes bash to search for an alias for the directory name argument to cd, which in the previous example would enable it to expand the alias anim correctly.

Finally, there are a few useful adjuncts to the basic alias command. If you type alias name without an equal sign (=) and value, the shell
will print the alias’s value or alias name not found if it is undefined. If you type alias without any arguments, you get a list of all the aliases you have defined. The command unalias name removes any alias definition for its argument.

Aliases are very handy for creating a comfortable environment, but they have essentially been superseded by shell scripts and functions, which give you everything aliases do plus much more. If you become proficient at them, you may find that you don’t need aliases anymore. However, aliases are ideal for novices who find Unix to be a rather forbidding place, full of terseness and devoid of good mnemonics.