4.4 Shell

4.4.1 What is a shell and do I want to use a different one?

A shell is the program that interprets what you type on the command line and decides what to do with it. A shell can also be invoked in a non-interactive way, for example to execute a pre-typed list of commands contained in a text file (a "shell script"). Think of a shell as the equivalent of the DOS "command.com" (command-line interpreter) and the shell script files as the equivalent of the DOS batch files (*.bat). In comparison with their DOS cousins, the Linux shell and scripting are on steroids.

There are several shells available on the Linux system (if you installed them): bash ("Bourne Again" shell), sh (Bourne shell, standard on many UNIX systems), csh (C shell, with a syntax akin to the "c" programming language, available on most UNIX systems), pdksh (public domain Korn shell), tcsh (tiny C shell, often used on small systems), sash (stand-alone shell, could be used when libraries are not available), ash, zsh, and perhaps a couple more.

The default shell on my system (and most probably on yours too) is bash , which is an excellent and standard shell, and I really cannot see a reason why a newbie like myself would want to change it. bash is fully backwards-compatible with the Bourne shell (the most popular shell on UNIX) and incorporates many enhancements and best features from other shells. From a newbie perspective, the different shells are included with Linux for historical reasons and backwards-compatibility of shell scripts that may require a particular shell to run. [Some shells may be useful if you write programs targeted for specialized "embedded" devices, that might run a "tiny" shell.]

You can determine the shell you are running using:

echo $SHELL

If you wanted to try another shell, type, for example:

tcsh

which will start the tiny c shell. When done, type

exit

which will return you to the previous shell (using exit on your first shell will log you out). You can find out how many shells you stacked on each other by displaying the "shell level" environmental variable:

echo $SHLVL

In the above command, the "$" means "expand the value of a shell environment variable", "SHLVL" is the variable name, and "echo" is a command that prints things.

The shell for each user is specified as the last field in the password file /etc/passwd . If you really wanted to change it, edit (as root) this file and replace the "/bin/bash" with the shell of your choice.

4.4.2 How do I customize my shell prompt?

On my machine, the prompt may look like this:

[stan@marie stan]$ _

Here "stan" is my login name, "marie" is the name of the computer, the second "stan" is the name of my current working directory, and "_" represents the cursor.

The prompt is set by the environmental variable called PS1. To display the current setting, I can use:

echo $PS1

The system-wide setting of the prompt (for all users on the system) is in the file /etc/bashrc which on my system contains such a line:

PS1="[\u@\h \W]\$ "

To customize the prompt, I can edit the file /etc/bashrc (as root) and insert almost any text inside the quotation marks. Here is the meaning of some special codes I may also choose to use:

\u - username of the current user (= $LOGNAME),

\h - the name of the computer running the shell (hostname),

\H - entire hostname,

\W - the base of the name of the current working directory,

\w - the full name of the current working directory,

\$ - display "$" for normal users and "#" for the root,

\! - history number of the current command,

\# - number of the current command (as executed in the current shell),

\d - current date,

\t - current time (24-hr),

\T - current time (12-hr) - bash 2.0 only,

\@ - current time (AM/PM format) - bash 2.0 only,

\s - name of the shell,

\a - sound alarm (beep),

\j - number of jobs the user has,

\n - new line,

\\ - backslash,

\[ - begin a sequence of non-printable characters,

\] - end a sequence of non-printable characters,

\nnn - the ASCII character corresponding to the octal number nnn.

$(date) - output from the date command (or any other command for that matter),

Here is an example on how to add colour. See the next chapter for details about colour:

PS1="\[\033[1;32m\][\u@\h \W]\$\[\033[0m\] "

There is also the second-level prompt, set by a variable called PS2. The shell uses the second level prompt when it expects additional input, and on my system the secondary prompt is "> ". I don't worry too much about PS2, but if I did I could set it the same way as PS1. There are even PS3 and PS4, but these are rarely seen.

Thank you from our readers like sqrt_-1@ezrs.com who wrote in with the following note:

