This book’s primary focus is on the Linux system that normally lies underneath server processes and interactive user sessions. But eventually, the system and the user have to meet somewhere. Startup files play an important role at this point, because they set defaults for the shell and other interactive programs. They determine how the system behaves when a user logs in.
Most users don’t pay close attention to their startup files, only touching them when they want to add something for convenience, such as an alias. Over time, the files become cluttered with unnecessary environment variables and tests that can lead to annoying (or quite serious) problems.
If you’ve had your Linux machine for a while, you may notice that your home directory accumulates a bafflingly large array of startup files over time. These are sometimes called dot files because they nearly always start with a dot (.). Many of these are automatically created when you first run a program, and you’ll never need to change them. This chapter primarily covers shell startup files, which are the ones you’re most likely to modify or rewrite from scratch. Let’s first look at how much care you need to take when working on these files.
When designing startup files, keep the user in mind. If you’re the only user on a machine, you don’t have much to worry about because errors only affect you and they’re easy enough to fix. However, if you’re creating startup files meant to be the defaults for all new users on a machine or network, or if you think that someone might copy your files for use on a different machine, your task becomes considerably more difficult. If you make an error in a startup file for 10 users, you might end up fixing this error 10 times.
Keep two essential goals in mind when creating startup files for other users:
Simplicity. Keep the number of startup files small, and keep the files as small and simple as possible so that they are easy to modify but hard to break. Each item in a startup file is just one more thing that can break.
Readability. Use extensive comments in files so that the users get a good picture of what each part of a file does.
Before making a change to a startup file, ask yourself whether you really should be making that change. Here are some good reasons for changing startup files:
You want to change the default prompt.
You need to accommodate some critical locally installed software. (Consider using wrapper scripts first, though.)
Your existing startup files are broken.
If everything in your Linux distribution works, be careful. Sometimes the default startup files interact with other files in /etc.
That said, you probably wouldn’t be reading this chapter if you weren’t interested in changing the defaults, so let’s examine what’s important.
What goes into a shell startup file? Some things might seem obvious, such as the path and a prompt setting. But what exactly should be in the path, and what does a reasonable prompt look like? And how much is too much to put in a startup file?
The next few sections discuss the essentials of a shell startup file—from the command path, prompt, and aliases through the permissions mask.
The most important part of any shell startup file is the command path. The path should cover the directories that contain every application of interest to a regular user. At the very least, the path should contain these components, in order:
/usr/local/bin /usr/bin /bin
This order ensures that you can override standard default programs with site-specific variants located in /usr/local.
Most Linux distributions install executables for nearly all packaged software in /usr/bin. There are occasional differences, such as putting games in /usr/games and graphical applications in a separate location, so check your system’s defaults first. And make sure that every general-use program on the system is available through one of the directories listed above. If not, your system is probably getting out of control. Don’t change the default path in your user environment to accommodate a new software installation directory. A cheap way to accommodate separate installation directories is to use symbolic links in /usr/local/bin.
Many users use a bin directory of their own to store shell scripts and programs, so you may want to add this to the front of the path:
$HOME/bin
If you’re interested in systems utilities (such as traceroute
, ping
, and lsmod
), add the sbin directories to your path:
/usr/local/sbin /usr/sbin /sbin
There is one small but controversial command path component to discuss: the dot. Placing a dot (.
) in your path allows you to run programs in the current directory without using ./
in front of the program name. This may seem convenient when writing scripts or compiling programs, but it’s a bad idea for two reasons:
It can be a security problem. You should never put a dot at the front of the path. Here’s an example of what can happen: An attacker could put a Trojan horse named ls
in an archive distributed on the Internet. Even if a dot were at the end of the path, you’d still be vulnerable to typos such as sl
or ks
.
It is inconsistent and can be confusing. A dot in a path can mean that a command’s behavior will change according to the current directory.
The traditional manual page path was determined by the MANPATH
environment variable, but you shouldn’t set it because doing so overrides the system defaults in /etc/manpath.config.
Experienced users tend to avoid long, complicated, useless prompts. In comparison, many administrators and distributions drag everything into a default prompt. Your choice should reflect your users’ needs; place the current working directory, hostname, and username in the prompt if it really helps.
Above all, avoid characters that mean something significant to the shell, such as these:
{ } = & < >
Take extra care to avoid the >
character, which can cause erratic, empty files to appear in your current directory if you accidentally copy and paste a section of your shell window (recall that >
redirects output to a file).
Even a shell’s default prompt isn’t ideal. For example, the default bash
prompt contains the shell name and version number.
This simple prompt setting for bash
ends with the customary $
(the traditional csh
prompt ends with %
):
PS1='u$ '
The u
is a substitution for the current username (see the PROMPTING section of the bash(1) manual page). Other popular substitutions include the following:
h
The hostname (the short form, without domain names)
!
The history number
w
The current directory. Because this can become long, you can limit the display to just the final component with W
.
$
$
if running as a user account, #
if root
Among the stickier points of modern user environments is the role of aliases, a shell feature that substitutes one string for another before executing a command. These can be efficient shortcuts that save some typing. However, aliases also have these drawbacks:
It can be tricky to manipulate arguments.
They are confusing; a shell’s built-in which
command can tell you if something is an alias, but it won’t tell you where it was defined.
They are frowned upon in subshells and noninteractive shells; they do not work in other shells.
Given these disadvantages, you should probably avoid aliases whenever possible because it’s easier to write a shell function or an entirely new shell script. Modern computers can start and execute shells so quickly that the difference between an alias and an entirely new command should mean nothing to you.
That said, aliases do come in handy when you wish to alter a part of the shell’s environment. You can’t change an environment variable with a shell script, because scripts run as subshells. (You can also define shell functions to perform this task.)
As described in Chapter 2, a shell’s built-in umask
(permissions mask) facility sets your default permissions. You should run umask
in one of your startup files to make certain that any program you run creates files with your desired permissions. The two reasonable choices are these:
077
This mask is the most restrictive permissions mask because it doesn’t give any other users access to new files and directories. This is often appropriate on a multi-user system where you don’t want other users to look at any of your files. However, when set as the default, it can sometimes lead to problems when your users want to share files but don’t understand how to set permissions correctly. (Inexperienced users have a tendency to set files to a world-writable mode.)
022
This mask gives other users read access to new files and directories. This can be important on a single-user system because many daemons that run as pseudo-users are not be able to see files and directories created with the more restrictive 077
umask.
Now that you know what to put into shell startup files, it’s time to see some specific examples. Surprisingly, one of the most difficult and confusing parts of creating startup files is determining which of several startup files to use. The next sections cover the two most popular Unix shells: bash
and tcsh
.
In bash
, you can choose from the startup filenames .bash_profile, .profile, .bash_login, and .bashrc. Which one is appropriate for your command path, manual page path, prompt, aliases, and permissions mask? The answer is that you should have a .bashrc file accompanied by a .bash_profile symbolic link pointing to .bashrc because there are a few different kinds of bash
shell instance types.
The two main shell instance types are interactive and noninteractive, but of those, only interactive shells are of interest because noninteractive shells (such as those that run shell scripts) usually don’t read any startup files. Interactive shells are the ones that you use to run commands from a terminal, such as the ones you’ve seen in this book, and they can be classified as login or non-login.
Traditionally, a login shell is what you get when you first log in to a system with the terminal using a program such as /bin/login. Logging in remotely with SSH also gives you a login shell. The basic idea is that the login shell is an initial shell. You can tell if a shell is a login shell by running echo $0
; if the first character is a -
, the shell’s a login shell.
When bash
runs as a login shell, it runs /etc/profile. Then it looks for a user’s .bash_profile, .bash_login, and .profile files, running only the first one that it sees.
As strange as it sounds, it’s possible to run a noninteractive shell as a login shell to force it to run startup files. To do so, start the shell with the -l
or --login
option.
A non-login shell is an additional shell that you run after you log in. It’s simply any interactive shell that’s not a login shell. Windowing system terminal programs (xterm
, GNOME Terminal, and so on) start non-login shells unless you specifically ask for a login shell.
Upon starting up as a non-login shell, bash
runs /etc/bash.bashrc and then runs the user’s .bashrc.
The reasoning behind the two different startup filesystems is that in the old days, users logged in through a traditional terminal with a login shell, then started non-login subshells with windowing systems or the screen
program. For the non-login subshells, it was deemed a waste to repeatedly set the user environment and run a bunch of programs that had already been run. With login shells, you could run fancy startup commands in a file such as .bash_profile, leaving only aliases and other “lightweight” things to your .bashrc.
Nowadays, most desktop users log in through a graphical display manager (you’ll learn more about these in the next chapter). Most of these start with one noninteractive login shell in order to preserve the login versus non-login model described above. When they do not, you need to set up your entire environment (path, manual path, and so on) in your .bashrc, or you’ll never see any of your environment in your terminal window shells. However, you also need a .bash_profile if you ever want to log in on the console or remotely, because those login shells don’t ever bother with .bashrc.
In order to satisfy both non-login and login shells, how would you create a .bashrc that can also be used as your .bash_profile? Here’s one very elementary (yet perfectly sufficient) example:
# Command path. PATH=/usr/local/bin:/usr/bin:/bin:/usr/games PATH=$HOME/bin:$PATH # PS1 is the regular prompt. # Substitutions include: # u username h hostname w current directory # ! history number s shell name $ $ if regular user PS1='u$ ' # EDITOR and VISUAL determine the editor that programs such as less # and mail clients invoke when asked to edit a file. EDITOR=vi VISUAL=vi # PAGER is the default text file viewer for programs such as man. PAGER=less # These are some handy options for less. # A different style is LESS=FRX # (F=quit at end, R=show raw characters, X=don't use alt screen) LESS=meiX # You must export environment variables. export PATH EDITOR VISUAL PAGER LESS # By default, give other users read-only access to most new files. umask 022
As described earlier, you can share this .bashrc file with .bash_profile via a symbolic link, or you can make the relationship even clearer by creating .bash_profile as this one-liner:
. $HOME/.bashrc
With a .bashrc matching your .bash_profile, you don’t normally run extra commands for login shells. However, if you want to define different actions for login and non-login shells, you can add the following test to your .bashrc, which checks the shell’s $-
variable for an i
character:
case $- in *i*) # interactive commands go here command --snip-- ;; *) # non-interactive commands go here command --snip- ;; esac
The standard csh
on virtually all Linux systems is tcsh
, an enhanced C shell that popularized features such as command-line editing and multi-mode filename and command completion. Even if you don’t use tcsh
as the default new user shell (we suggest using bash
), you should still provide tcsh
startup files in case your users happen to come across tcsh
.
You don’t have to worry about the difference between login shells and non-login shells in tcsh
. Upon startup, tcsh
looks for a .tcshrc file. Failing this, it looks for the csh
shell’s .cshrc startup file. The reason for this order is that you can use the .tcshrc file for tcsh
extensions that don’t work in csh
. You should probably stick to using the traditional .cshrc instead of .tcshrc; it’s highly unlikely that anyone will ever use your startup files with csh
. And if a user actually does come across csh
on some other system, your .cshrc will work.
Here is sample .cshrc file:
# Command path. setenv PATH /usr/local/bin:/usr/bin:/bin:$HOME/bin # EDITOR and VISUAL determine the editor that programs such as less # and mail clients invoke when asked to edit a file. setenv EDITOR vi setenv VISUAL vi # PAGER is the default text file viewer for programs such as man. setenv PAGER less # These are some handy options for less. setenv LESS meiX # By default, give other users read-only access to most new files. umask 022 # Customize the prompt. # Substitutions include: # %n username %m hostname %/ current directory # %h history number %l current terminal %% % set prompt="%m%% "
The best way to write startup files and choose defaults for new users is to experiment with a new test user on the system. Create the test user with an empty home directory and refrain from copying your own startup files to the test user’s directory. Write the new startup files from scratch.
When you think you have a working setup, log in as the new test user in all possible ways (on the console, remotely, and so on). Make sure that you test as many things as possible, including the windowing system operation and manual pages. When you’re happy with the test user, create a second test user, copying the startup files from the first test user. If everything still works, you now have a new set of startup files that you can distribute to new users.
The following sections outline reasonable defaults for new users.
The default shell for any new user on a Linux system should be bash
because:
Users interact with the same shell that they use to write shell scripts (for example, csh
is a notoriously bad scripting tool—don’t even think about it).
bash
is standard on Linux systems.
bash
uses GNU readline, and therefore its interface is identical to that of many other tools.
bash
gives you fine, easy-to-understand control over I/O redirection and file handles.
However, many seasoned Unix wizards use shells such as csh
and tcsh
simply because they can’t bear to switch. Of course, you can choose any shell you like, but choose bash
if you don’t have any preference, and use bash
as the default shell for any new user on the system. (A user can change his or her shell with the chsh
command to suit individual preferences.)
On a traditional system, the default editor should be vi
or emacs
. These are the only editors virtually guaranteed to exist on nearly any Unix system, which means they’ll cause the least trouble in the long run for a new user. However, Linux distributions often configure nano
to be the default editor, because it’s easier for beginners to use.
As with shell startup files, avoid large default editor startup files. A little set showmatch
in the .exrc startup file never hurt anyone but steer clear of anything that significantly changes the editor’s behavior or appearance, such as the showmode
feature, auto-indentation, and wrap margins.
Avoid these in startup files:
Don’t put any kind of graphical command in a shell startup file.
Don’t set the DISPLAY
environment variable in a shell startup file.
Don’t set the terminal type in a shell startup file.
Don’t skimp on descriptive comments in default startup files.
Don’t run commands in a startup file that print to the standard output.
Never set LD_LIBRARY_PATH
in a shell startup file (see 15.1.4 Shared Libraries).
Because this book deals only with the underlying Linux system, we won’t cover windowing environment startup files. This is a large issue indeed, because the display manager that logs you in to a modern Linux system has its own set of startup files, such as .xsession, .xinitrc, and the endless combinations of GNOME- and KDE-related items.
The windowing choices may seem bewildering, and there is no one common way to start a windowing environment in Linux. The next chapter describes some of the many possibilities. However, when you determine what your system does, you may get a little carried away with the files that relate to your graphical environment. That’s fine, but don’t carry it over to new users. The same tenet of keeping things simple in shell startup files works wonders for GUI startup files, too. In fact, you probably don’t need to change your GUI startup files at all.