CPS 356 & 444/544 Lecture notes: the UNIX shell



Coverage: [UPE] Chapter 3


Introduction

  • shell definition: interface between the user and the operating system
  • different shells (targeted toward different uses and applications)
  • we are using the Korn (ksh) shell
    • ksh is a superset of the Bourne shell
    • allows access to prior (history) commands with the j, k keys (after <esc>)
    • starting and exiting
      • ksh creates a new instance of the Korn shell
      • $ exit closes the window or logout (equivalent to <ctrl-d>)
  • we have vi at the command-line
  • the shell is fully programmable
  • interpreted
  • will read from standard input or file input; interacting with system vs. shell programming


UNIX shells

  • Bourne (sh)
    • original UNIX shell
    • default prompt $
  • Korn (ksh)
    • superset of Bourne
    • default prompt $
    • default shell for CPS444/544
  • C (csh)
    • has a C-like syntax
    • default prompt %
  • Bash (bash)
    • bourne again shell
    • superset of Bourne
    • default prompt bash$
  • tcsh, zsh, ...
  • develop your own!


Basic shell setup


    (regenerated from [ATT] with minor modifications)




Shell commands vs. UNIX commands

some commands are built in to the shell and others are native UNIX commands
  • (shell builtin) echo or print vs. (UNIX) echo
  • shell cd vs. UNIX cd
  • use type shell builtin to distinguish:
    $ type ls
    ls is a tracked alias for /usr/bin/ls
    $ type less
    less is /usr/bin/less
    $ type echo
    echo is a shell builtin
    $ type print
    print is a shell builtin
    $ type type
    type is a shell builtin
    
  • or do a man, if the BUILTIN(1) page is returned, the command is particular to the shell


Kernel metacharacters

  • erase (^?): deletes previous character
  • kill (^U): deletes entire line
  • eof (^D): end of file
  • intr (^C): kills current foreground process
  • suspend (^Z)
  • stop (^S)
  • start (^Q)
  • lnext (^V): literal next, escapes special meaning of following kernel metacharacter
  • and others
  • stty -a (displays them)
  • tset


stty command

  • get/set kernel metacharacters
  • remember that a command does not receive its arguments until shell has interpreted all shell metacharacters
  • analogously, shell does not receive command line until kernel has interpreted all kernel metacharacters
  • these settings control standard input from and output to the terminal, not the shell
  • how to redefine erase to # (be careful)?
  • $ stty erase # this not work, why?
    $ stty erase '#' # are the single quotes necessary? will double quotes work just as well?
    $ stty erase \# # why must we protect the hash?
    $ stty erase ^? # why doesn't backspace need to be quoted?
    
  • stty sane
  • access/modification of terminal attributes through C
    • tcgetattr and tcsetattr functions
    • struct terminos


Korn shell metacharacters

  • filename wildcard meta-characters:

    character meaning
    # start of a comment to eol
    ; command separator
    ~ home directory
    * match any characters; alone expands to all files in current directory
    ? match any single character
    | pipe or logical "or" between patterns
    < redirect standard input
    > redirect standard output
    $ get value of variable following
    `<command>` command substitution; called grave quotes
    $(<command>) command substitution
    \ escapes next shell metacharacter; allows long command-lines to be split across multiple lines
    ' ... ' ... protected from shell interpretation
    " ... " ... protected from shell interpretation, except for $, \, " ", or $( ) (or ` `)
    [ begin a character group
    ] end a character group
    - denotes a character range
    ! negate a character group
    ?(<pattern>) match zero or one instance of <pattern>
    *(<pattern>) match zero or more instances of <pattern>
    +(<pattern>) match one or more instances of <pattern>
    @(<pattern>) match exactly one instance of <pattern>
    !(<pattern>) match any strings which do not contain <pattern>

  • examples:

      $ ls p*.c (lists all files which start with p and end in .c)

      $ ls prog?.c (lists all files which start with prog followed by any one character and end in .c)

      $ ls prog[0-9].c (lists all files which start with prog and end in .c with any single digit as the fifth character)

      $ ls prog+([0-9]).c (lists all files which start with prog followed by one or more digits and end in .c)

      $ ls prog*([0-9])@(.f|.c) (lists all files which start with prog, followed by zero or more digits, followed by .f or .c)

  • is . a shell metacharacter?


Metacharacters at different levels of interpretation

  • kernel
  • shell
  • grep, vi, ...


Command substitution

    $(<command>) is literally replaced by the output from command (the Bourne shell syntax for this uses grave quotes: `<command>`)
    $ print "The date and time is $(date)."
    The date and time is Tue Sep  2 13:38:02 EDT 2008.
    $ print "There are $(who | wc -l) users logged onto $(hostname)."
    There are 4 users logged onto sun131-31.cps.udayton.edu.
    $ echo "You have $(ls | wc -l) files in $(pwd)."
    You have 4 files in /home/cps444-n1.19.
    


