The Console, Konsole, XTerm, etc


When you start the unix console on the Mac or Linux, that really is just a window which knows how to display text in a fixed width font. It knows nothing about commands or anything like that.
However, it knows that it must immediately start another process called a shell, forward your keystrokes to that program and display any output the shell sends back. It also knows that once that shell finishes, so should it (usually anyway).

Shells


The Shell is the thing that directly executes your commands. Common examples include tcsh, bash, zsh, ksh, ash,.... However, there are two main styles: Korn Shells (bash is the main one) and C Shells (tcsh is the main one). Windows shells are crap and do very little bar execute commands. Good unix shells are full programming environments.
Shells read your commands, interpret them and react in the correct way. So, when you type "ls -la skoleLinux" into the console this is what happens:
  1. The console gets the keystrokes one at a time and passes them unchanged to the shell program it is running.
  2. The shell reads the keystrokes. When it gets a <return>, it breaks up the command as follows:
            Word #1: "ls"
            Word #2: "-la"
            Word #3: "skoleLinux"
    

    Word #1 is a command, the rest are options to the command. The command is either
    - a shell built-in command (echo,export,cd,=, ...)
    - an external command (should be in PATH)
    If the command is a built-in (eg cd skoleLinux), your shell does it internally. Otherwise, it searches the PATH environment variable for a program matching with that name. Here's my PATH (and how to display it):

            gavin@ravioli gavin> echo $PATH
            /usr/local/bin:/bin:/usr/bin/X11:/usr/games:/home/gavin/bin
    

    "ls" is not a built-in. So, it must be in the PATH. The above list of directories is searched in order to find a program called "ls". The shell finds the matching program "/bin/ls".

  3. Now, the shell executes "/bin/ls" passing it the options "-la" and "skoleLinux". Until it completes "ls" is now in control.

The difference between one shell and another lies mostly in the details of the interpretation and what built-in commands are available. The shells are the main owners/maintainers of Environment variables (eg $PATH, $CVS_RSH, $UID). One major difference between bash and tcsh is the built-in command used to set/modify your environment variables.

In bash, to set an environment variable you do things like:

export PATH=/usr/local/bin:/usr/bin
export PATH=$PATH:/usr/bin/X11:/usr/games:/home/gavin/bin
echo $PATH
        /usr/local/bin:/bin:/usr/bin/X11:/usr/games:/home/gavin/bin

In tcsh, you would do:

setenv PATH /usr/local/bin:/usr/bin
setenv PATH $PATH:/usr/bin/X11:/usr/games:/home/gavin/bin
echo $PATH
        /usr/local/bin:/bin:/usr/bin/X11:/usr/games:/home/gavin/bin

I recommend using bash. It's the standard one, it's the one I use and know and it's the one people will generally assume you are using as it is the default in most Linux systems.

In most unix systems the command "chsh" will allow you to change your shell permanently. You want it to be "/bin/bash" (without inverted commas of course).

BASH

A few useful facts about bash:

  1. ~/.bash_profile (ie the file .bash_profile in your home dir)

    All commands in this file are executed when you start bash. So you can put customisations in there, such as setting environment variables. You might like to create the file with:

            export CVS_RSH=ssh
            export CVS_ROOT=":ext:johne@cvs.skoleLinux.no:/var/lib/cvs"
    

    the above commands would be executed every time you login. Then you wouldn't need to type the commands every time you want to use CVS, they'd be set every time in advance.

  2. alias

    If you type a command a lot (eg ssh -X -C johne@fortycoats.ucd.ie): you can create a shortcut by:

    alias forty="ssh -t -X -C johne@fortycoats.ucd.ie "

    so, from then on, every time you type "forty" on the command line, when bash interprets it, it will substitute the above longer string delaying your inevitable arthritis. This is something you would put in your ~/.bash_profile

  3. It's a full programming environment.

    Without going into gory details, suffice to say that you can write if, else, while, for, etc. directly into bash and it will interpret it. For example, the following command will loop over a bunch of infidel usernames, deleting their home directories.

       for i in john rowland paul
       do
            rm -r ~$i/
       done
    
  4. Wildcards and other special characters

    If you do

            ls foo_*.txt
    
    you'll get a listing of all files beginning with "foo_" and ending ".txt" . In DOS, you can similarly do
    dir *
    . However, in DOS, the dir program reads the * and evaluates it. Here, BASH evaluates the * and ls sees the list of files as its options. ls itself does not understand wildcards. When it interpets the command it looks for certain special characters to interpret:
            * means a sequence of one or more characters (a wildcard)
            ? means a single character (a wildcard)
            $ means the following characters make up an env variable (eg $PATH)
            [acde] means a single character matching any of a,c,d or e
            [0-9] means any digit
            ~ shorthand for home directory
    
    As a case in point, if you are ever in a directory with a huge number of files (say 100,000) and you want to delete or list the files, you might try:
        gavin@robin tmp1> ls *
        bash: /bin/ls: Argument list too long
        gavin@robin tmp1> rm *
        bash: /bin/rm: Argument list too long
    
    It won't work. This is because bash evaluates the *, all 100,000 filenames end up as arguments (options) to the command and the ls and rm programs can't handle this. One solution which is certainly not optimal, but is useful as an example is to use a for loop.
        gavin@robin tmp1> for i in *
        > do
        > rm $i
        > done
    
    So bash launches the rm command once for each file * matches instead of once for all files. Related:
    Basic Shell Commands
    Moving to the last directory you were in


    About the author, Gavin McCullagh.