A [Li|U]nix shell is the command-line interface between the user and the system. It is used to perform some action, specifically, typing commands and displaying output, requested by the user.
Bash is known as the Bourne-again shell, written by Brian Fox, and is a play on the name of the previously named Bourne shell (/bin/sh) written by Steve Bourne. [1]
Over time, as one progresses with using the shell, it will become necessary to execute
commands that may contain many arguments or have output piped to other commands. Beyond
simple commands such as cat
and ls
, it can be tedious should one need to re-type,
or, in most cases, edit, a given command. Luckily, bash
provides a facility to make
this scenario easier: the command-line editing mode.
The command-line editing mode emulates the movement functions of two common text editors,
emacs
and vi
. In the case of the shell, the cursor's movement is being controlled.
.. todo:: Tighten up the above sentence. It's wordy and doesn't seem to make the point I want it to make.
By default, bash
operates in emacs
mode.
The following commands are very common while using the emacs
mode.
Ctrl-b
: Move backward by one characterCtrl-f
: Move forward by one characterCtrl-a
: Move to the beginning of the lineCtrl-e
: Move to the end of the lineCtrl-k
: Delete from the cursor forwardCtrl-u
: Delete from the cursor backwardCtrl-r
: Search the command history
The following commands are very common while using the vi
mode.
h
: Move backward by one characterl
: Move forward by one characterw
: Move forward by one word0
: Move to the beginning of the line$
: Move to the end of the lined$
: Delete from the cursor to the end of the lined0
: Delete from the cursor the beginning of the line:history s
: Search the command history
One can manually set the desired mode using the below commands.
emacs
set -o emacs
vi
set -o vi
See :doc:`text_editing_101` for details on appropriate edit commands to use on the command line.
Environment variables are used to define values for often-used attributes of a
user's shell. In total, these variables define the user's environment. Some
environment variables provide a simple value describing some basic attribute,
such the user's current directory ($PWD
). Others define the behavior of a
command, such as whether or not the history
command should log repeated
commands individually or log the repeated command once ($HISTCONTROL
).
The most common, or most recognized, environment variable is the $PATH
variable. It defines the set of directories that the shell can search to find a
command. Without an explicit path provided when calling a command (i.e. /bin/ps
),
the shell will search the directories listed in the $PATH
variable until it
finds the command. If the command is not found in any of the defined directories
in $PATH
, the shell will produce an error explaining as much.
$ foobar -V -bash: foobar: command not found
To view the contents of the $PATH
variable, use echo
to print the variable's value:
$ echo $PATH /usr/local/sbin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin
The order of the directories in the $PATH
variable, from left to right, is
important; when searching directories for a command, the shell will stop looking
after it finds its first match.
In other words, using our example $PATH
variable above, if there is a
version of ps
that exists in /usr/local/bin
that is preferred (by the sysadmin)
over the version that exists in /bin
, the shell will still execute /bin/ps
due to the precedence of the directories defined in the $PATH
variable.
To list all of the shell's environment variables, use the env
command:
$ env HOSTNAME=foobar SHELL=/bin/bash TERM=xterm HISTSIZE=1000 USER=root PATH=/usr/local/sbin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin:/usr/local/bin MAIL=/var/spool/mail/root PWD=/root/curriculum PS1=[\[\e[33;1m\]\t \[\e[31;1m\]\u\[\e[0m\]@\[\e[31;1m\]\h\[\e[0m\] \W\[\e[0m\]]# HISTCONTROL=ignoredups SHLVL=1 SUDO_COMMAND=/bin/bash HOME=/root HISTTIMEFORMAT=[%Y-%m-%d %H:%M:%S] OLDPWD=/tmp
Shell profiles are used to define a user's environment. In cases where an environment variable needs to be set or a script needs to be run at login, a profile can be used to ensure this happens consistently and automatically. Anything that can be run in a standalone shell script can be placed in a profile.
There are two types of profiles:
- Global profile (
/etc/profile
) - User profile (
~/.bash_profile
)
This is the global profile. Any environment variable set in this file applies to all users. Any script called from this file is executed for all users.
This is the user profile. Any environment variable set in this file applies to the user only. Any script called from this file is executed for the user only.
NOTE: It is possible to override settings from /etc/profile
via ~/.bash_profile
as ~/.bash_profile
is executed after /etc/profile
.
Certain variables exist that provide useful information about what is happening in the environment. For example, it may be necessary to know the ID of a running process or the exit status of an executed command.
To determine the process ID (PID) of the current shell, first run ps
to find the PID, then run echo $$
to confirm the PID.
$ ps -efl | grep bash 502 20440 20439 0 10:25PM ttys001 0:00.01 -bash 4006 31 0 2433436 1228 - S 0 502 20447 20440 0 10:29PM ttys001 0:00.00 grep bash 4006 31 0 2432768 620 - R+ 0 $ echo $$ 20440
Occasionally, commands will need to be executed in the background (via the &
operator). The PID of that process
can be found using the $!
variable. For example, call sleep
for 30 seconds and place it in the background.
Then echo $!
to see the PID. Alternatively, call ps
to confirm the PID.
$ sleep 30 & [1] 20450 $ echo $! 20450 $ ps -efl | grep sleep 502 20450 20440 0 10:33PM ttys001 0:00.00 sleep 30 4006 31 0 2432748 496 - S 0
When a command is executed, it always has an exit status. That status defines whether or not the command was successful. For success, the exit status is 0. Non-zero values denote failure. Many commands provide multiple exit codes to help define what the reason for failure was. This helps the user troubleshoot any problems.
As an example, try to list a known file within a user's home directory, then list a file that is known not to exist.
After each command, execute echo $?
to see the exit status.
$ ls .bash_profile .bash_profile $ echo $? 0 $ ls foobar ls: foobar: No such file or directory $ echo $? 1
The history is a handy facility within bash
; it stores all of the commands that the user has executed.
To see the history, simply type history
and all of the stored commands will be displayed to the terminal.
Similarily, run cat ~/.bash_history
to see all stored commands.
A benefit of storing command history is that the commands can be easily recalled. To execute the last command,
type !!
:
$ ls file1 file2 dir1 $ !! ls file1 file2 dir1
Note that the last command is echoed just above the output of that command.
To execute the nth command in history, run !n
where n
is the line number of the command as found in the
output of history
:
$ history | less 1 ls -la 2 ls -F 3 pwd $ !2 ls -F file1 file2 dir1/
Finally, one can search the history by typing Ctrl-r
followed by a string to match a command:
$ (reverse-i-search)`ls': ls -F
To execute the command (if a match is found), simply type Enter.
From time to time, it may be necessary to manage commands running in the background. These are typically referred to as jobs.
A command can be placed in the background via the &
operator. Use the jobs
command to see the job in the background.
To bring it back to the foreground, run fg
:
[23:24:22 ~]$ sleep 30 & [1] 20969 [23:24:26 ~]$ jobs [1]+ Running sleep 30 & [23:24:29 ~]$ fg sleep 30 [23:24:56 ~]$
While in the foreground, the job can be suspended via Ctrl-z
and sent to the background once more using bg
:
[23:24:56 ~]$ sleep 30 & [1] 21078 [23:28:25 ~]$ jobs [1]+ Running sleep 30 & [23:28:27 ~]$ fg sleep 30 ^Z [1]+ Stopped sleep 30 [23:28:33 ~]$ bg [1]+ sleep 30 & [23:28:37 ~]$ jobs [1]+ Running sleep 30 & [23:29:39 ~ ]$ jobs [1]+ Done sleep 30
It is possible to have multiple jobs running in the background at the same time. Use the jobs
command to track them
via their job ID, noted between the square brackets after sending a job to the background. Knowing the job ID is helpful in
the event that the job needs to be pulled into the foreground (via fg
) or if the job needs to be killed:
[23:36:01 ~]$ sleep 120 & [1] 21086 [23:36:16 ~]$ sleep 240 & [2] 21087 [23:36:20 ~]$ jobs [1]- Running sleep 120 & [2]+ Running sleep 240 & [23:36:21 ~]$ fg %1 sleep 120 ^C [23:36:33 ~]$ jobs [2]+ Running sleep 240 & [23:36:35 ~]$ kill %2 [23:36:39 ~]$ jobs [2]+ Terminated: 15 sleep 240
NOTE: When manipulating jobs with any command, the jobs are described by their ID using the %n
notation
where n
is the job ID.
For information on ensuring running jobs continue, even when terminal connectivity is lost, see the sections on :ref:`gnu-screen` and :ref:`tmux`.
Footnotes
[1] | C Programming by Al Stevens, Dr. Dobb's Journal, July 1, 2001 |