A shell is a program which stands between the user and the operating system. Its main purpose is to load and run other programs when requested. There are several shells available for Unix/Linux:
sh. This is the “lowest common denominator”;
shell scripts should be written to be compatible with sh
for maximum portability. sh is very obsolete, and as
noted below, few Linux distributions offer it any more.
Bash is
backwards compatible to sh but provides many more
features. bash is the default shell on most Unix and
Linux systems. In some versions of Linux (but not Ubuntu),
sh is an alias for bash. Part of the GNU
project.
bash, but with even more
bells and whistles. Called zsh.
ash, was
designed to be a lightweight replacement for the Bourne shell but with
some modern features. It is very small and fast, and is used to (a)
run scripts more quickly than possible with bash or
zsh, and (b) as the default on mini-systems. On some
systems it is called dash, the Debian Ash Shell. In
Ubuntu, sh is an alias for dash.
Here are the size comparisons:
-rwxr-xr-x 1 root root 818232 2010-04-18 20:51 bash
-rwxr-xr-x 1 root root 550804 2010-04-18 21:00 zsh
-rwxr-xr-x 1 root root 83888 2010-04-01 14:22 dash
csh; the improved version used today is
tcsh.
Ksh is
not often seen on Linux because the code was originally proprietary,
but a public domain version called pdksh now exists.
The modern shells, bash and zsh, basically
started with sh and then added features of both
tcsh and ksh as the authors saw fit, without
breaking Bourne compatibility. (Similarly, Unix began with the Bell
version (SysV). Berkeley Unix (BSD) made improvements and changes,
and Linus Torvalds picked and chose what he liked the best to create
Linux. In turn, some Linux features have fed back into BSD to create
Apple’s OS-X.)
With only one (noted) exception, everything in the rest of this
presentation applies to both bash and zsh.
Most of the examples work with ash, too.
At minimum, bash or another shell provides a
command prompt where a user types his or her
intentions in the form of command lines. For
example:
> cp -a file1 file2
>
where > is the prompt, cp is the
command, -a is an option, and
file1 and file2 are arguments.
The“command” can be external—a seperate program file to be run, internal—built into the shell for speed, a script— a series of commands stored in a file and executed by the shell as if typed in at the terminal, or a function—a script provided by the user as a part of the shell for speed. Any of these can be called via an easy-to-remember alias created by the user.
When necessary, a script can indicate on its first line which shell is
to be used to execute the rest. If there is no explicit shell given,
sh (or whatever is aliased to sh) is
assumed. Here’s a simple example of a script:
> cat bin/unzipall
#!/bin/bash
# Loop to unzip all files given on the command line
for i in $@
do
unzip $i
echo $i
done
This script could have been typed in as a single line at the command prompt, using semicolons to separate the parts:
>for i in $@; do unzip $i; echo $i; done
The main advantage of the shell script is that it can be reused at
will.
The two most important features of the shell’s language are loops, shown above, and tests, used to select alternatives. Here’s an example of a script with a test:
>cat bin/wdiff
#!/bin/bash
cd ~/words
if [[ -d /dell/words/ ]]
then diff -q --to-file=/dell/words/ ww.html nono.html
else echo "DELL not mounted"
fi
> myvar=something
The value of a variable is used when the name is prefixed
with a dollar sign:
> echo myvar [prints myvar]
> echo $myvar [prints something]
Within double quotes, values are substituted for shell variables. Within single quotes, they are not:
> echo "This is $myvar." [prints This is something.]
> echo ’This is $myvar.’ [prints This is $myvar.]
> mycommand one two three
has three arguments, but
> mycommand "one two" three
has two. Either single or double quotes can be used for this purpose.
Another use is to prevent the shell from seeing characters that have special meaning. This sometimes works with double quotes and sometimes doesn’t— when in doubt, use single quotes, which always leave everything inside quotes “as is”. If quotes are not used, then special characters have to be “escaped” with a backslash to give them their actual meaning. For example:
> echo this; [not this] ***will not work
> echo ’this; [not this]’ ***ok
> echo this\;\ \ \[not this\] ***ok
> echo this is an asterisk * and this isn’t ***will not work
Quotes are often needed when a file name contains a space:
> cp myfile file two
> cp myfile file\ two
> cp myfile "file two"
> cd ’Program Files"
Shell variables can be manipulated in various ways to get what you want. Here are a few examples:
> myfile="/home/dierdorf/myfile.ext"
> echo ${myfile} prints /home/dierdorf/myfile.ext
> echo ${myfile#*/} prints home/dierdorf/myfile.ext
> echo ${myfile##*/} prints myfile.ext
> echo ${myfile%.*} prints /home/dierdorf/myfile
> echo echo ${myfile%%e*} prints /hom
> echo ${${myfile%%.*}##*/} prints myfile
> echo ${myfile/my/your} prints /home/dierdorf/yourfile.ext
> echo ${myfile//e/a} prints /homa/diardorf/myfila.axt
In the expression
part1 && part2
part2 is executed only if
part1 is true; otherwise it is
skipped. (Logical AND)
part1 || part2
causes part2 to be executed only if
part1 is false. (Logical
OR)
! part1
is true if part1 is false, and vice versa. (Logical
NOT)
Anything inside [[...]] is evaluated to be true or
false. For example:
> cat bin/unhtmlall
#! /bin/bash
echo "================="
for i in "$@"
do
[[ -e "$i" ]] || continue
cat "$i" | w3m -T text/html -dump >"${i%.htm*}.txt"
dd="${i}_files"
[[ -d "$dd" ]] && rm -r $dd
dd="${i%.htm*}_files"
[[ -d "$dd" ]] && rm -r $dd
echo "$i --> ${i%.htm*}.txt"
done
rename s/\.txt\././ *.txt
echo "=================="
read -p "rm all converted files (yN) ==> " ANS
[[ $ANS == "y" ]] && rm "$@"
In addition to the fundamental job of running other programs on demand, modern shells all provide several other features for the user.
emacs-style or vi-style, with all the navigation and editing keys they imply.
> rm *.bak
instead of having to write
>rm one.bak two.bak three.bak ...
Note that expansion is done by the shell before executing the command,
so in this example rm “sees” the long list.
Both bash and zsh offer many more complex
ways of selecting files, though. For example, this zsh
example will list all files:
*.bak,
I,
>ls **/*.bak~I*(*m-30Lk+100)
>longprogram &
to start longprogram in the background —that is, you
will immediately get a command prompt back and can run another job in
parallel with it. Commands are available to bring it back into the
foreground (that is, so it owns the keyboard and mouse again), list all jobs
currently running, kill a job that should not be running, and so on.
Here’s a batch file example:
#!/bin/bash
(job1) & (job2) & (job3) & (job4) &
wait
job5
job1 through job4 will be run in parallel.
(If you have a CPU with at least four cores, they truly will all be
running at the same time, even if they are CPU-intensive.)
job5 will be run after all of 1 through 4 have completed.
Most people customize their shell, selecting the prompt style they
like, adding aliases, and setting options to change the default
behavior. These customizations are normally in the file
.bashrc (or .zshrc) in the user’s home
directory. The number of settings is mind-boggling, and much too
complex to go into here. If you want to change things, here are some
sources:
bash, but what it does have is
accurate. (As usual, changes add new features, not change old ones.)
bash, not zsh.