When I first started playing with the ANSI escape sequences, I had problems whenever the line I was typing in wrapped to the next line. The cursor would not move to the next line, overwriting the prompt; the line would wrap but overwrite itself below the prompt; etc. The I saw an extremely long (3 lines!) prompt definition, and it worked better that mine. It's because of \[\033[0m\] sprinkled throughout. The three line prompt is from www.dotfiles.com.”

Monstrous 3 line prompt by Robert:

export PS1='\[\033[0m\]\[\033[0;31m\].:\[\033[0m\]\[\033[1;30m\][\[\033[0m\]\[\033[0;28m\]Managing \033[1;31m\]\j\[\033[0m\]\[\033[1;30m\]/\[\033[0m\]\[\033[1;31m\]$(ps ax | wc -l | tr -d '\'' '\'')\[\033[0m\]\[\033[1;30m\] \[\033[0m\]\[\033[0;28m\]jobs.\[\033[0m\]\[\033[1;30m\]] [\[\033[0m\]\[\033[0;28m\]CPU Load: \[\033[0m\]\[\033[1;31m\]$(temp=$(cat /proc/loadavg) && echo ${temp%% *}) \[\033[0m\]\[\033[0;28m\]Uptime: \[\033[0m\]\[\033[1;31m\]$(temp=$(cat /proc/uptime) && upSec=${temp%%.*} ; let secs=$((${upSec}%60)) ; let mins=$((${upSec}/60%60)) ; let hours=$((${upSec}/3600%24)) ; let days=$((${upSec}/86400)) ; if [ ${days} -ne 0 ]; then echo -n ${days}d; fi ; echo -n ${hours}h${mins}m)\[\033[0m\]\[\033[1;30m\]]\[\033[0m\]\[\033[0;31m\]:.\n\[\033[0m\]\[\033[0;31m\].:\[\033[0m\]\[\033[1;30m\][\[\033[0m\]\[\033[1;31m\]$(ls -l | grep "^-" | wc -l | tr -d " ") \[\033[0m\]\[\033[0;28m\]files using \[\033[0m\]\[\033[1;31m\]$(ls --si -s | head -1 | awk '\''{print $2}'\'')\[\033[0m\]\[\033[1;30m\]] [\[\033[0m\]\[\033[1;31m\]\u\[\033[0m\]\[\033[0;31m\]@\[\033[0m\]\[\033[1;31m\]\h \[\033[0m\]\[\033[1;34m\]\w\[\033[0m\]\[\033[1;30m\]]\[\033[0m\]\[\033[0;31m\]:.\n\[\033[0m\]\[\033[0;31m\].:\[\033[0m\]\[\033[1;30m\][\[\033[0m\]\[\033[1;31m\]\t\[\033[0m\]\[\033[1;30m\]]\[\033[0m\]\[\033[0;31m\]:. \[\033[0m\]\[\033[1;37m\]\$ \[\033[0m\]'


4.4.3 Colour on text terminal

Colour on the text terminal can be produced using the "ANSI escape sequences". For example:

echo -e "\033[44;37;5m ME \033[0m COOL"

The above sets the background to blue, foreground white, blinking video, and prints " ME ", then resets the terminal back to defaults and prints " COOL". The "-e" is an option specific to the echo command--it enables the interpretations of the special characters. The "\033[" introduces the escape sequence. The "m" means "set attribute" and thus finishes the sequence. The actual codes in the example above are "44;37;5" and "0".

Change the "44;37;5" to produce different colour combinations--the number/order of codes do not matter. The codes to choose from are listed below:

Code Action/Color

---------------------------

0 reset all attributes to their defaults

1 set bold

2 set half-bright (simulated with color on a color display)

4 set underscore (simulated with color on a color display)

5 set blink

7 set reverse video

22 set normal intensity

24 underline off

25 blink off

27 reverse video off

30 set black foreground

31 set red foreground

32 set green foreground

33 set brown foreground

34 set blue foreground

35 set magenta foreground

36 set cyan foreground

37 set white foreground

38 set underscore on, set default foreground color

39 set underscore off, set default foreground color

40 set black background

41 set red background

42 set green background

43 set brown background

44 set blue background

45 set magenta background

46 set cyan background

47 set white background

49 set default background color

Other interesting codes:

\033[2J clear screen

\033[0q clear all keyboard LEDs (won't work from Xterm)

\033[1q set "Scroll Lock" LED

\033[2q set "Num Lock" LED

\033[3q set Caps Lock LED

\033[15;40H move the cursor to line 15, column 40

\007 bell (beep)

LEDs (="Light Emitting Diods) are the lights on the keyboard which indicate if <CapsLock>, <NumLock> and <ScrollLock> are engaged.

See man console_codes for more.

4.4.4 How do I print symbols on the console, in a text mode application, and in X?

The procedure described here may give me fast access to the PC extended character set (codes 128-255) and is quite portable in the PC world: it works in MS Windows, DOS (if you have an ANSI driver installed), and inside any text mode Linux application (including right on the shell command line). I found it was worth my time to memorize the codes for the few characters I tend to use the most.

It works like this. Make sure that <NumLock> is on. Then press <Alt> and hold it. While <Alt> is pressed, key in on the numeric keypad these four digits: 0181. Now release <Alt> and the Greek letter mu "µ" appears. I find quite useful the following characters from the PC character set encoding: 176 ° (degree), 177 ± (plus minus), 178 ² (square), 179 ³ (power 3), 181 µ (Greek mu), 0183 · (multiplication sign), 232 è (French accent agrave), 233 é (French accent aigu) 228 ä (German a-umlaut), 243 ó (Polish u-zamkniete), 248 ø (Scandinavian o-bar) 252 ü (German u-umlaut). Some other characters are also possible, here is the full listing:

128 ? 147 ? 166 ¦ 185 ¹ 204 Ì 223 ß 242 ò

129 ? 148 ? 167 § 186 º 205 Í 224 à 243 ó

130 , 149 * 168 ¨ 187 » 206 Î 225 á 244 ô

131 f 150 - 169 © 188 ¼ 207 Ï 226 â 245 õ

132 ? 151 - 170 ª 189 ½ 208 Ð 227 ã 246 ö

133 ? 152 ~ 171 « 190 ¾ 209 Ñ 228 ä 247 ÷

134 ? 153 ? 172 ¬ 191 ¿ 210 Ò 229 å 248 ø

135 ? 154 s 173 ­ 192 À 211 Ó 230 æ 249 ù

136 ^ 155 > 174 ® 193 Á 212 Ô 231 ç 250 ú

137 ? 156 ? 175 ¯ 194 Â 213 Õ 232 è 251 û

138 S 157 ? 176 ° 195 Ã 214 Ö 233 é 252 ü

139 < 158 ? 177 ± 196 Ä 215 × 234 ê 253 ý

140 ? 159 Y 178 ² 197 Å 216 Ø 235 ë 254 þ

141 ? 160 179 ³ 198 Æ 217 Ù 236 ì 255 ÿ

142 ? 161 ¡ 180 ´ 199 Ç 218 Ú 237 í

143 ? 162 ¢ 181 µ 200 È 219 Û 238 î

144 ? 163 £ 182 ¶ 201 É 220 Ü 239 ï

145 ? 164 ¤ 183 · 202 Ê 221 Ý 240 ð

146 ? 165 ¥ 184 ¸ 203 Ë 222 Þ 241 ñ

Now, if I really want to, I can have a file with a name µm·°C±b³. MS Windows, DOS ANSI, and Unicode differ slightly in some of the above characters, but the useful "core" remains the same. See http://www.hclrss.demon.co.uk/demos/ansi.html if you want to know the details of the differences. Linux uses the Unicode standard.

Under X, the above key combinations will not work. But I may use:

kcharselect&

or

gcharmap&

to select a Unicode character and copy it into my application. Not all Unicode characters are available yet, but many are. From Unicode pages other than page 0, the characters may display or not, depending on your application and the availability of the glyph in your font. For example, I can surely use the following characters in most KDE applications (if they display on your browser, depends on your browser AND the availability of a suitable Unicode font):

Greek (Unicode page 3, char 913 to 969): ???????????? ????????????????? ????????????????? ???????????

Russian: (Unicode page 4, chars 1040 to 1103): ????????? ????????????? ????????????? ????????????? ?????????????? ??

and many others. You can find common Unicode codes (numerical) and their html symbolic ("character entity") references at http://www.hclrss.demon.co.uk/demos/ent4_frame.html.

4.4.5 How do I write a simple shell script?

Create a text (ASCII) file which will contain the shell script. For example, I would use the pico editor to write a script that runs the program tar with all the parameters usually necessary to uncompress tarballs downloaded from the Internet (I never seem to remember the tar options). I decided to call my script "untar":

pico untar

Since the file "untar" did not exist in my current directory, it was created by the pico text editor. Now, I type in the content of my script:

#!/bin/bash

echo this is the script file $0

echo untarring the file $1

# this calls tar with options -xvzf (extract,

# verbose, filter through gzip, input filename)

tar -xvzf $1

I save the file with <Ctrl>o and exit with <Ctrl>x


The first line of the script, starting with "#!" (called pound-bang), is special--it tells the shell what program should be used to interpret my script. In this example, the script is to be interpreted by the bash shell /bin/bash . The first line must start with #! or the script will never run (the file will be interpreted as just a text file). Other lines starting with # are comments for the author (readers, users) of the shell and are totally ignored by the computer.

The $0, $1, $2 ... in my script are the parameters passed to my script. For example, if I ran a script called "myscript" with seven parameters like this:

myscript a b c d e f g

then $0 would be seen inside "myscript" as having the value "myscript", $1 would have the value "a", $2 would be "b", $3 would be "c", etc.

On the second and third line of my example script, the command echo prints on the screen everything that follows on the same line, expanding $0 and $1 to the values of the parameters passed to the script. The fourth and fifth line contains a comment I wrote to myself to remind myself what I was trying to achieve, just in case I ever had to modify my script. The last line performs the actual work.

Once the script is written, I make the file executable to the file owner ("u"=user):

chmod u+x untar

and my script is ready to run like this:

./untar my_tar.tar.gz

Linux scripting is definitely rich, flexible, powerful and can be complex. However, it does not require special knowledge to write simple scripts for automation of common tasks. You just put together a group of often used commands, one by one, into a file. I use scripting because I am too lazy to type the same groups of commands over and over again.

A really simple sequence of commands can also be typed into a text file and passed to shell for straight execution using:

source my_file

[No need for the initial "pound bang" or executable permission.]

4.4.6 Meaning of quotes

Normally, these characters are special to the shell:

\ ' " ` < > [ ] ? | ; # $ ^ & * ( ) = <Space> <Tab> <Newline>

There are four different types of quotes: backslash (\), single quotes (apostrophes, '), double quotes (quotation marks, "), and backquotes (`).

The backslash \ means: disable the special meaning of the subsequent character.

Quoting with '' (two apostrophes) means: quote exactly, disabling any special characters inside the quotes.

Quoting with "" means: disable the special characters inside the quotes except for $ ` \

The pair `` (two backquotes) means: do a command substitution inside the backquotes first. So what is inside the backquotes is executed by the shell first, and then the output is passed to the command outside the quotes. The same can also be acomplished with $(command) which nests better than backquotes.

Examples. I can create a funny directory called "*" by either \ quoting or '' quoting:

mkdir \*

mkdir '*'

This hides the special meaning of the "*" from the shell (without the quote it would mean "all files in the current directory").

4.4.7 Input/output redirection

There are three important input-output streams: standard input ("stdin"), standard output ("stdout"), and standard error output ("stderr"). They all default to the console ("console" means the keyboard for the input and the screen for the output), but they can be redirected.

To redirect the standard output I use ">". For example:

dir my_dir > filelisting.txt

will redirect the standard output of the dir command into the textfile filelisting.txt and nothing should appear on my screen. The file can be subsequently edited (e.g. with pico filelisting.txt) or embedded into a document.

To redirect the standard error, I need to use the construct "2>". For example:

dir my_dir 2> errorlisting.txt

The above will send the normal output onto the screen and nothing to the file unless dir produces an error. On error, nothing may go to my screen, and the file errorlisting.txt will contain the error message, which might be something like:

dir: my_dir: Permission denied

Finally, I can redirect both standard output and standard error to a file using:

dir my_dir > file_and_error_listing.txt 2>&1

which first redirects the standard output to a textfile, and then redirects the standard error to the same location as the standard output. A bit twisted, how it works, but it works.

In the examples above, if the file (to which to redirect) already existed, it will be overwritten. To append to an existing file, I use ">>" as in these examples:

dir my_dir >> filelisting.txt

dir my_dir 2>> errorlisting.txt

dir my_file >>file_and_error_listing.txt 2>&1

If you are puzzled by the "2>" symbol, here, briefly, is how to rationalize it. The standard streams have standard descriptors. "0" is standard input, "1" standard output and "2" is standard error.

dir my_dir > file.txt

is short for

dir my_dir 1> file.txt

and therefore the example below redirects the standard error:

dir my_dir 2> file.txt

One can also use the symbol "|" to send ("pipe") the output from one command as input for another command. In this popular example, the output from dir is piped to more (more pauses the display after each screen-full):

dir | more

One can also split the output so it goes both to a file and the screen using "tee":

dir | tee filelisting.txt

It is called "tee" by the analogy to the "T"-letter-shape fitting that pipefitters use, and which divides flow.

This section so far dealt with redirecting standard output. Redirecting standard input is not nearly as useful as redirecting the output, but it can be done using a construct like this:

cat < my_file

There is also something called in-line redirection of the standard output, realized with "<<". Forget about it, seems of no use to me. Yet, here is an example if you really ever needed it (here, the ">" stands for the secondary prompt):

cat << my_marker

> my_line_from_the_keyboard

> another line_from_the_keyboard

> my_marker [the marker of my choice ends the in-line redirection].

Apart from redirection to regular files and "filters" (as shown in the examples above), one can redirect to/from devices and other special files. Some examples follow.

An example of redirection to a device file. The following command displays the listing of files on the fourth text terminal:

dir > /dev/tty4

An example of redirection to a special "FIFO" file. This command sends the message "you are lucky" to the lucky ICQ user UIN 77777777 (assuming you are connected to the icq server with your licq program):

echo message 77777777 "you are lucky" > ~/.licq/licq_fifo

The above works because the file "licq_fifo" in your licq directory is a special "fifo" (first-in-first-out) queue file. How could the above ever be more useful than sending a message using the pretty licq GUI front-end? For example, you could write a short script to impress fellow icq users with multiple (identitcal) messages:

#!/bin/bash

echo Messaging UIN: $1 Message: $2 Times: $3

# The next command puts puts your licq in the status "on-line, invisible".

echo 'status *online' > ~/.licq/licq_fifo

c=0

while [ $c -le $3]

do

echo message $1 $2 > ~/.licq/licq_fifo

c=`expr $c + 1`

echo $c " "

done

echo 'status offline' > ~/.licq/licq_fifo

echo "all done"

The above example may give you an idea how one can use licq for automation, owing to the smart licq communication model (the fifo file) and simple file redirection.

4.4.8 Shell special characters (metacharacters)

Normally, these characters have special meaning to the shell:

\ ' " ` < > | ; <Space> <Tab> <Newline> ( ) [ ] ? # $ ^ & * =

Here is the meaning of some of them:

me=blahblah

assigns the value "blahblah" to the variable called "me". I can print the name of the variable using:

echo $me

$0 name of the shell or the shell script being executed.

$# number of the positional parameters to the command

$1 the value of the first positional parameter passed to the command. $2 is the second positional parameter passed to the command. etc. up to $9.

$* expands to all positional parameters passed to the command

$@ expands to all positional parameters passed to the command, but individually quoted when "$@" is used.

See man bash if you really need more.




UNIXguide.net
Suggest a Site