Linux:3 The Shell

From HandWiki
Revision as of 20:33, 24 November 2019 by imported>Jworkorg
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

The Shell in Linux

The subject of this chapter is the shell, the program that reads your command input and runs the specified commands. The shell environment is the most fundamental way to interact with the system--you are said to be "in" a shell from the very moment you've successfully logged in to the system.

The `$' character preceding the cursor is called the shell prompt; it tells you that the system is ready and waiting for input. On Debian systems, the default shell prompt also includes the name of the current directory (see section Linux:5_Files_and_Directories). A tilde character (`~') denotes your home directory, which is where you'll find yourself when you log in.

For example, a typical user's shell prompt might look like this:

~ $ _

If your shell prompt shows a number sign (`#') instead of a `$', this means that you're logged in with the superuser, or root, account. Beware: the root account has complete control over the system; one wrong keystroke and you might accidentally break it something awful. You need to have a different user account for yourself, and use that account for your regular use.

Every Linux system has at least one shell program, and most have several. We'll cover bash, which is the standard shell on most Linux systems. (Its name stands for "Bourne again shell"---a pun on the name of Steve Bourne, who was author of the traditional Unix shell, the Bourne shell.)

NOTE: See Info file `bashref.info', node `Top', for more information on using bash.


Keys for Command Line Editing

Before you learned how to run commands by typing them in at the shell prompt. The text you type at a shell prompt is called the command line (it's also called the input line).

The following table describes the keystrokes used for typing command lines.

KEYSTROKES - DESCRIPTION

text - Insert text at the point where the cursor is at; if there is text to the right of the cursor, it is shifted over to the right.

BKSP - Delete the character to the left of the cursor.

DEL - Delete the character the cursor is underneath.

RET - Send the command line to bash for execution (in other words, it runs the command typed at the shell prompt). You don't have to be at the far right end of the command line to type RET; you can type it when the cursor is anywhere on the command line.

C-a - Move the cursor to the beginning of the input line.

C-d - Same as DEL (this is the Emacs equivalent).

C-e - Move the cursor to the end of the input line.

C-k - Kill, or "cut," all text on the input line, from the character the cursor is underneath to the end of the line.

C-l - Clear the terminal screen.

C-u - Kill the entire input line.

C-y - Yank, or "paste," the text that was last killed. Text is inserted at the point where the cursor is.

C-_ - Undo the last thing typed on this command line.

@leftarrow - Move the cursor to the left one character. [GNU INFO BUG: any <> in the preceding line should be the <- arrow key.]

@rightarrow - Move the cursor to the right one character. [GNU INFO BUG: any <> in the preceding line should be the -> arrow key.]

@uparrow and @downarrow - Cycle through the command history. [GNU INFO BUG: any <> in the preceding line should be the up and down arrow keys.]

NOTE: These keyboard commands are the same as those used by the Emacs editor. Many other Emacs keyboard commands also work on the command line. And, for Vi aficionados, it is possible to configure bash to recognize Vi-style bindings instead.

The following sections describe some important features of command line editing, such as quoting special characters and strings, letting the shell complete your typing, re-running commands, and running multiple commands. See Info file `bashref.info', node `Command Line Editing' for more information on bash's command line editing features.

Passing Special Characters to Commands

Some characters are reserved and have special meaning to the shell on their own. Before you can pass one of these characters to a command, you must quote it by enclosing the entire argument in single quotes (`).

For example, here's how to pass `Please Stop!' to a command:

'Please Stop!'

When the argument you want to pass has one or more single quote characters in it, enclose it in double quotes, like so:

"Please Don't Stop!"

To pass special characters as a string, give them as:

$'string'

where string is the string of characters to be passed. Special backslash escape sequences for certain characters are commonly included in a string, as listed in the following table.

ESCAPE SEQUENCE - DESCRIPTION

\a - Alert (rings the system bell).

\b - Backspace.

\e - Escape.

\f - Form feed.

\n - Newline.

\r - Carriage return.

\t - Horizontal tab.

\v - Vertical tab.

\\ - Backslash.

\NNN - Character whose ASCII code is NNN in octal (base 8).

To demonstrate the passing of special character sequences to tool, the following examples will use the figlet tool, which displays the text you give as an argument in a "font" made up of text characters.

  • To pass a backslash character as an argument to figlet, type:

    $ figlet $'\\' RET
  • To pass a form feed character followed by a pilcrow sign character (octal character code 266) to figlet, type:

    $ echo $'\f\266' RET

Letting the Shell Complete What You Type

Completion is where bash does its best to finish your typing. To use it, press TAB on the input line and the shell will complete the word to the left of the cursor to the best of its ability. Completion is one of those things that, once you begin to use it, you will wonder how you ever managed to get by without.

Completion works on both file names and command names, depending on the context of the cursor when you type TAB.

For example, suppose you want to specify, as an argument to the ls command, the `/usr/lib/emacs/20.4/i386-debian-linux-gnu/' directory--that's a lot to type. So instead of typing out the whole directory name, you can type TAB to complete it for you. Notice how our first attempt, typing only the letter `e' in `/e', brings up a series of files--while the second attempt, typing `em', further refines our search:

$ ls /usr/lib/eTAB
elm-me+    emacs      emacsen-common  entity-map    expect5.30
$ ls /usr/lib/emTAB

At this point, the system beeps and the shell completes the word `emacs', since all options in this directory beginning with the letters `em' complete to at least that word. Press /TAB to access this word and go on, and the shell completes the subdirectory `20.4' since that is the only file or directory in the `emacs' subdirectory:

$ ls /usr/lib/emacs/TAB20.4/

Press TAB again to have the shell complete the only subdirectory in `20.4':

$ ls /usr/lib/emacs/20.4/TABi386-debian-linux-gnu/

NOTE: Many applications also support command and/or file name completion; the most famous example of this is the Emacs text editor.

Repeating the Last Command You Typed

Type @uparrow to put the last command you typed back on the input line. You can then type RET to run the command again, or you can edit the command first. [GNU INFO BUG: any <> in the preceding line should be the one of the cursor arrow keys.]

  • To repeat the last command entered, type:

    $ @uparrow RET
    [GNU INFO BUG: any <> in the preceding line should be the one of the cursor arrow keys.]

The @uparrow key moves the last command you typed back to the input line, and RET executes it. [GNU INFO BUG: any <> in the preceding line should be the one of the cursor arrow keys.]

By typing @uparrow more than once, you can go back to earlier commands you've typed; this is a function of your command history.. [GNU INFO BUG: any <> in the preceding line should be the one of the cursor arrow keys.]

Additionally, you can use the bash reverse-incremental search feature, C-r, to search, in reverse, through your command history. You'll find this useful if you remember typing a command line with `foo' in it recently, and you wish to repeat the command without having to retype it. Type C-r followed by the text foo, and the last command you typed containing `foo' appears on the input line.

Like the Emacs command of the same name, this is called an incremental search because it builds the search string in character increments as you type. Typing the string `cat' will first search for (and display) the last input line containing a `c', then `ca', and finally `cat', as you type the individual characters of the search string. Typing C-r again retrieves the next previous command line that has a match for the search string.

  • To put the last command you entered containing the string `grep' back on the input line, type:

    $ C-r
    (reverse-i-search)`': grep
  • To put the third-to-the-last command you entered containing the string grep back on the input line, type:

    $ C-r
    (reverse-i-search)`': grep 
    C-r C-r

When a command is displayed on the input line, type RET to run it. You can also edit the command line as usual.

Running a List of Commands

To run more than one command on the input line, type each command in the order you want them to run, separating each command from the next with a semicolon (`;'). You'll sometimes find this useful when you want to run several non-interactive commands in sequence.

  • To clear the screen and then log out of the system, type:

    $ clear; logout RET
  • To run the hostname command three times, type:

    $ hostname; hostname; hostname RET
    figaro
    figaro
    figaro
    $

Redirecting Input and Output

The shell moves text in designated "streams." The standard output is where the shell streams the text output of commands--the screen on your terminal, by default. The standard input, typically the keyboard, is where you input data for commands. When a command reads the standard input, it usually keeps reading text until you type C-d on a new line by itself.

When a command runs and exits with an error, the error message is usually output to your screen, but as a separate stream called the standard error.

You redirect these streams--to a file, or even another command--with redirection. The following sections describe the shell redirection operators that you can use to redirect standard input and output.

Redirecting Input to a File

To redirect standard input to a file, use the `<' operator. To do so, follow a command with < and the name of the file it should take input from. For example, instead of giving a list of keywords as arguments to apropos, you can redirect standard input to a file containing a list of keywords to use.

  • To redirect standard input for apropos to file `keywords', type:

    $ apropos < keywords RET

Redirecting Output to a File

Use the `>' operator to redirect standard output to a file. To use it, follow a command with > and the name of the file the output should be written to.

  • To redirect standard output of the command apropos shell bash to the file `commands', type:

    $ apropos shell bash > commands RET

If you redirect standard output to an existing file, it will overwrite the file, unless you use the `>>' operator to append the standard output to the contents of the existing file.

  • To append the standard output of apropos shells to an existing file `commands', type:

    $ apropos shells >> commands RET

Redirecting Error Messages to a File

To redirect the standard error stream to a file, use the `>' operator preceded by a `2'. Follow a command with 2> and the name of the file the error stream should be written to.

  • To redirect the standard error of apropos shell bash to the file `command.error', type:

    $ apropos shell bash 2> command.error RET

As with the standard output, use the `>>' operator instead of `>' to append the standard error to the contents of an existing file.

  • To append the standard error of apropos shells to an existing file `command.error', type:

    $ apropos shells 2>> command.error RET

To redirect both standard output and standard error to the same file, use `&>' instead.

  • To redirect the standard output and the standard error of apropos shells to the file `commands', type:

    $ apropos shells &> commands RET

Redirecting Output to Another Command's Input

Piping is when you connect the standard output of one command to the standard input of another. You do this by specifying the two commands in order, separated by a vertical bar character, `|' (sometimes called a "pipe"). Commands built in this fashion are called pipelines.

For example, it's often useful to pipe commands that display a lot of text output to less, a tool for perusing text.

  • To pipe the output of apropos bash shell shells to less, type:

    $ apropos bash shell shells | less RET

This redirects the standard output of the command apropos bash shell shells to the standard input of the command less, which displays it on the screen.

Managing Jobs

The processes you have running in a particular shell are called your jobs. You can have more than one job running from a shell at once, but only one job can be active at the terminal, reading standard input and writing standard output. This job is the foreground job, while any other jobs are said to be running in the background.

The shell assigns each job a unique job number. Use the job number as an argument to specify the job to commands. Do this by giving the job number preceded by a `%' character.

To find the job number of a job you have running, list your jobs. The following sections describe the various commands for managing jobs.

Suspending a Job

Type C-z to suspend or stop the foreground job--useful for when you want to do something else in the shell and return to the current job later. The job stops until you either bring it back to the foreground or make it run in the background.

For example, if you are reading a document in info, typing C-z will suspend the info program and return you to a shell prompt where you can do something else. The shell outputs a line giving the job number (in brackets) of the suspended job, the text `Stopped' to indicate that the job has stopped, and the command line itself, as shown here:

[1]+  Stopped                 info -f cookbook.info

In this example, the job number is 1 and the command that has stopped is `info -f cookbook.info'. The `+' character next to the job number indicates that this is the most recent job.

If you have any stopped jobs when you log out, the shell will tell you this instead of logging you out:

$ logout RET
There are stopped jobs.
$

At this point you can list your jobs, stop any jobs you have running, and then log out.

Putting a Job in the Background

New jobs run in the foreground unless you specify otherwise. To run a job in the background, end the input line with an ampersand (`&'). This is useful for running non-interactive programs that perform a lot of calculations.

  • To run the command apropos shell > shell-commands as a background job, type:

    $ apropos shell > shell-commands & RET
    [1] 6575
    $ 

The shell outputs the job number (in this case, 1) and process ID (in this case, 6575), and then returns to a shell prompt. When the background job finishes, the shell will list the job number, the command, and the text `Done', indicating that the job has completed successfully:

[1]+  Done                    apropos shell >shell-commands

To move a job from the foreground to the background, first suspend it and then type bg (for "background").

  • For example, to start the command apropos shell > shell-commands in the foreground, suspend it, and then specify that it finish in the background, you would type:

    $ apropos shell > shell-commands RET
    C-z
    
    [1]+  Stopped                 apropos shell >shell-commands
    $ bg RET
    [1]+ apropos shell &
    $

If you have suspended multiple jobs, specify the job to be put in the background by giving its job number as an argument.

  • To run job 4 in the background, type:

    $ bg %4 RET

NOTE: Running a job in the background is sometimes called "backgrounding" or "amping off" a job.

Putting a Job in the Foreground

Type fg to move a background job to the foreground. By default, fg works on the most recent background job.

  • To bring the most recent background job to the foreground, type:

    $ fg RET

To move a specific job to the foreground when you have multiple jobs in the background, specify the job number as an option to fg.

  • To bring job 3 to the foreground, type:

    $ fg %3 RET

Listing Your Jobs

To list the jobs running in the current shell, type jobs.

  • To list your jobs, type:

    $ jobs RET
    [1]-  Stopped                 apropos shell >shell-commands
    [2]+  Stopped                 apropos bash >bash-commands
    $

This example shows two jobs---apropos shell > shell-commands and apropos bash > bash-commands. The `+' character next to a job number indicates that it's the most recent job, and the `-' character indicates that it's the job previous to the most recent job. If you have no current jobs, jobs returns nothing.

To list all of the processes you have running on the system, use ps instead of jobs.

Stopping a Job

Typing C-c interrupts the foreground job before it completes, exiting the program.

  • To interrupt cat, a job running in the foreground, type:

    $ cat RET
    C-c RET
    $

Use kill to interrupt ("kill") a background job, specifying the job number as an argument.

  • To kill job number 2, type:

    $ kill %2 RET

Command History

Your command history is the sequential list of commands you have typed, in the current or previous shell sessions. The commands in this history list are called events.

By default, bash remembers the last 500 events, but this number is configurable.

Your command history is stored in a text file in your home directory called `.bash_history'; you can view this file or edit it like you would any other text file.

Two very useful things that having a command history lets you do is to repeat the last command you typed, and (as explained earlier in this chapter) to do an incremental backwards search through your history.

The following sections explain how to view your history and specify events from it on the command line. See Info file `bashref.info', node `Bash History Facilities', for more information on command history.

Viewing Your Command History

Use history to view your command history.

  • To view your command history, type:

    $ history RET
    1 who
    2 apropos shell >shell-commands
    3 apropos bash >bash-commands
    4 history
    $

This command shows the contents of your command history file, listing one command per line prefaced by its event number. Use an event number to specify that event in your history.

If your history is a long one, this list will scroll off the screen, in which case you may want to pipe the output to less in order to peruse it. It's also common to search for a past command by piping the output to grep.

  • To search your history for the text `apropos', type:

    $ history | grep apropos RET
    2 apropos shell >shell-commands
    3 apropos bash >bash-commands
    5 history | grep apropos
    $

This command will show the events from your history containing the text `apropos'. (The last line of output is the command you just typed.)

Specifying a Command from Your History

You can specify a past event from your history on the input line, in order to run it again.

The simplest way to specify a history event is to use the up and down arrow keys at the shell prompt to browse your history. The up arrow key (@uparrow) takes you back through past events, and the down arrow key (@downarrow) moves you forward into recent history. When a history event is on the input line, you can edit it as normal, and type RET to run it as a command; it will then become the newest event in your history. [GNU INFO BUG: any <> in the preceding line should be the one of the cursor arrow keys.]

  • To specify the second-to-the-last command in your history, type:

    $ @uparrow @uparrow
    [GNU INFO BUG: any <> in the preceding line should be the one of the cursor arrow keys.]

To run a history event by its event number, enter an exclamation point (`!', sometimes called "bang") followed by the event number. (Get the event number by viewing your history.

  • To run history event number 1, type:

    $ !1 RET

Recording a Shell Session

Use script to create a typescript, or "capture log," of a shell session--it writes a verbatim copy of your session to a file, including commands you type and their output. The first and last lines of the file show the beginning and ending time and date of the capture session. To stop recording the typescript, type exit at a shell prompt. By default, typescripts are saved to a file called `typescript' in the current directory; specify the file name to use as an argument.

  • To create a typescript of a shell session and save it to the file `log.19990817', type:

    $ script log.19990817 RET
    Script started, output file is log.19990817
    $ hostname RET
    erie
    $ apropos bash > bash.commands RET
    $ exit RET
    exit
    Script done, output file is log.19990817
    $

In this example, the typescript records a shell session consisting of two commands (hostname and apropos) to a file called `log.19990817'. The typescript looks like this:

Script started on Tue May 25 14:21:52 1999
$ hostname
erie
$ apropos bash > bash.commands
$ exit
exit

Script done on Tue May 25 14:22:30 1999

NOTE: It's possible, but usually not desirable, to run script from within another script session. This usually happens when you've forgotten that you are running it, and you run it again inside the current typescript, even multiple times--as a result, you may end up with multiple sessions "nested" inside each other like a set of Russian dolls.

Customizing Your Shell

The following sections describe the most common ways to customize the shell--including changing the text of the shell prompt and creating aliases for other commands. These customizations will apply to the rest of your current shell session, unless you change them again. Eventually, you will want to make them work all the time, like whenever you log in or start a new shell--and how to do this is discussed below.

Changing the Shell Prompt

A shell variable is a symbol that stores a text string, and is referenced by a unique name. bash keeps one special variable, named PS1, for the text of the shell prompt. To change the text of the shell prompt, you need to change the contents of the PS1 variable.

To change a variable's contents, type its name followed by an equal sign (`=') character and the string that should replace the variable's existing contents.

  • To change your shell prompt to `Your wish is my command: ', type:

    $ PS1='Your wish is my command: ' RET
    Your wish is my command: 

Since the replacement text has spaces in it, we've quoted it.

You can put special characters in the prompt variable in order to output special text. For example, the characters `\w' in the value of PS1 will list the current working directory at that place in the shell prompt text.

  • To change your prompt to the default bash prompt--the current working directory followed by a `$' character--type:

    $ PS1='\w $ ' RET
    ~ $

The following table lists some special characters and their text output at the shell prompt.

SPECIAL CHARACTER - TEXT OUTPUT

\a - Inserts a C-g character, which makes the internal speaker beep. (It "rings the system bell"; C-g is sometimes called the bell character.)

\d - The current date.

\h - The hostname of the system.

\n - A newline character.

\t - The current system time, in 24-hour format.

\@ - The current system time, in 12-hour a.m./p.m. format.

\w - The current working directory.

\u - Your username.

\! - The history number of this command.

You can combine any number of these special characters with regular characters when creating a value for PS1.

  • To change the prompt to the current date followed by a space character, the hostname of the system in parenthesis, and a greater-than character, type:

    $ PS1='\d (\h)>' RET
    14 Dec 1999 (ithaca)>

Making a Command Alias

Use alias to assign an alias, a name that represents another command or commands. Aliases are useful for creating short command names for lengthy and frequently used commands.

  • To make an alias of bye for the exit command, type:

    $ alias bye="exit" RET

This command makes `bye' an alias for `exit' in the current shell, so typing bye would then run exit.

You can also include options and arguments in an alias.

  • To make an alias of `ap' for the command apropos shell bash shells, type:

    $ alias ap="apropos shell bash shells" RET

This command makes `ap' an alias for `apropos shell bash shells' in the current shell, so typing ap would run apropos shell bash shells.

Adding to Your Path

To add or remove a directory in your path, use a text editor to change the shell variable `PATH' in the `.bashrc' file in your home directory.

For example, suppose the line that defines the `PATH' variable in your `.bashrc' file looks like this:

PATH="/usr/bin:/bin:/usr/bin/X11:/usr/games"


You can add the directory `/home/nancy/bin' to this path, by editing this line like so:


PATH="/usr/bin:/bin:/usr/bin/X11:/usr/games:/home/nancy/bin"

Customizing Future Shells

There are a number of configuration startup files in your home directory that you can edit to make your configurations permanent. You can also edit these files to specify commands to be run whenever you first log in, log out, or start a new shell. These configuration files are text files that can be edited with any text editor.

When you log in, bash first checks to see if the file `/etc/profile' exists, and if so, it executes the commands in this file. This is a generic, system-wide startup file that is run for all users; only the system administrator can add or delete commands to this file.

Next, bash reads and executes the commands in `.bash_profile', a "hidden" file in your home directory. Thus, to make a command run every time you log in, add the command to this file.

For all new shells after you've logged in (that is, all but the "login shell"), bash reads and executes the commands in the `.bashrc' file in your home directory. Commands in this file run whenever a new shell is started except for the login shell.

There are separate configuration files for login and all other shells so that you can put specific customizations in your `.bash_profile' that only run when you first log in to the system. To avoid having to put commands in both files when you want to run the same ones for all shells, append the following to the end of your `.bash_profile' file:

if [ -f ~/.bashrc ]; then . ~/.bashrc; fi

This makes bash run the `.bashrc' file in your home directory when you log in. In this way, you can put all of your customizations in your `.bashrc' file, and they will be run both at log in and for all subsequent shells. Any customizations before this line in `.bash_profile' run only when you log in.

For example, a simple `.bash_profile' might look like this:

# "Comment" lines in shell scripts begin with a # character.
# They are not executed by bash, but exist so that you may 
# document your file.

# You can insert blank lines in your file to increase readability;
# bash will not mind.

# Generate a welcome message when you log in.
figlet 'Good day, '$USER'!'

# Now run the commands in .bashrc
if [ -f ~/.bashrc ]; then . ~/.bashrc; fi

This `.bash_profile' prints a welcome message with the figlet text font tool, and then runs the commands in the `.bashrc' file.

A simple .bashrc file might look like this:

# Make color directory listings the default.
alias ls="ls --color=auto"

# Make "l" give a verbose directory listing.
alias l="ls -l"

# Set a custom path.
PATH="/usr/local/bin:/usr/bin:/bin:/usr/bin/X11:/usr/games:~/bin:."

# Set a custom shell prompt.
PS1="[\w] $ "

# Make a long history list and history file.
HISTSIZE=20000
HISTFILESIZE=20000

# Export the path and prompt variables for all 
# variables you define.
export HISTSIZE HISTFILESIZE PATH PS1

This `.bashrc' sets a few useful command aliases and uses a custom path and shell prompt whenever a new shell is run; with the preceding `.bash_profile', this `.bashrc' is also run at login.

When you log out, bash reads and executes the commands in the `.bash_logout' file in your home directory, if it exists. To run commands when you log out, put them in this file.

  • To clear the screen every time you log out, your `.bash_logout' would contain the following line:

    clear

This executes the clear command, which clears the screen of the current terminal, such as in the xterm window where you type it, or in a virtual console.

NOTE: Some distributions come with default shell startup files filled with all kinds of interesting stuff. Debian users might want to look at the example startup files in `/usr/share/doc/bash/examples/startup-files'.