Shell metacharacter interpretation examples

    $ echo hello
    hello
    $
    $ echo hello how are you
    hello how are you
    $
    $ echo *
    $
    $ echo *.c
    $
    $ cat on the wall
    $
    $ touch mickey mouse
    $
    $ # is whitespace a shell metacharacter?
    $ touch mickey\ mouse
    $
    $ touch \"hello
    $
    $ echo HOME
    HOME
    $
    $ echo $HOME
    /home/cps444-n1.19
    $
    $ echo '$HOME'
    $HOME
    $
    $ echo \$HOME
    $HOME
    $
    $ echo "$HOME"
    /home/cps444-n1.19
    $
    $ echo 'Single quotes "protect" double quotes'
    Single quotes "protect" double quotes
    $
    $ # ref. [UIAN] (p. 4-4)
    $ echo "Well, isn't that \"special\"?"
    Well, isn't that "special"?
    $
    $ echo "The value of \$PWD is $PWD"
    The value of $PWD is /home/cps444-n1.10/homeworks
    $
    # is newline a shell metacharacter?
    $ # use \ or quotes for escape newline for line continuation
    $ echo Howdy Tom, Dave, Robert, Paul, Sarah, \
    > Lucy, Linus, Linda, and Larry
    Howdy Tom, Dave, Robert, Paul, Sarah, Lucy, Linus, Linda, and Larry
    $
    $ echo "Howdy Tom, Dave, Robert, Paul, Sarah, 
    > Lucy, Linus, Linda, and Larry"
    Howdy Tom, Dave, Robert, Paul, Sarah,
    Lucy, Linus, Linda, and Larry
    $
    $ echo 'Howdy Tom, Dave, Robert, Paul, Sarah, 
    > Lucy, Linus, Linda, and Larry'
    Howdy Tom, Dave, Robert, Paul, Sarah,
    Lucy, Linus, Linda, and Larry
    $
    $ echo "Hello, how are you
    > today?"
    Hello, how are you
    today?
    $
    $ echo 'Go $HOME'
    Go $HOME
    $ echo "$5.00 is too much!"
    .00 is too much!
    $ echo $(who | wc -l) users is not very many
    2 users is not very many
    $
    $ ./a.out one two three four
    argc is 5
    argv[0] is ./a.out
    argv[1] is one
    argv[2] is two
    argv[3] is three
    argv[4] is four
    $
    $ ./a.out one "two three" four
    argc is 4
    argv[0] is ./a.out
    argv[1] is one
    argv[2] is two three
    argv[3] is four
    $
    $ # how can we create a file named -r
    $ # how can we remove a file named -r (be careful)
    


Shell scripts

  • for output, use print (shell builtin) or echo (e.g.,
    $ print "Hello World"
    Hello World
    
    print supports newline suppression through -n option, (e.g., print -n hello))
  • at the end of your script, use return <N> to return a specific return value
  • you can use the builtin variable $? to access the exit status of the previously run command (e.g.,
    $ print $?
    0
    
    )
  • the shell works with standard I/O and file I/O
  • $ cat > ourscript # can be done with vi as well
    print Beginning of long file listing
    ls -l
    echo End of long file listing
    return 0
    ^D
    $ ksh < ourscript # standard I/O
    Beginning of long file listing
    ...
    $ ksh ourscript # file I/O
    Beginning of long file listing
    ...
    End of long file listing
    
  • making a script standalone and executable:
    • include #!/usr/bin/env ksh (or alternatively #!/usr/bin/env followed by the path to the shell interpreter you want to evaluate the script) as the first line of the script
      • this line is not a comment
      • called the bang line
      • this statement in an executable file specifies which shell interpreter should evaluate the commands in the file
      • without this line the script will be evaluated with the default Borne shell
      • you could specify any command after #! to act as the interpreter for the commands in the script, and you can also give arguments
      • using env improves portability, mostly between Linux distros. Depending on the distro, a shell binary may be in a different bin directory whereas /usr/bin/env is a universal location.
      • can use the :r !which ksh ex command to read the path of ksh into the vi buffer (more on the which command later)
    • use chmod to make the script executable (more on the chmod command later):
      $ chmod +x ourscript
      
    • then you can execute ourscript like a regular command:
      $ ./ourscript
      Beginning of long file listing
      ...
      End of long file listing
      


References

    [UPE] B.W. Kernighan and R. Pike. The UNIX Programming Environment. Prentice Hall, Upper Saddle River, NJ, Second edition, 1984.
    [USP] K.A. Robbins and S. Robbins. UNIX Systems Programming: Concurrency, Communication, and Threads. Prentice Hall, Upper Saddle River, NJ, Second edition, 2003.

Return Home