UNIX Shell Programming Featuring KornShell
UNIX Shell Programming Featuring KornShell
Course Guide
EY–G994E-SG-0002
UNIX Shell Programming Featuring KornShell
Course Guide
EY–G994E-SG-0002
Notice
This guide contains information protected by copyright. No part of this guide may be photocopied or
reproduced in any form without prior written consent from Compaq Computer Corporation.
The software described in this guide is furnished under a license agreement or nondisclosure agreement.
The software may be used or copied only in accordance with the terms of this agreement.
Other product names mentioned herein may be trademarks and/or registered trademarks of their
respective companies.
©1999 Compaq Computer Corporation. All rights reserved. Printed in the USA.
Aero, ALPHA, ALPHA AXP, AlphaServer, AlphaStation, Armada, BackPaq, COMPAQ, Compaq
Insight Manager, CompaqCare logo, Counselor, DECterm, Deskpro, DIGITAL, DIGITAL logo,
DIGITAL Alpha Systems, Digital Equipment Corporation, DIGITAL UNIX, DirectPlus, FASTART,
Himalaya, HSZ, InfoPaq, Integrity, LAT, LicensePaq, Ministation, NetFlex, NonStop, OpenVMS,
PaqFax, Presario, ProLiant, ProLinea, ProSignia, QuickBack, QuickFind, Qvision, RDF, RemotePaq,
RomPaq, ServerNet, SERVICenter, SmartQ, SmartStart, SmartStation, SolutionPaq, SpeedPaq,
StorageWorks, Systempro/LT, Tandem, TechPaq, TruCluster, Tru64 UNIX are registered in United
States Patent and Trademark Office.
AIX and IBM are registered trademarks of International Business Machines Corp. BSD is a trademark
of the University of California, Berkeley, CA. Memory Channel is a trademark of Encore Computer
Corporation. Global Knowledge Network and the Global Knowledge Network logo are trademarks of
Global Nowledge Network, Inc. Microsoft and Windows NT are registered trademarks of Microsoft
Corporation. MIPS is a trademark of MIPS Computer Systems. Motif, OSF and OSF/1 are registered
trademarks of the Open Software Foundation. NetWorker is a trademark of Legato. NFS is a registered
trademark of Sun Microsystems, Inc. Oracle is a registered trademark and Oracle7 is a trademark of
Oracle Corporation. POSIX and IEEE are registered trademarks of the Institute of Electrical and
Electronics Engineers, Inc. PostScript is a registered trademark of Adobe Systems, Inc. UNIX is a
registered trademark licensed exclusively through X/Open Company Ltd. X Window System is a
trademark of the Massachusetts Institute of Technology.
EY-G994E-SG-0002 iii
Using the Pipe Operator to List All Block-Structured Devices ................... 1-7
Using the Pipe Operator to List All Files in /dev on the Printer .................. 1-7
Wildcard Metacharacters ...................................................................................... 1-8
Wildcards...................................................................................................... 1-8
Using Wildcards ........................................................................................... 1-8
Command History and Command Line Editing ................................................... 1-9
The history Command .................................................................................. 1-9
Recalling a Specific Command .................................................................... 1-9
Recalling a Command ................................................................................ 1-10
Using vi Commands ................................................................................... 1-10
Filename Completion ................................................................................. 1-10
Shell Variables .................................................................................................... 1-12
Guidelines................................................................................................... 1-12
Using Variables .......................................................................................... 1-12
Shell Variables............................................................................................ 1-12
Exporting Variables.................................................................................... 1-13
Listing Exported Variables......................................................................... 1-13
Foreground and Background Processes .............................................................. 1-14
Introduction ................................................................................................ 1-14
Running a Program in the Background ...................................................... 1-14
Running Multiple Commands in the Background...................................... 1-14
Running a Pipeline in the Background....................................................... 1-15
Obtaining a Long Listing of Process Status ............................................... 1-15
Moving a Foreground Job to the Background............................................ 1-16
Moving a Background Job into the Foreground......................................... 1-16
Waiting for a Background Process to Complete ........................................ 1-16
Terminating a Background Job .................................................................. 1-16
Stopping a Background Job........................................................................ 1-17
Job References............................................................................................ 1-17
vi Refresher......................................................................................................... 1-18
Sample vi Commands................................................................................. 1-18
Summary .......................................................................................................... 1-19
Defining and Redirecting Standard Files ................................................... 1-19
Using the Pipe Operator to Connect Two Commands ............................... 1-19
Using Wildcard Metacharacters ................................................................. 1-19
Using the History Command to Recall Commands ................................... 1-19
Using Shell Variables ................................................................................. 1-19
Defining and Using Foreground and Background Processes ..................... 1-19
Reviewing Some vi Commands ................................................................. 1-19
2 Getting Started with Scripting
About This Chapter............................................................................................... 2-3
Introduction .................................................................................................. 2-3
Objectives ..................................................................................................... 2-3
Resources...................................................................................................... 2-3
Processes ............................................................................................................ 2-4
iv EY-G994E-SG-0002
Definition...................................................................................................... 2-4
Process as Program Wrapper........................................................................ 2-4
fork() and exec() ........................................................................................... 2-4
Login Process Diagram ................................................................................ 2-4
Executing Shell Scripts......................................................................................... 2-5
Introduction .................................................................................................. 2-5
Executing a Shell Script as an Argument to ksh .......................................... 2-5
Permission Requirements for Executing a Shell Script as an Argument ..... 2-5
Executing Shell Scripts by Name ................................................................. 2-5
Permission Requirements for Executing Shell Scripts by Name ................. 2-5
The #! Operator ............................................................................................ 2-5
The print Statement ...................................................................................... 2-5
print Statement Syntax ................................................................................. 2-6
Using the print Statement to Write Standard Output.................................... 2-6
Using Positional Parameters ................................................................................. 2-7
Positional Parameters ................................................................................... 2-7
Arguments .................................................................................................... 2-7
Using Positional Parameters......................................................................... 2-8
Using the shift Statement.............................................................................. 2-8
shift Statement Syntax.................................................................................. 2-8
Default Parameter Value .............................................................................. 2-8
Using Parameter Values ............................................................................... 2-9
Escape Sequences ............................................................................................... 2-10
Using Wildcards as Literals........................................................................ 2-10
How the Escape Sequences Influence Output ............................................ 2-10
Using Escape Sequences Properly.............................................................. 2-11
Passing Arguments to Shell Scripts .................................................................... 2-12
Introduction ................................................................................................ 2-12
Environmental Variables ............................................................................ 2-12
Environmental Variables and Positional Parameters ................................. 2-12
How the read Command Works ................................................................. 2-13
Using the read Command ........................................................................... 2-13
Including a Prompt ..................................................................................... 2-13
Using read with a Prompt ........................................................................... 2-14
Testing Arguments.............................................................................................. 2-15
Techniques for Testing Arguments ............................................................ 2-15
General Syntax ........................................................................................... 2-15
Using the (( )) Command............................................................................ 2-15
Using the test Command ............................................................................ 2-15
Using the [ ] Command .............................................................................. 2-15
The [[ ]] Command..................................................................................... 2-16
Using Operators .................................................................................................. 2-17
Introduction ................................................................................................ 2-17
Integer Comparison Operators ................................................................... 2-17
Using Integer Comparison Operators......................................................... 2-17
String Comparison Operators ..................................................................... 2-18
EY-G994E-SG-0002 v
Using String Comparison Operators .......................................................... 2-18
File Enquiry Operators ............................................................................... 2-19
Using File Enquiry Operators..................................................................... 2-19
Testing for Permissions .............................................................................. 2-19
Logic Operators .......................................................................................... 2-20
Using Logic Operators ............................................................................... 2-20
Review........................................................................................................ 2-20
Making Decisions and Looping.......................................................................... 2-21
Introduction ................................................................................................ 2-21
The if/then/fi Commands............................................................................ 2-21
Using the if Command to Test the Status of the [[ Command ................... 2-21
Using the if Command to Test the Status of the who | grep Command ..... 2-22
Exact Syntax............................................................................................... 2-22
Commands in then or else Blocks .............................................................. 2-22
Using the while Loop ................................................................................. 2-22
Infinite Loops ............................................................................................. 2-23
The for Loop in KornShell ......................................................................... 2-23
Using the for Loop...................................................................................... 2-23
A Special Case............................................................................................ 2-23
Using Execute Trace and Verbose Trace to Debug Shell Scripts....................... 2-24
Introduction ................................................................................................ 2-24
Execute Trace ............................................................................................. 2-24
Using Execute Trace................................................................................... 2-24
Verbose Trace............................................................................................. 2-25
Using Verbose Trace .................................................................................. 2-25
Using Execute Trace Inside a Shell Script ................................................. 2-25
Command Substitution ....................................................................................... 2-26
Introduction ................................................................................................ 2-26
Procedure.................................................................................................... 2-26
Assigning Output of a Command to a Variable ......................................... 2-26
Using the Grave Accent.............................................................................. 2-26
Shell Script Examples......................................................................................... 2-27
Example 1................................................................................................... 2-27
Example 2................................................................................................... 2-28
Summary .......................................................................................................... 2-29
Defining and Using Processes .................................................................... 2-29
Executing a Shell Script ............................................................................. 2-29
Using Positional Parameters....................................................................... 2-29
Using Escape Sequences ............................................................................ 2-29
Passing Arguments to Shell Scripts............................................................ 2-29
Testing Arguments ..................................................................................... 2-29
Using Operators.......................................................................................... 2-29
Using Conditions, Control Statements and Loops ..................................... 2-29
Debugging Scripts Using Execute Trace and Verbose Trace .................... 2-29
Using Command Substitution .................................................................... 2-30
Exercises .......................................................................................................... 2-31
vi EY-G994E-SG-0002
Instructions ................................................................................................. 2-31
3 Intermediate Shell Scripting
About This Chapter............................................................................................... 3-3
Introduction .................................................................................................. 3-3
Objectives ..................................................................................................... 3-3
Resources...................................................................................................... 3-3
Executing a Script as a Sibling ............................................................................. 3-4
Normal Execution of a Shell Script.............................................................. 3-4
Parent and Child Scripts ............................................................................... 3-4
Running a Sibling......................................................................................... 3-4
Using the Dot Command .............................................................................. 3-5
Class Discussion........................................................................................... 3-5
The exec Command...................................................................................... 3-5
Grouping Shell Commands................................................................................... 3-7
Introduction .................................................................................................. 3-7
Using the Semicolon..................................................................................... 3-7
Using Parentheses......................................................................................... 3-7
Using Braces................................................................................................. 3-8
Control Statements................................................................................................ 3-9
Command Execution Dependent on Previous Command (&&, | |).............. 3-9
The && Operator ......................................................................................... 3-9
The | | Operator ............................................................................................. 3-9
The case Statement ....................................................................................... 3-9
Using the case Statement............................................................................ 3-10
The until Statement .................................................................................... 3-10
Using the until Statement ........................................................................... 3-10
Syntax for break and continue.................................................................... 3-11
Using break and continue ........................................................................... 3-11
Advanced Loop Processing ................................................................................ 3-12
Redirecting Input/Output in while Loops................................................... 3-12
Using the while read Statement.................................................................. 3-12
KornShell Aliases ............................................................................................... 3-13
Alias Definition .......................................................................................... 3-13
Preset Aliases.............................................................................................. 3-13
Defined Aliases .......................................................................................... 3-13
Tracked Aliases .......................................................................................... 3-13
Using Aliases in a Script ............................................................................ 3-14
Using $ set -o trackall................................................................................. 3-14
Exporting Aliases ....................................................................................... 3-15
KornShell Functions ........................................................................................... 3-16
Function Definition .................................................................................... 3-16
Invoking a Function.................................................................................... 3-16
Debugging Functions.................................................................................. 3-17
Exporting Functions ................................................................................... 3-17
The ENV Environment Variable ........................................................................ 3-18
EY-G994E-SG-0002 vii
The ENV Environment Variable ................................................................ 3-18
Default Execution....................................................................................... 3-18
Execution on Creating a New Kornshell .................................................... 3-18
Executing a Shell Script as an Argument to ksh ........................................ 3-18
Summary of Differences between $ myscript and $ ksh myscript............. 3-19
Executing ~/.kshrc...................................................................................... 3-19
Exception for Tru64 UNIX and Some Other Implementations.................. 3-19
Autoloading Functions ............................................................................... 3-19
Delaying Function Definition..................................................................... 3-20
Using Directory Information .............................................................................. 3-21
Introduction ................................................................................................ 3-21
Example Using the ma Function ................................................................ 3-22
Example Using the ga Function ................................................................. 3-23
Notes on Using the ga Function ................................................................. 3-24
Example Using the la Function .................................................................. 3-25
Another Example........................................................................................ 3-26
Running This Script.................................................................................... 3-26
Summary .......................................................................................................... 3-27
Executing a Script as a Sibling................................................................... 3-27
Grouping Shell Commands ........................................................................ 3-27
Using Control Statements........................................................................... 3-27
Enhancing Loop Processing ....................................................................... 3-27
Creating and Using Aliases ........................................................................ 3-27
Creating and Using Functions .................................................................... 3-27
Using the ENV Variable............................................................................. 3-27
Using Directory Information ...................................................................... 3-27
Exercises .......................................................................................................... 3-28
Instructions ................................................................................................. 3-28
4 Advanced Shell Scripting
About This Chapter............................................................................................... 4-3
Introduction .................................................................................................. 4-3
Objectives ..................................................................................................... 4-3
Resources...................................................................................................... 4-3
Menu Processing................................................................................................... 4-4
List Processing (select)................................................................................. 4-4
User Prompts ................................................................................................ 4-5
Prompt Reminder ......................................................................................... 4-5
Signals….. ............................................................................................................ 4-6
Introduction .................................................................................................. 4-6
Assigned Signals in Tru64 UNIX................................................................. 4-6
Obtaining a List of Signals ........................................................................... 4-7
Signal Actions .............................................................................................. 4-7
User Programming Example ........................................................................ 4-7
Common Signals .......................................................................................... 4-8
Notes about the kill Signal ........................................................................... 4-8
viii EY-G994E-SG-0002
Using kill to Send a Signal to a Process ....................................................... 4-9
Handling Signals in a Shell Script ...................................................................... 4-10
The trap Command ..................................................................................... 4-10
Using trap to Clean up Temporary Files .................................................... 4-10
The /tmp Directory ..................................................................................... 4-10
Using trap to Catch, Ignore, and Reset Signals .......................................... 4-11
Ignoring Other Signals ............................................................................... 4-11
Executing Commands................................................................................. 4-11
Displaying trap Settings ............................................................................. 4-11
Using the trap Command............................................................................ 4-12
date Formats ............................................................................................... 4-12
Integer Arithmetic in the KornShell ................................................................... 4-13
The Integer Data Type................................................................................ 4-13
Declaring Integers ...................................................................................... 4-13
The (( )) Operator ....................................................................................... 4-13
Supported Operators................................................................................... 4-13
Using Math Operations in a while Loop .................................................... 4-14
Declaring Integers of Different Bases ........................................................ 4-14
Converting from Decimal to Hexadecimal................................................. 4-14
Floating-Point Arithmetic in the KornShell........................................................ 4-15
Not Supported in ksh88.............................................................................. 4-15
Utilities Operators ...................................................................................... 4-15
Using Operators from Utilities ................................................................... 4-15
Supported in ksh93..................................................................................... 4-16
Variable Arrays................................................................................................... 4-17
Declaring Arrays ........................................................................................ 4-17
Assigning Values to an Array..................................................................... 4-17
Accessing the Values of an Array .............................................................. 4-17
Using Variable Arrays................................................................................ 4-18
Loading an Array from a Disk File ............................................................ 4-19
The set –A Command................................................................................. 4-19
Assigning Values to an Array Using the set -A Command........................ 4-20
Changing IFS (Internal Field Separator) ............................................................ 4-21
Introduction ................................................................................................ 4-21
Using IFS.................................................................................................... 4-22
Command Evaluation ......................................................................................... 4-23
Order of Evaluation (eval).......................................................................... 4-23
Common Errors in Evaluation.................................................................... 4-23
Repairing Common Errors in Evaluation – Part 1...................................... 4-24
Repairing Common Errors in Evaluation – Part 2...................................... 4-24
Tools for Shell Scripts ........................................................................................ 4-25
The df Command........................................................................................ 4-25
The sed and cut Commands with df ........................................................... 4-25
Setting Positional Parameters ............................................................................. 4-26
Setting and Changing Positional Parameters.............................................. 4-26
Using Positional Parameters....................................................................... 4-26
EY-G994E-SG-0002 ix
Using the ls Command ............................................................................... 4-27
Making Nice Neat Columns ............................................................................... 4-28
Slicing off the Leftmost Characters............................................................ 4-28
Using Wildcards ......................................................................................... 4-29
Slicing off Portions of a Pathname............................................................. 4-29
The ## Operator.......................................................................................... 4-29
Slicing off the Rightmost Characters ......................................................... 4-30
Slicing off the Suffix from a Filename....................................................... 4-30
Renaming Files........................................................................................... 4-31
Finding the Length of a String.................................................................... 4-31
Using ${#str} ............................................................................................. 4-32
Summary .......................................................................................................... 4-33
Creating and Using Menu Processors......................................................... 4-33
Identifying and Using Signals .................................................................... 4-33
Handling Signals in a Shell Script.............................................................. 4-33
Using Integer Arithmetic............................................................................ 4-33
Using Floating-Point Arithmetic ................................................................ 4-33
Creating and Using Variable Arrays .......................................................... 4-33
Changing the Internal Field Separator........................................................ 4-33
Performing Command Evaluation Using eval............................................ 4-33
Using Tools for Shell Scripts ..................................................................... 4-33
Setting Positional Parameters ..................................................................... 4-34
Exercises .......................................................................................................... 4-35
Instructions ................................................................................................. 4-35
5 Tips and Tricks
About This Chapter............................................................................................... 5-3
Introduction .................................................................................................. 5-3
Objectives ..................................................................................................... 5-3
Resources...................................................................................................... 5-3
Here Documents ................................................................................................... 5-4
Sending Mail from a Shell Script ................................................................. 5-4
Using the mail Command............................................................................. 5-4
Redirection Characters ................................................................................. 5-4
Invoking the ed Utility.................................................................................. 5-5
Substituting Arguments Inside a Here Document ........................................ 5-5
Using a Here Document to Spawn a Child Shell Script............................... 5-6
File Input and Output Operations ......................................................................... 5-7
Opening a Stream for Reading ..................................................................... 5-7
Opening a Stream for Writing ...................................................................... 5-8
Command Options Processing.............................................................................. 5-9
Introduction .................................................................................................. 5-9
Using Command Line Options..................................................................... 5-9
Error Checking ........................................................................................... 5-10
Detecting Invalid Command Line Options................................................. 5-10
+ Switches and - Switches.......................................................................... 5-10
x EY-G994E-SG-0002
Using + and - Switches............................................................................... 5-11
The OPTIND Variable ............................................................................... 5-11
Using the OPTIND Variable ...................................................................... 5-12
Pattern Matching Operators ................................................................................ 5-13
Review........................................................................................................ 5-13
Matching..................................................................................................... 5-13
Special KornShell-Only Wildcards ............................................................ 5-14
Using a Lock File to Synchronize Access .......................................................... 5-15
Using a Lock File ....................................................................................... 5-15
Testing for Superuser ................................................................................. 5-15
Test 1 .......................................................................................................... 5-15
Test 2 .......................................................................................................... 5-15
setuid Bit for Shell Scripts.......................................................................... 5-16
The setuid Concept ..................................................................................... 5-16
Using setuid ................................................................................................ 5-17
Using sush .................................................................................................. 5-17
KornShell Command Processing ........................................................................ 5-19
KornShell Command Line Parsing............................................................. 5-19
Command Word Precedence ...................................................................... 5-19
Exercise/Discussion.................................................................................... 5-20
Co–processes ...................................................................................................... 5-21
Definition.................................................................................................... 5-21
Running a Script as a Co-process............................................................... 5-21
Co-process Diagram ................................................................................... 5-22
Using Multiple Co-processes ..................................................................... 5-23
Using Co-processes .................................................................................... 5-24
Starting preserve shell From .profile .......................................................... 5-24
Single Quotes.............................................................................................. 5-25
The if Command......................................................................................... 5-25
The print Command.................................................................................... 5-25
The for Loop............................................................................................... 5-25
The read Command .................................................................................... 5-25
Readability and Maintainability.......................................................................... 5-26
Suggestions................................................................................................. 5-26
Include Comments at the Beginning of a Script......................................... 5-26
Organize the Script into Sections of Related Commands .......................... 5-26
Explain Obscure Syntax with Comments................................................... 5-26
Use Blank Lines to Delineate Compound Statements................................ 5-27
Indent the Bodies of Compound Statements .............................................. 5-27
Set up Compound Statements Consistently................................................ 5-27
Avoid Combining Unrelated Commands ................................................... 5-28
Performance ........................................................................................................ 5-29
Improving Performance.............................................................................. 5-29
Shell Script Examples......................................................................................... 5-30
Searching the /etc/passwd File ................................................................... 5-30
Repeatedly Invoking a Command .............................................................. 5-30
EY-G994E-SG-0002 xi
Using replay_opt ........................................................................................ 5-31
The Leading Colon ..................................................................................... 5-32
Checking Commands.................................................................................. 5-32
A Better grep .............................................................................................. 5-33
The sed Command...................................................................................... 5-33
How the sed Command Works................................................................... 5-34
Summary .......................................................................................................... 5-35
Using Here Documents............................................................................... 5-35
Using File I/O Operators ............................................................................ 5-35
Using Command Options Processing......................................................... 5-35
Reviewing Pattern Matching Operators ..................................................... 5-35
Using a Lock File to Synchronize Access.................................................. 5-35
Using Kornshell Command Processing...................................................... 5-35
Creating and Using Co-Processes .............................................................. 5-35
Practice Tips on Code Readability and Maintainability............................. 5-35
Identifying Ways to Improve Performance ................................................ 5-35
Exercises .......................................................................................................... 5-36
Instructions ................................................................................................. 5-36
Appendix A
List of Symbols .....................................................................................................A-3
Symbol Table................................................................................................A-3
Appendix B
xii EY-G994E-SG-0002
Tables
EY-G994E-SG-0002 xiii
xiv EY-G994E-SG-0002
Figures
EY-G994E-SG-0002 xv
xvi EY-G994E-SG-0002
About This Course
EY-G994E-SG-0002 xvii
UNIX Shell Programming Featuring KornShell
xviii EY-G994E-SG-0002
About This Course
Course Description
KornShell scripts are powerful tools for administering systems, manipulating text,
or managing large collections of files. In this course, you will learn how to write
scripts for the newest and most important of the standard UNIX shells, the
KornShell. If you already know the C shell, you can build on that knowledge and
learn to write more advanced scripts with the KornShell.
Place in Curriculum
This course is a basic user course. It is also the prerequisite for the UNIX
programming curriculum.
Target Audience
This course will be of particular benefit to system analysts, application
programmers, system administrators and technical personnel who want to learn
how to write KornShell scripts.
EY-G994E-SG-0002 xix
UNIX Shell Programming Featuring KornShell
Prerequisites
It is expected that the student will have attended a UNIX Utilities & Commands
course or have the equivalent knowledge.
Course Goals
To program the KornShell, you should be able to:
! Define and redirect standard files
! Use the pipe operator to connect two commands
! Use wildcard metacharacters
! Use the history command to recall commands
! Use shell variables
! Define and use foreground and background processes
! Define and use processes and co-processes
! Use directory information in scripts
! Set and use positional parameters
! Use escape sequences
! Pass arguments to shell scripts and test arguments
! Use conditions and control statements
! Use the if command in a decision
! Use while and for loops
! Debug scripts using execute trace and verbose trace
! Use command substitution
! Group shell commands
! Create and use aliases and functions
! Identify and use signals and handle signals in a shell script
! Use integer and floating-point arithmetic
! Create and use variable arrays
! Perform command evaluation using eval
! Use Here documents and file I/O operators
! Use command options processing
! Use a lock file to synchronize access
xx EY-G994E-SG-0002
About This Course
Nongoals
This course does not cover the following topics:
! Managing the software process
! Transferring files and executing commands across TCP/IP networks
! System administration
EY-G994E-SG-0002 xxi
UNIX Shell Programming Featuring KornShell
Course Map
The Course Map shows how each chapter is related to other chapters and to the
course as a whole. Before studying a chapter, you should master all of its
prerequisite chapters. The prerequisite chapters are depicted before the following
chapters on the Course Map. The direction of the arrows determines the order in
which the chapters should be covered.
xxii EY-G994E-SG-0002
About This Course
Review
Getting Started
with Scripting
Intermediate
Shell Scripting
Advanced
Shell Scripting
Chapter Descriptions
A brief description of each chapter is listed below.
! Review — Reviews of basic shell concepts, including redirecting standard
files, using the pipe operator and wildcard metacharacters, and the history
command. Using shell variables and understanding foreground and
background processes, vi commands is also discussed.
! Getting Started with Scripting — Describes how to execute a shell script,
pass arguments to scripts, test arguments, and debug scripts. Also, how to use
the if command, and while and for loops; use positional parameters,
escape sequences, condition and control statements, and command
substitution.
EY-G994E-SG-0002 xxiii
UNIX Shell Programming Featuring KornShell
Time Schedule
The amount of time required for this course depends on each student’s background
knowledge, experience, and interest in the various topics. Use the following table
as a guideline.
xxiv EY-G994E-SG-0002
About This Course
Course Conventions
This book uses the following course conventions.
Resources
For more information on the topics in this module, refer to the following:
! Tru64 UNIX Reference Pages
! Command and Shell User’s Guide
! Kornshell Programming Tutorial, Barry Rosenberg, Reading, MA: Addison-
Wesley Publishing Co., 1991 (ISBN 0-201-56324-X)
! The Kornshell Command and Programming Language, Morris I. Bolsky and
David G. Korn, Englewood Cliffs, NJ: Prentice Hall, 1989 (ISBN 0-13-
516972-0)
EY-G994E-SG-0002 xxv
UNIX Shell Programming Featuring KornShell
xxvi EY-G994E-SG-0002
Review
Module 1
EY-G994E-SG-0002 1–1
UNIX Shell Programming Featuring KornShell
1–2 EY-G994E-SG-0002
Review
Objectives
When you complete this module, you will be able to:
! Define and redirect standard files
! Use the pipe operator to connect two commands
! Use wildcard metacharacters
! Use the history command to recall commands
! Use shell variables
! Define and use foreground and background processes
! Use some vi commands
Resources
For more information on the topics in this module, refer to the following:
! Tru64 UNIX Reference Pages
! Command and Shell User’s Guide
! Kornshell Programming Tutorial, Barry Rosenberg, Reading, MA: Addison-
Wesley Publishing Co., 1991 (ISBN 0-201-56324-X)
! The Kornshell Command and Programming Language, Morris I. Bolsky and
David G. Korn, Englewood Cliffs, NJ: Prentice Hall, 1989 (ISBN 0-13-
516972-0)
EY-G994E-SG-0002 1–3
UNIX Shell Programming Featuring KornShell
Standard Files
Standard Input
Standard input refers to the stream from which commands and scripts gather input.
Standard Output
Standard output refers to the stream to which commands and scripts send their
(nonerror) output.
Example
who, date, ls, ...
1–4 EY-G994E-SG-0002
Review
EY-G994E-SG-0002 1–5
UNIX Shell Programming Featuring KornShell
Redirecting Input
The < operator redirects standard input, telling the KornShell to gather input from
the specified file.
For example, the following command mails the contents of file message to user
john.
$ mail john < message
1–6 EY-G994E-SG-0002
Review
Using the Pipe Operator to List All Files in /dev on the Printer
Use the following command to write all files in /dev which are block structured
devices and then send that list to the printer.
$ ls -l /dev | grep ’^b’ | lpr
EY-G994E-SG-0002 1–7
UNIX Shell Programming Featuring KornShell
Wildcard Metacharacters
Wildcards
Table 1-1 shows the wildcards available in the Bourne Shell, C Shell, and
KornShell. Note that the KornShell also supports five additional wildcards not
supported by the Bourne Shell and C shell.
Using Wildcards
The following code example shows how wildcards are used.
Example
$ ls -a
. .login get.c put.c x x2 xfour z4
.. a msg.c put.o x1 x3 y4sale zed
$ ls x?
x1 x2 x3
$ ls x*
x x1 x2 x3 xfour
$ ls x??
x?? not found
$ ls [xyz]*
x x2 xfour z4
x1 x3 y4sale zed
$ ls [x-z]4*
y4sale z4
$ ls [!a-y]*
z4 zed
$ ls -l ~/srcfile
-rw-r--r-- 1 mary 362 Nov 3 12:13 srcfile
$ cp myfile ~
1–8 EY-G994E-SG-0002
Review
EY-G994E-SG-0002 1–9
UNIX Shell Programming Featuring KornShell
Recalling a Command
Another way to repeat recently issued commands is to press Esc/K over and over
until you reach the command you want to redo, as shown in the following
example.
Example
$ set -o vi #establish vi mechanism for redoing commands
$ <esc>k #retrieve latest command
$ set -o vi #cursor at beginning of line
k #retrieve next latest command
$ chmod a-x mbox #cursor at beginning of line
^C #terminate history scan
Using vi Commands
When typing commands on the KornShell command line, you can use just about
any vi commands to edit the command line.
Table 1-2 lists vi commands and their meanings.
Filename Completion
If you only know the first letter or first few letters of a command, you can type
<esc>\ and the KornShell will complete the remaining letters for you.
Note that sometimes several files begin with the same initial letters, so you may
need to type in quite a few letters before the KornShell can determine the filename,
as shown in the following code example.
1 – 10 EY-G994E-SG-0002
Review
Example
$ ls
comm edit files make machine shell
$ lpr ed<esc>\
lpr edit
EY-G994E-SG-0002 1 – 11
UNIX Shell Programming Featuring KornShell
Shell Variables
Guidelines
Variable names MUST begin with a letter or underscore, but may contain digits,
letters, or underscores.
Using Variables
The following example shows how to assign and display shell variables.
Example
$ var1=”Brown” # assign a value to variable var1
$ var2=”stone” # assign a value to variable var2
$ concat=”$var1$var2” # concatenate two variables
$ print "$var2"
stone
$ print "$concat"
Brownstone
Shell Variables
Table 1-3 lists commonly used KornShell reserved variables. The complete list of
environment variables available on your system will be a superset of this list.
1 – 12 EY-G994E-SG-0002
Review
Exporting Variables
Suppose you declare a variable named var on the shell command line.
If you do export var, then shell scripts can access the value of var.
If you do not export var, then shell scripts cannot access the value of var.
The following example contrasts the results of exporting and not exporting the
variable.
Example
$ cat shscript
print $var
$ var=12345
$ export var
$ shscript
12345
If an exported variable is modified, the new value is exported.
EY-G994E-SG-0002 1 – 13
UNIX Shell Programming Featuring KornShell
1 – 14 EY-G994E-SG-0002
Review
$ ps x
PID STAT TT TIME CMD
2680 S 01 0:00 - (ksh)
4792 R 01 0:07 ps x
4790 R 01 0:07 grep ^B
4791 R 01 0:01 lpr
EY-G994E-SG-0002 1 – 15
UNIX Shell Programming Featuring KornShell
1 – 16 EY-G994E-SG-0002
Review
Job References
Table 1-4 shows job references for the fg, bg, wait, and kill commands.
EY-G994E-SG-0002 1 – 17
UNIX Shell Programming Featuring KornShell
vi Refresher
Sample vi Commands
The vi editor is a powerful text editor.
Sample commands and their meanings are listed in Table 1-5.
1 – 18 EY-G994E-SG-0002
Review
Summary
Defining and Redirecting Standard Files
Standard files are the stream from which commands and scripts gather input.
These streams can be redirected using operators described in this chapter.
EY-G994E-SG-0002 1 – 19
UNIX Shell Programming Featuring KornShell
1 – 20 EY-G994E-SG-0002
Getting Started with Scripting
Module 2
EY-G994E-SG-0002 2–1
UNIX Shell Programming Featuring KornShell
2–2 EY-G994E-SG-0002
Getting Started with Scripting
Objectives
When you complete this module, you will be able to:
! Define and use processes
! Execute a shell script
! Use positional parameters
! Use escape sequences
! Pass arguments to shell scripts
! Test arguments
! Use operators
! Use conditions, control statements and loops
! Debug scripts using execute trace and verbose trace
! Use command substitution
Resources
For more information on the topics in this module, refer to the following:
! Tru64 UNIX Reference Pages
! Command and Shell User’s Guide
! Kornshell Programming Tutorial, Barry Rosenberg, Reading, MA: Addison-
Wesley Publishing Co., 1991 (ISBN 0-201-56324-X)
! The Kornshell Command and Programming Language, Morris I. Bolsky and
David G. Korn, Englewood Cliffs, NJ: Prentice Hall, 1989 (ISBN 0-13-
516972-0)
EY-G994E-SG-0002 2–3
UNIX Shell Programming Featuring KornShell
Processes
Definition
A process is the kernel environment in which a user program executes. The kernel
schedules the process to execute, not programs.
Shell ‘execs’
Command
2–4 EY-G994E-SG-0002
Getting Started with Scripting
The #! Operator
By default, the KornShell assumes that the scripts you invoke are KornShell
scripts. However, you can run a C shell script from the KornShell command line.
Conversely, you can run a KornShell script from the C shell command line.
If you are writing a KornShell script and want to allow anyone (no matter what
shell they are using) to run it, place the following statement as the first line of your
script:
#!/usr/bin/ksh
EY-G994E-SG-0002 2–5
UNIX Shell Programming Featuring KornShell
2–6 EY-G994E-SG-0002
Getting Started with Scripting
Arguments
Figure 2-2 shows how the positional parameters are assigned.
$0 $1 $2 $9 ${10} ${11}
EY-G994E-SG-0002 2–7
UNIX Shell Programming Featuring KornShell
2–8 EY-G994E-SG-0002
Getting Started with Scripting
EY-G994E-SG-0002 2–9
UNIX Shell Programming Featuring KornShell
Escape Sequences
Table 2-2 lists escape sequences and what they do.
2 – 10 EY-G994E-SG-0002
Getting Started with Scripting
EY-G994E-SG-0002 2 – 11
UNIX Shell Programming Featuring KornShell
Environmental Variables
Environment variables are commonly used for values that do not vary from
command to command. For example, LANG is used to represent the language of
the user.
$ export ANIMAL=dog
$ myscript mouse
What animal: lion
environment animal = dog
cmd line animal = mouse
read animal = lion
2 – 12 EY-G994E-SG-0002
Getting Started with Scripting
$ myscript
sam tony
arg1 = sam
arg2 = tony
$ myscript
mary betty harry
arg1 = mary
arg2 = betty harry
$ myscript
george
arg1 = george
arg2 =
Including a Prompt
You can build the prompt string into the read statement as follows:
read var?prompt
prompt is written to standard error. Line from standard input is assigned to var.
EY-G994E-SG-0002 2 – 13
UNIX Shell Programming Featuring KornShell
2 – 14 EY-G994E-SG-0002
Getting Started with Scripting
Testing Arguments
Techniques for Testing Arguments
The KornShell provides four techniques for testing arguments:
1. [[ ]] — new with KornShell (preferred for string tests)
2. (( )) — new with KornShell (preferred for math tests)
3. test command — Bourne shell and KornShell
4. []— Bourne shell & KornShell
General Syntax
All four techniques test arguments and assign the outcome of that test to the
special shell variable $?. The value of $? will be either:
zero SUCCESS
or
nonzero FAILURE
EY-G994E-SG-0002 2 – 15
UNIX Shell Programming Featuring KornShell
The [[ ]] Command
Sample usage of the [[ ]] command is shown below.
if [[ “$response” = “Yes” ]]
then
print “Okay, we’re going ahead.”
fi
Note: Spaces around [[ and ]] are required, as shown below.
$ [[“$response” = “Yes” ]]
ksh: [[: not found
2 – 16 EY-G994E-SG-0002
Getting Started with Scripting
Using Operators
Introduction
This section discusses the following operators:
! Integer comparison operators
! String comparison operators
! File enquiry operators
! Logic operators
EY-G994E-SG-0002 2 – 17
UNIX Shell Programming Featuring KornShell
$ [[ “$s” = “Bye” ]]
$ print $?
1
You can compare a string to a pattern containing wildcards, for example:
$ s=”Yes”
$ [[ “$s” = Y* ]] # Does string start with ‘Y’
$ print $?
0
2 – 18 EY-G994E-SG-0002
Getting Started with Scripting
EY-G994E-SG-0002 2 – 19
UNIX Shell Programming Featuring KornShell
Logic Operators
The following logic operators are shown in decreasing order of precedence.
Operator What It Does
! Unary negation operator
&& Logical AND operator
|| Logical OR operator
Review
Given the following:
$ A="Oak"; B="Elm"; C=hope; D=hope
what value is returned by each of the following?
1. [[ $A = $C ]]
2. [[ ! -n $D ]]
3. [[ $A != $B && $C = $D ]]
4. [[ $A = $B || $C = $D ]]
2 – 20 EY-G994E-SG-0002
Getting Started with Scripting
if [[ -f $1 ]]
then
print "$1 is a plain file"
elif [[ -d $1 ]]
then
print "$1 is a directory file"
else
print "$1 is neither a plain file nor a directory"
fi
EY-G994E-SG-0002 2 – 21
UNIX Shell Programming Featuring KornShell
Exact Syntax
Note the need for exact syntax. KornShell is not as forgiving as the C language.
! then requires a line by itself
! elif requires a then, else does not
! fi terminates if
2 – 22 EY-G994E-SG-0002
Getting Started with Scripting
Infinite Loops
The following program loops forever.
while true
do
lines executed in an infinite loop
done
true always returns a 0 (success) value.
A Special Case
The following is a special case of for that uses positional parameters.
# The following for loop iterates one time for each command
# line argument:
for FILE
do
cp ${FILE} ${FILE}new
done
Note:
for FILE
is equivalent to:
for FILE in $*
EY-G994E-SG-0002 2 – 23
UNIX Shell Programming Featuring KornShell
Execute Trace
Execute trace prints shell commands as they are executed.
$ print $PS4
+
$ export PS4=’at $LINENO - ’
2 – 24 EY-G994E-SG-0002
Getting Started with Scripting
Verbose Trace
Verbose trace prints shell commands as they are read, and is useful for syntax
checking.
EY-G994E-SG-0002 2 – 25
UNIX Shell Programming Featuring KornShell
Command Substitution
Introduction
Command substitution may be used to assign the output of a command to a
variable.
Procedure
Assign the standard output of command to var, as shown below.
var=$(command)
2 – 26 EY-G994E-SG-0002
Getting Started with Scripting
if (( $# != 1 ))
then
print "Usage: $0 number" >&2
exit 1
fi
number_logged_in=$(who | wc -l)
if (( $number_logged_in > $1 ))
then
print "Too many users logged on"
kill -9 $PPID
fi
EY-G994E-SG-0002 2 – 27
UNIX Shell Programming Featuring KornShell
Example 2
This example shows a shell script which takes one filename as a command line
argument and determines how many lines are in that file. If the file is longer than
two pages, the shell script asks you if you wish to print it after hours. If you
respond affirmatively, the shell script exits; otherwise, the file is printed. If the
command line argument is a directory or is not readable, an appropriate error
message is printed.
#!/usr/bin/ksh
#printlater
if [[ $# -ne 1 ]] ; then
print "Usage: $0 filename" >&2
exit 1
fi
if [[ -d $1 || ! -r $1 ]]
then
print "$1 cannot be printed." >&2
exit 2
fi
let "len=$(wc -l $1)/60+1"
if [[ $len -gt 2 ]]
then
read ans?"Print after hours?: "
if [[ $ans = y* ]] ; then
exit
fi
fi
lpr $1
2 – 28 EY-G994E-SG-0002
Getting Started with Scripting
Summary
Defining and Using Processes
A process is a kernel environment in which a user program executes. Each
program runs in a process, so the process acts as a program wrapper. Use
fork() to create a new process running in the same program and exec() to
replace a program in a process with another.
Testing Arguments
Arguments are tested using four techniques described in this chapter. All four
techniques put the outcome of the test into the variable $?.
Using Operators
This chapter discussed integer, string, file enquiry, and logic operators.
EY-G994E-SG-0002 2 – 29
UNIX Shell Programming Featuring KornShell
2 – 30 EY-G994E-SG-0002
Getting Started with Scripting
Exercises
Instructions
1. Write a shell script that checks for a minimum of two arguments. Print an
error message to the standard error file if the user types less than two
arguments; otherwise, print all the arguments to the standard output file.
2. Write a shell script that will accept a single file name on the command line. If
the file exists, the script will ask the user whether a backup copy of the file
should be made. A backup copy with a suffix of .backup is created, if
requested, and the vi editor is invoked for the file.
3. Write a shell script that will prompt for and read from the standard input file
a first name, a last name, and a telephone extension. Write these values to a
file named ./phonelist and loop until a first name of "quit" is typed.
4. The shell script dirtest works incorrectly. Make a copy in your directory
and execute it with several pathnames as command line arguments, for
example:
$ dirtest /etc /etc/motd /mnt
Use shell debugging techniques to find and correct the problems. A listing of
dirtest follows:
#!/bin/ksh
#dirtest - shell script with bugs
for i
if (-d i)
print "$i is a directory"
else
print "$1 is not a directory"
endif
end
5. Write a shell script that will accept an option (-r or -w) and a file name
argument on the command line. Have the script print an appropriate message
to the standard output file indicating that the file does not exist, is readable,
or is writeable. If an option is not typed on the command line, assume -r.
6. Write a shell script that will make a copy with a suffix of .save of any file
specified on the command line, for example abc to abc.save. Assume that
users might specify multiple file names on the command line. If no file
names are typed on the command line, make the .save copies for all files in
the current working directory.
7. Use the ps(1), cut(1), and sort(1) commands to print a list of process ids
currently in use. Print the list of PIDs in increasing numerical order.
EY-G994E-SG-0002 2 – 31
UNIX Shell Programming Featuring KornShell
2 – 32 EY-G994E-SG-0002
Intermediate Shell Scripting
Module 3
EY-G994E-SG-0002 3–1
UNIX Shell Programming Featuring KornShell
3–2 EY-G994E-SG-0002
Intermediate Shell Scripting
Objectives
When you complete this module, you will be able to:
! Execute a script as a sibling
! Group shell commands
! Use control statements
! Enhance loop processing
! Create and use aliases
! Create and use functions
! Use the ENV variable
! Recall and use directory information in scripts
Resources
For more information on the topics in this module, refer to the following:
! Tru64 UNIX Reference Pages
! Command and Shell User’s Guide
! Kornshell Programming Tutorial, Barry Rosenberg, Reading, MA: Addison-
Wesley Publishing Co., 1991 (ISBN 0-201-56324-X)
! The Kornshell Command and Programming Language, Morris I. Bolsky and
David G. Korn, Englewood Cliffs, NJ: Prentice Hall, 1989 (ISBN 0-13-
516972-0)
EY-G994E-SG-0002 3–3
UNIX Shell Programming Featuring KornShell
login child
ls
ksh ksh
Running a Sibling
Instead of running a KornShell script as a child, you can run it as a sibling.
Although the second script is termed “sibling,” the original script remains the
parent. By running as a sibling, the script can change the parent’s environment.
To run as a sibling, precede the KornShell script with a . (dot) and then a space.
The dot command serves the same purpose in KornShell as the source command
does in the C shell. The dot command is used for shell scripts only.
3–4 EY-G994E-SG-0002
Intermediate Shell Scripting
Class Discussion
Consider: $ .profile
login:
This process can be viewed as:
login
ksh
becomes
ksh ls
(cd)
EY-G994E-SG-0002 3–5
UNIX Shell Programming Featuring KornShell
login
ksh
becomes
ls
3–6 EY-G994E-SG-0002
Intermediate Shell Scripting
(cd )
Using Parentheses
Parentheses force the group to execute in a child shell.
The following example shows how to use parenthesis.
Example
$ pwd # where are we?
/usr/users/sam
EY-G994E-SG-0002 3–7
UNIX Shell Programming Featuring KornShell
(cd )
Using Braces
Braces cause the group to execute in the parent shell, but allow redirection of
multiple commands.
$ { cd /etc ; pwd ; ls m* ; } > ~/list
Note the punctuation: Spaces before and after the braces are essential; the trailing
semicolon is also essential.
The following example shows how to use braces.
Example
$ cat ~/list
/etc
mail.aliases miscd mkfs
mklost+found mknod mkpasswd
mkproto motd mount
$ pwd
/etc
This can be viewed as:
login
ls
ksh
(cd,pwd)
3–8 EY-G994E-SG-0002
Intermediate Shell Scripting
Control Statements
Command Execution Dependent on Previous Command (&&, | |)
Using the boolean AND operator (&&) tells the KornShell to execute the command
on the right only if the command on the left succeeds. Using the boolean OR
operator (||) tells the KornShell to execute the command on the right only if the
command on the left fails.
The | | Operator
The following example shows how to use the || operator.
Example
cmd1 || cmd2 execute cmd2 only if cmd1 fails.
$ who | grep -q sam || print "sam NOT logged on"
EY-G994E-SG-0002 3–9
UNIX Shell Programming Featuring KornShell
3 – 10 EY-G994E-SG-0002
Intermediate Shell Scripting
In the following example, the grep command returns a failure status if the search
string is not in the input file.
Example
until grep -s Results $1
do
print "No Results found in $1"
shift
done
$ myscript abc.txt data.file nov.dat
No Results found in abc.txt
EY-G994E-SG-0002 3 – 11
UNIX Shell Programming Featuring KornShell
3 – 12 EY-G994E-SG-0002
Intermediate Shell Scripting
KornShell Aliases
Alias Definition
An alias is a synonym or nickname for a command or shell script. Aliases take no
arguments.
Use aliases to save some typing, to give cryptic UNIX names a name that is easily
remembered, or to indicate a warning.
Preset Aliases
Preset aliases are defined by the ksh program. The user takes no action to get
preset aliases.
Defined Aliases
Defined aliases are commonly defined in .profile.
Tracked Aliases
Tracked aliases are defined for common shell commands the first time that shell
command is used. The KornShell can find a tracked alias faster than other
commands.
EY-G994E-SG-0002 3 – 13
UNIX Shell Programming Featuring KornShell
$ delete myfile
$ lst savefile
-rwxr-xr-x 1 sam staff 580 Jul 5 11:38 savefile
$ alias lst
lst = ls -l
$ alias
3 – 14 EY-G994E-SG-0002
Intermediate Shell Scripting
Exporting Aliases
To export an alias, use the –x option to the alias statement, as shown below.
Note that you cannot export an alias to a script that is invoked as an argument to
ksh.
Example
$ alias -x delete=’rm –i’ # export the delete alias
EY-G994E-SG-0002 3 – 15
UNIX Shell Programming Featuring KornShell
KornShell Functions
Function Definition
In the KornShell, a function is a named block of code. Like functions in other
languages, you can create KornShell functions that accept arguments and return
values. You can define a function inside a startup file, inside a large program, or
even as the sole contents of a file.
Many programmers place their KornShell functions in the .profile startup file,
as shown below.
Example
$ cat ui.fn
# A function that invokes the UIL compiler (part of Motif)
function ui
{
uil -o $1.uid $1.uil # invoke the UIL compiler
}
If you do not place a function in a startup file, you can use the dot command to
make that function available, as shown below.
$ . ui.fn # make the function accessible from the ksh cmd. line
Invoking a Function
A function is like a shell script built into the ksh process. Invoke a function as
you would invoke a script, for example:
$ ui abc # invoke the ui function, passing one argument
The preceding function invocation UIL compiled abc.uil to produce
abc.uid.
Notice that just like invoking a script, you can pass command line arguments to a
function. The command line arguments for scripts ($1, $2, $#, $*, etc.) can also
appear inside functions.
3 – 16 EY-G994E-SG-0002
Intermediate Shell Scripting
Debugging Functions
You can use the typeset –ft command to force an execution trace of a
function. An example is shown below.
Example
$ cat full.fn
#full- function to print the full pathname for the
#file given as an argument
function full
{
if [[ $1 != /* ]]
then
PathName=$PWD/$1
else
PathName=$1
fi
print $PathName
}
$ full abc
+ [[ abc != /* ]]
+ PathName=/usr/users/sam/abc
+ print /usr/users/sam/abc
/usr/users/sam/abc
To debug a function, you can also embed the set –o xtrace and set +o
xtrace pairs inside the function.
Exporting Functions
To export a function, use the –fx option with the typeset statement, as shown
below. Even if you export the function, scripts invoked as an argument to ksh will
not be able to access the function.
$ typeset –fx ui # export the ui function defined earlier
EY-G994E-SG-0002 3 – 17
UNIX Shell Programming Featuring KornShell
Default Execution
If you do make the preceding assignment, then the KornShell will execute the
following three scripts at login:
! /etc/profile
! ~/.profile
! ~/.kshrc
3 – 18 EY-G994E-SG-0002
Intermediate Shell Scripting
$ alias delete
delete=rm # defined from ~/.kshrc
$ cat myscript
alias delete # show value of exported alias
$ myscript
delete=rm -i
Executing ~/.kshrc
~/.kshrc executes in child ksh before myscript.
! Dual script environment exists for aliases and functions.
! Shell scripts that execute by name get exported aliases and functions defined
in login ksh.
! Shell scripts that execute as an argument to ksh get exported aliases and
functions defined in the $ENV file.
Example
$ ksh myscript
delete=rm
Autoloading Functions
Autoloading functions are an alternative to defining functions in ~/.profile or
the $ENV file. You can reduce startup time by delaying function definition until
needed.
EY-G994E-SG-0002 3 – 19
UNIX Shell Programming Featuring KornShell
3 – 20 EY-G994E-SG-0002
Intermediate Shell Scripting
EY-G994E-SG-0002 3 – 21
UNIX Shell Programming Featuring KornShell
function ma
{
DirFile=$HOME/.dir.data
Usage="Usage: ma [word]"
case $# in
0) print $(basename $PWD):$PWD >> $DirFile
;;
1) print $1:$PWD >> $DirFile
;;
*) print "Too many arguments." >&2
print $Usage >&2
;;
esac
}
The next example writes into DirFile myetc:/etc
$ cd /etc
$ ma myetc
The next example writes into DirFile sys:/usr/sys
$ cd /usr/sys
$ ma
3 – 22 EY-G994E-SG-0002
Intermediate Shell Scripting
function ga
{
DirFile=$HOME/.dir.data
Usage="Usage: ga word"
case $# in
1) d=$(grep "^$1:" $DirFile | awk -F: ’{print $2}’)
# Look for word in DirFile and set d = 2nd field
if [[ -n $d ]]
then
cd $d
print "New current directory is $(pwd)"
else
print "No entry for \"$1\" in $DirFile"
fi
;;
*) print "Too many arguments." >&2
print $Usage >&2
;;
esac
}
As shown below, the new current directory is /etc.
$ ga myetc
As shown below, the new current directory is /usr/sys.
$ ga sys
EY-G994E-SG-0002 3 – 23
UNIX Shell Programming Featuring KornShell
3 – 24 EY-G994E-SG-0002
Intermediate Shell Scripting
function la
{
DirFile=$HOME/.dir.data
Usage="Usage: la word"
case $# in
0) cat $DirFile
;;
1) e=$(grep $1 $DirFile)
if [[ -n $e ]] ; then
print $e
else
print "No entry for \"$1\" in DirFile"
fi
;;
*) print $Usage >&2
;;
esac
}
$ la sys
sys:/usr/sys
$ la
myetc:/etc
sys:/usr/sys
grep $1 $DirFile
Writes to stdout the line of the file that contains the value of the first positional
parameter. There should be only one such line in the file. This function has
problems if there are multiple lines that have the same token. The repair is left as
an exercise.
EY-G994E-SG-0002 3 – 25
UNIX Shell Programming Featuring KornShell
Another Example
This script prints the name and login shell of every user on the system.
Example
# !/usr/bin/ksh
USAGE=”usage: stats.ksh”
IFS=’:’
3 – 26 EY-G994E-SG-0002
Intermediate Shell Scripting
Summary
Executing a Script as a Sibling
By running a script as a sibling instead of a child, you can modify the parent’s
environment. Sibling scripts are run by invoking the dot command (.). The exec
command, although seldom used, replaces the parent shell with any other shell
command.
EY-G994E-SG-0002 3 – 27
UNIX Shell Programming Featuring KornShell
Exercises
Instructions
1. Create a function to change the permissions of a file to 600, invoke vi to edit
the file, and change the file permissions to 400.
2. Create a function to display the line(s) of the ps ax output that contain the
string specified as an argument, for example:
$ func inetd
should print:
143 ? I 0:00 /etc/inetd
Ensure that any ps lines created by the function execution are not printed for
example lines containing grep inetd.
3. Define the function llf and alias ll so that after logging out and logging in
again, they will be defined differently for shell scripts that are executed by
name or as an argument to ksh.
For scripts executed by name:
llf = ’ls -l $1’
ll = ’ls -l’
For scripts executed as an argument to ksh:
llf = ’ls -F $1’
ll = ’ls -F’
Test with a shell script containing the lines:
ll $1
llf $1
What is the effect if the following line is inserted as the first line of the shell
script?
#!/bin/ksh
4. Write a shell script using case which takes one or two command line
arguments. If two arguments are typed on the command line, the first is a file
name and the second is a directory name. Use find(1) to search for a file of
that name in the specified directory. If only one argument is typed on the
command line, it is a file name to be sought in the current working directory
tree.
5. Write a shell script to compile a source file whose name (without the .c) is
given on the command line. Additional command line arguments must begin
with a dash (-) and represent options for the compile command.
Note that options could occur before or after the file name, for example:
cc -g -o abc abc.c -lm
3 – 28 EY-G994E-SG-0002
Advanced Shell Scripting
Module 4
EY-G994E-SG-0002 4–1
UNIX Shell Programming Featuring KornShell
4–2 EY-G994E-SG-0002
Advanced Shell Scripting
Objectives
When you complete this module, you will be able to:
! Create and use menu processors
! Identify and use signals
! Handle signals in a shell script
! Use integer arithmetic
! Use floating-point arithmetic
! Create and use variable arrays
! Change the internal field separator
! Perform command evaluation using eval
! Use tools for shell scripts
! Set positional parameters
Resources
For more information on the topics in this module, refer to the following:
! Tru64 UNIX Reference Pages
! Command and Shell User’s Guide
! Kornshell Programming Tutorial, Barry Rosenberg, Reading, MA: Addison-
Wesley Publishing Co., 1991 (ISBN 0-201-56324-X)
! The Kornshell Command and Programming Language, Morris I. Bolsky and
David G. Korn, Englewood Cliffs, NJ: Prentice Hall, 1989 (ISBN 0-13-
516972-0)
EY-G994E-SG-0002 4–3
UNIX Shell Programming Featuring KornShell
Menu Processing
List Processing (select)
The following example uses the select command to display a menu to the user.
! A shell script fragment is shown at the top of the example. The execution of
that fragment is shown in the middle.
! For the first response, i=fries.
! Note that select is like an infinite loop. A break or exit is needed to
get out of the loop.
! Default value for $PS3 is #?.
Example
$ cat menuscript
PS3="Please enter the number for a food: "
select i in candy carrot fries spinach
do
case $i in
candy|fries) print "Poor choice"
;;
carrot|spinach) print "Good choice"
break
;;
*) print "invalid number"
;;
esac
done
$ menuscript
1) candy
2) carrot
3) fries
4) spinach
Please enter the number for a food: 3
Poor choice
Please enter the number for a food: 2
Good choice
4–4 EY-G994E-SG-0002
Advanced Shell Scripting
User Prompts
In the previous example:
! <RETURN> will redisplay the menu
! 5 (or any number not in the menu) would cause the variable i to be assigned
the value ""
Although the use of menus is a bit old fashioned, user prompts are useful when
menus will be used to indicate user preference. However, a graphical user interface
such as Motif is preferable.
Prompt Reminder
The following table shows the how to set the user prompts.
EY-G994E-SG-0002 4–5
UNIX Shell Programming Featuring KornShell
Signals
Introduction
Signals are sent to a process to inform it that an event has occurred. A process can
handle or ignore a signal. The default action for most signals is process
termination. A signal can only be sent to a process with the same UID as the
sender, although superuser can send a signal to any process.
4–6 EY-G994E-SG-0002
Tips and Tricks
Using setuid
Example
$ ls -l /usr/ucb/passwd
-rws--x--x 3 root bin 16384 Aug 8 19:49 /usr/ucb/passwd
$ passwd
Old password:
New password:
Verify:
This can be represented by:
login
passwd
ksh
Using sush
Example
/* sush.c program to run a KornShell script
whose name and arguments are given on
the cmd line. */
void
main(int argc, char *argv[])
{
strcpy(argv[0], "ksh");
if (execvp("ksh", argv) == -1) {
perror("sush error");
exit(1);
}
exit(0);
}
The following commands must be typed as superuser:
# cc -o sush sush.c
# chmod 4750 sush
# ls -l sush
-rwsr-x--- 1 root system 27916 Jan 4 10:55 sush
EY-G994E-SG-0002 5 – 17
UNIX Shell Programming Featuring KornShell
5 – 18 EY-G994E-SG-0002
Tips and Tricks
EY-G994E-SG-0002 5 – 19
UNIX Shell Programming Featuring KornShell
Exercise/Discussion
Consider the following.
Examples
$ cd ~$USER # ’~’ expanded before variable
~mary: No such file or directory
$ eval cd ~$USER # eval forces second pass
5 – 20 EY-G994E-SG-0002
Tips and Tricks
Co–processes
Definition
A co-process is a background job that is started in such a way that you can
communicate with it using read and print commands.
EY-G994E-SG-0002 5 – 21
UNIX Shell Programming Featuring KornShell
Co-process Diagram
The process can be represented as shown in Figure 5-1.
Figure 5-1 Co-process Diagram
print -p stdin
read -p
stout
5 – 22 EY-G994E-SG-0002
Tips and Tricks
$ cat program2
# program2
while true
do
read text
print "$text - this is from program2"
done
$ program1 |&
$ exec 3<&p
$ exec 4>&p
$ program2 |&
$ exec 5<&p
$ exec 6>&p
EY-G994E-SG-0002 5 – 23
UNIX Shell Programming Featuring KornShell
Using Co-processes
The following example preserves the co-process started in .profile and saves
the files in ~/trashcan. The original is deleted if the save is successful. Next,
it prints a success message or an error message to stdout. On exit, it archives all
files in ~/trashcan and deletes the saved versions. The signal handler archives
files, compress the archive, and deletes saved versions.
Example
# preserve
tf=obsolete.$(date +%d%m%y).$$ # name for archive
trap ’cd ~/trashcan
tar -cf ~/$tf * ;\
compress ~/$tf ;\
rm * ;\
exit’ TERM HUP INT STOP QUIT
while true # save the files and delete originals.
do
read file
if cp $file ~/trashcan 2>&1 # errors to stdout
then
rm $file
print "$file saved" # msg to stdout
fi
done
Single Quotes
Single quotes are essential in the signal handler to avoid expansion of the * wild
card as the signal handler is established with the trap command.
The if Command
The if statement checks the status return from the cp command. The file is
removed only if cp is successful. Errors from the cp command are written to
stdout, which is the channel back to the calling co-process.
If the function is called with a full pathname argument, the command substitution
prints nothing. $file is a full pathname.
EY-G994E-SG-0002 5 – 25
UNIX Shell Programming Featuring KornShell
5 – 26 EY-G994E-SG-0002
Tips and Tricks
if [[ -w /etc/passwd ]]
then
print "have write access to /etc/passwd"
fi
EY-G994E-SG-0002 5 – 27
UNIX Shell Programming Featuring KornShell
5 – 28 EY-G994E-SG-0002
Tips and Tricks
Performance
Improving Performance
The following are 11 tips for improving the performance of your KornShell
scripts:
1. Use KornShell built-ins rather than external programs whenever possible.
2. Use aliases rather than functions whenever possible.
3. Keep the $ENV file small. Remember, this file executes for all child
processes.
4. Use tracked aliases by setting the trackall option.
5. Set the nolog option to keep any function definitions out of the history list.
6. Use autoload functions.
7. Avoid creating child processes unnecessarily. Among other techniques,
consider:
! Using the . (dot) command to execute scripts where possible
! Using {} to group commands rather than () where possible
8. Declare variables as integer, whenever possible.
9. Use the semicolon to group related commands. The shell can process two or
three commands after reading a single line from the script file. But beware —
while this is generally good for performance, it can be very bad for
readability.
10. Document what your scripts do. The presence of comment lines seems to
have little or no effect on performance of a script, so you cannot use that as
an excuse not to document your scripts.
11. Use the time command to verify that your strategies have in fact enhanced
performance.
EY-G994E-SG-0002 5 – 29
UNIX Shell Programming Featuring KornShell
5 – 30 EY-G994E-SG-0002
Tips and Tricks
Using replay_opt
The following example shows how to use replay_opt to invoke a command
repeatedly.
Example
# replay_opt shell script to invoke a command repeatedly.
# The command is specified as a cmd line arg.
# Options:
# -d delay interval (default = 5 sec)
# -s size in number of lines (default=23 or LINES)
# -t show the tail of the display
# getopts is used to process the command options.
Delay=5 # delay interval
Tail="" # show tail of display
Size=${LINES:-23} # size of display
Usage="Usage: $0 [-d delay] [-s size] [-t] command"
trap ’clear; exit’ 1 2 3 15
EY-G994E-SG-0002 5 – 31
UNIX Shell Programming Featuring KornShell
Checking Commands
The following example shows checking commands.
Example
# Ensure a command was supplied
if [[ $# -eq 0 ]]
then
print "No command supplied" >&2
print $Usage >&2
exit 1
fi
5 – 32 EY-G994E-SG-0002
Tips and Tricks
A Better grep
The following script example invokes sed and makes it work like grep.
Example
# csed shell script to grep for a string in a file
# and display several lines about that line
# containing the string.
if [[ $# -ne 2 ]]
then
print "Usage: $(basename $0) pattern filename" >&2
exit 1
fi
sed -n -e "/$1/{x;p;x;p;n;p;}" -e h $2
# sed reads a line from the file into its pattern space and
# applies the sed command (-e args) to the lines that match.
# As the next line is read, the pattern space is copied into
# the hold space (by the hold command below);
#
# x exchange the contents of the pattern space
# and the hold space
# p print the contents of the pattern space
#
# n replace the pattern space with the next
# line of input
# h replace the contents of the hold space with
# the pattern space
#
# -n option suppress the file contents normally
# written to standard output
! $1 is the search pattern.
! $2 is the name of the file to be searched.
! /$1/ puts a line that has the search pattern into the pattern space.
EY-G994E-SG-0002 5 – 33
UNIX Shell Programming Featuring KornShell
5 – 34 EY-G994E-SG-0002
Tips and Tricks
Summary
Using Here Documents
A Here document consists of one or more lines of data presented to the command
when the command is invoked. Here documents can contain positional
parameters. Here documents can also spawn child shell scripts.
Exercises
Instructions
1. Write a shell script that uses getopts to convert an octal, decimal, or
hexadecimal number given on the command line to octal, decimal or
hexadecimal. The -r option takes an argument, o, d, or x, to indicate the
number base of the result (have the script assume a decimal result if the -r
option is not passed). The options -o, -d, or -x indicate the number base of
the input (have the script assume decimal input if none of these options is
passed). The following lab exercise is intended to be a challenge for you. It
illustrates advanced techniques and is not meant to be easy.
2. Write a shell script that will create co-processes to perform remote shell
commands to several hosts on the network simultaneously and log the results
of the commands in log files (one per remote host) on the local host. The
main script should report the pathnames of the log files on exit. The log file
names need to be unique and obvious (in other words, the host name should
be a part of the log file name). The script executing in each co-process will
obtain the name of the host and the name of the log file as command line
arguments. The main script will prompt the user for the command to be
executed remotely, then pass each command to all the co-processes via the
co-process’ standard input. Be sure that when the main script exits, it gives
co-processes time to finish any incomplete commands.
5 – 36 EY-G994E-SG-0002
Common Symbols
Appendix A
EY-G994E-SG-0002 A–1
UNIX Shell Programming Featuring KornShell
A–2 EY-G994E-SG-0002
Common Symbols
List of Symbols
Symbol Table
Table A-1 is a list of common symbols and their definitions.
EY-G994E-SG-0002 A–3
UNIX Shell Programming Featuring KornShell
A–4 EY-G994E-SG-0002
Lab Solutions
Appendix B
EY-G994E-SG-0002 B–1
UNIX Shell Programming Featuring KornShell
B–2 EY-G994E-SG-0002
Lab Solutions
echo $*
2.2 Solution
#! /bin/ksh
#
# Program which takes one argument, optionally backs it up,
and
# then invokes vi on the file specified.
#
if (( $# != 1))
then
print -u2 "$0 takes exactly one argument"
exit 1
fi
if [[ "$ans" != "n" ]]
then
cp $1 $1.backup
fi
vi $1
EY-G994E-SG-0002 B–3
UNIX Shell Programming Featuring KornShell
2.3 Solution
#! /bin/ksh
#
# Script for entering data into a phone list.
#
LIST=./phonelist
read first?"Enter the first name (quit to quit): "
while [[ "$first" != quit ]]
do
read last?"Enter the last name: "
read extension?"Enter the phone extension: "
print $first $last $extension >> $LIST
read first?"Enter the first name (quit to quit): "
done
B–4 EY-G994E-SG-0002
Lab Solutions
2.4 Solution
Script started on Sat Jan 1 02:41:15 2000
$ dirtest /etc /etc/motd /mnt
sh: ./dirtest: Permission denied
$ chmod +x dirtest
$ dirtest /etc /etc/motd /mnt
./dirtest[3]: syntax error at line 4 : `if' unexpected
$ vi dirtest
$ cat dirtest
#!/bin/ksh
#dirtest - shell script with bugs
for i
do
if (-d i)
print "$i is a directory"
else
print "$1 is not a directory"
endif
end
$ dirtest /etc /etc/motd /mnt
./dirtest[3]: syntax error at line 8 : `else' unexpected
$ vi +8 dirtest
$ cat dirtest
#!/bin/ksh
#dirtest - shell script with bugs
for i
do
if (-d i)
then
print "$i is a directory"
else
print "$1 is not a directory"
endif
end
$ dirtest /etc /etc/motd /mnt
./dirtest[3]: syntax error at line 8 : `else' unmatched
$ vi +8 dirtest
$ cat dirtest
#!/bin/ksh
#dirtest - shell script with bugs
for i
do
if (-d i)
then
print "$i is a directory"
else
print "$1 is not a directory"
fi
end
EY-G994E-SG-0002 B–5
UNIX Shell Programming Featuring KornShell
B–6 EY-G994E-SG-0002
Lab Solutions
EY-G994E-SG-0002 B–7
UNIX Shell Programming Featuring KornShell
2.5 Solution
#! /bin/ksh
#
# A script doing file testing, illustrating many if statements
#
USAGE1="Usage: $0 [-r|-w] file"
USAGE2="If neither -r nor -w are supplied, -r is assumed."
# do the test
if [[ ! -f "$file" ]]
then
print "$file does not exist"
exit 0
fi
B–8 EY-G994E-SG-0002
Lab Solutions
2.6 Solution
#! /bin/ksh
#
# Back up lots of files. If we are not told which files to
back up,
# do all in the current directory.
#
if (( $# > 0 ))
then
files=$*
else
files=*
fi
2.7 Solution
#! /bin/ksh
ps -e | tail +1 | cut -c1-12 | sort -n
EY-G994E-SG-0002 B–9
UNIX Shell Programming Featuring KornShell
3.2 Solution
#! /bin/ksh
#
# function to extract certain lines from ps
#
function psg {
# The last grep prevents the 2nd grep from appearing in
the ps
# listing. We have to be careul; what if we are called
with "grep"
# as an argument?
ps ax | grep $1 | grep -v "grep $1"
}
3.4 Solution
#! /bin/ksh
#
# Script to locate a file either below the current dir or
below a
# dir specified by the user
case $# in
1) find . -name $1 -print ;;
2) find $2 -name $1 -print ;;
*) print -u2 "Usage: $0 file [dir]"
exit 1;;
esac
B – 10 EY-G994E-SG-0002
Lab Solutions
function byebye {
print -u2 "Caught a signal. Exiting."
exit 1
}
4.2 Solution
#! /bin/ksh
# print the hexadecimal of a decimal integer in $1
print "obase=16\n$1" | bc
#
# or
#
typeset -i16 hex
hex=$1
print $hex
EY-G994E-SG-0002 B – 11
UNIX Shell Programming Featuring KornShell
4.3 Solution
#! /bin/ksh
#
# A script illustrating arithmetic operations and non-base-
10 #integers.
#
typeset -i2 binary
n=$1
while (( $n != 1 ))
do
if (( $n % 2 == 0 ))
then
(( n = $n / 2 ))
else
binary=$n
print "$n $binary"
(( n = $n * 3 + 1 ))
fi
done
4.4 Solution
#! /bin/ksh
#
# Produce a histogram of the values in the array hist.
#
for value in ${hist[*]}
do
n=0
while (( $n < $value ))
do
print -n "*"
(( n = $n + 1 ))
done
print
done
B – 12 EY-G994E-SG-0002
Lab Solutions
4.5 Solution
#! /bin/ksh
#
# A replacement for rm whch stores the files in $TRASH,
compressed
# with a timestamp
#
TRASH=~/trashcan
if [[ ! -d $TRASH ]]
then
mkdir $TRASH
fi
for file
do
stamp=`date +%Y%m%d%H%M%S`
newfile=$TRASH/$file.$stamp
mv $file $newfile
compress $newfile
done
4.6 Solution
#! /bin/ksh
#
# Script which un-trashes a file trashed by the prior lab
exercise
#
for file
do
for possible in ~/trashcan/$file.*
do
local=${possible##*/}
read ans?"restore $local? [y/n]"
if [[ "$ans" = y ]]
then
mv $possible .
uncompress $local
local=${local%.Z} # uncompressed, it no longer ends in .Z
# remove timestamp
mv $local ${local%.[0-9]*}
break
fi
done
done
EY-G994E-SG-0002 B – 13
UNIX Shell Programming Featuring KornShell
ibase=10
obase=10
while getopts :r:odx opt
do
case $opt in
o) ibase=8;;
d) ibase=10;;
x) ibase=16;;
r) case $OPTARG in
o) obase=8;;
d) obase=10;;
x) obase=16;;
*) print -u2 "Unknown result base specified in
'$OPTARG'\n$USAGE"
exit 1;;
esac;;
:) print -u2 "Missing base for result.\n$USAGE"
exit 1;;
\?) print -u2 "Unknown argument '$OPTARG'\n$USAGE"
exit 1;;
esac
done
shift $OPTIND-1
B – 14 EY-G994E-SG-0002
Lab Solutions
5.2 Solution
#! /bin/ksh
#
# Run commands on multiple machines.
#
# The remote machines are specified as arguments on the
command
# line.
function die {
print -u2 $*
exit 1
}
# main loop
while read command?"Command to execute: "
do
fd=3
while (( $fd <= $topfd ))
do
print -u$fd "$command"
(( fd = $fd + 1 ))
done
done
EY-G994E-SG-0002 B – 15
UNIX Shell Programming Featuring KornShell
B – 16 EY-G994E-SG-0002
Tips and Tricks
Using setuid
Example
$ ls -l /usr/ucb/passwd
-rws--x--x 3 root bin 16384 Aug 8 19:49 /usr/ucb/passwd
$ passwd
Old password:
New password:
Verify:
This can be represented by:
login
passwd
ksh
Using sush
Example
/* sush.c program to run a KornShell script
whose name and arguments are given on
the cmd line. */
void
main(int argc, char *argv[])
{
strcpy(argv[0], "ksh");
if (execvp("ksh", argv) == -1) {
perror("sush error");
exit(1);
}
exit(0);
}
The following commands must be typed as superuser:
# cc -o sush sush.c
# chmod 4750 sush
# ls -l sush
-rwsr-x--- 1 root system 27916 Jan 4 10:55 sush
EY-G994E-SG-0002 5 – 17
UNIX Shell Programming Featuring KornShell
5 – 18 EY-G994E-SG-0002
Tips and Tricks
EY-G994E-SG-0002 5 – 19
UNIX Shell Programming Featuring KornShell
Exercise/Discussion
Consider the following.
Examples
$ cd ~$USER # ’~’ expanded before variable
~mary: No such file or directory
$ eval cd ~$USER # eval forces second pass
5 – 20 EY-G994E-SG-0002
Tips and Tricks
Co–processes
Definition
A co-process is a background job that is started in such a way that you can
communicate with it using read and print commands.
EY-G994E-SG-0002 5 – 21
UNIX Shell Programming Featuring KornShell
Co-process Diagram
The process can be represented as shown in Figure 5-1.
Figure 5-1 Co-process Diagram
print -p stdin
read -p
stout
5 – 22 EY-G994E-SG-0002
Tips and Tricks
$ cat program2
# program2
while true
do
read text
print "$text - this is from program2"
done
$ program1 |&
$ exec 3<&p
$ exec 4>&p
$ program2 |&
$ exec 5<&p
$ exec 6>&p
EY-G994E-SG-0002 5 – 23
UNIX Shell Programming Featuring KornShell
Using Co-processes
The following example preserves the co-process started in .profile and saves
the files in ~/trashcan. The original is deleted if the save is successful. Next,
it prints a success message or an error message to stdout. On exit, it archives all
files in ~/trashcan and deletes the saved versions. The signal handler archives
files, compress the archive, and deletes saved versions.
Example
# preserve
tf=obsolete.$(date +%d%m%y).$$ # name for archive
trap ’cd ~/trashcan
tar -cf ~/$tf * ;\
compress ~/$tf ;\
rm * ;\
exit’ TERM HUP INT STOP QUIT
while true # save the files and delete originals.
do
read file
if cp $file ~/trashcan 2>&1 # errors to stdout
then
rm $file
print "$file saved" # msg to stdout
fi
done
Single Quotes
Single quotes are essential in the signal handler to avoid expansion of the * wild
card as the signal handler is established with the trap command.
The if Command
The if statement checks the status return from the cp command. The file is
removed only if cp is successful. Errors from the cp command are written to
stdout, which is the channel back to the calling co-process.
If the function is called with a full pathname argument, the command substitution
prints nothing. $file is a full pathname.
EY-G994E-SG-0002 5 – 25
UNIX Shell Programming Featuring KornShell
5 – 26 EY-G994E-SG-0002
Tips and Tricks
if [[ -w /etc/passwd ]]
then
print "have write access to /etc/passwd"
fi
EY-G994E-SG-0002 5 – 27
UNIX Shell Programming Featuring KornShell
5 – 28 EY-G994E-SG-0002
Tips and Tricks
Performance
Improving Performance
The following are 11 tips for improving the performance of your KornShell
scripts:
1. Use KornShell built-ins rather than external programs whenever possible.
2. Use aliases rather than functions whenever possible.
3. Keep the $ENV file small. Remember, this file executes for all child
processes.
4. Use tracked aliases by setting the trackall option.
5. Set the nolog option to keep any function definitions out of the history list.
6. Use autoload functions.
7. Avoid creating child processes unnecessarily. Among other techniques,
consider:
! Using the . (dot) command to execute scripts where possible
! Using {} to group commands rather than () where possible
8. Declare variables as integer, whenever possible.
9. Use the semicolon to group related commands. The shell can process two or
three commands after reading a single line from the script file. But beware —
while this is generally good for performance, it can be very bad for
readability.
10. Document what your scripts do. The presence of comment lines seems to
have little or no effect on performance of a script, so you cannot use that as
an excuse not to document your scripts.
11. Use the time command to verify that your strategies have in fact enhanced
performance.
EY-G994E-SG-0002 5 – 29
UNIX Shell Programming Featuring KornShell
5 – 30 EY-G994E-SG-0002
Tips and Tricks
Using replay_opt
The following example shows how to use replay_opt to invoke a command
repeatedly.
Example
# replay_opt shell script to invoke a command repeatedly.
# The command is specified as a cmd line arg.
# Options:
# -d delay interval (default = 5 sec)
# -s size in number of lines (default=23 or LINES)
# -t show the tail of the display
# getopts is used to process the command options.
Delay=5 # delay interval
Tail="" # show tail of display
Size=${LINES:-23} # size of display
Usage="Usage: $0 [-d delay] [-s size] [-t] command"
trap ’clear; exit’ 1 2 3 15
EY-G994E-SG-0002 5 – 31
UNIX Shell Programming Featuring KornShell
Checking Commands
The following example shows checking commands.
Example
# Ensure a command was supplied
if [[ $# -eq 0 ]]
then
print "No command supplied" >&2
print $Usage >&2
exit 1
fi
5 – 32 EY-G994E-SG-0002
Tips and Tricks
A Better grep
The following script example invokes sed and makes it work like grep.
Example
# csed shell script to grep for a string in a file
# and display several lines about that line
# containing the string.
if [[ $# -ne 2 ]]
then
print "Usage: $(basename $0) pattern filename" >&2
exit 1
fi
sed -n -e "/$1/{x;p;x;p;n;p;}" -e h $2
# sed reads a line from the file into its pattern space and
# applies the sed command (-e args) to the lines that match.
# As the next line is read, the pattern space is copied into
# the hold space (by the hold command below);
#
# x exchange the contents of the pattern space
# and the hold space
# p print the contents of the pattern space
#
# n replace the pattern space with the next
# line of input
# h replace the contents of the hold space with
# the pattern space
#
# -n option suppress the file contents normally
# written to standard output
! $1 is the search pattern.
! $2 is the name of the file to be searched.
! /$1/ puts a line that has the search pattern into the pattern space.
EY-G994E-SG-0002 5 – 33
UNIX Shell Programming Featuring KornShell
5 – 34 EY-G994E-SG-0002
Tips and Tricks
Summary
Using Here Documents
A Here document consists of one or more lines of data presented to the command
when the command is invoked. Here documents can contain positional
parameters. Here documents can also spawn child shell scripts.
Exercises
Instructions
1. Write a shell script that uses getopts to convert an octal, decimal, or
hexadecimal number given on the command line to octal, decimal or
hexadecimal. The -r option takes an argument, o, d, or x, to indicate the
number base of the result (have the script assume a decimal result if the -r
option is not passed). The options -o, -d, or -x indicate the number base of
the input (have the script assume decimal input if none of these options is
passed). The following lab exercise is intended to be a challenge for you. It
illustrates advanced techniques and is not meant to be easy.
2. Write a shell script that will create co-processes to perform remote shell
commands to several hosts on the network simultaneously and log the results
of the commands in log files (one per remote host) on the local host. The
main script should report the pathnames of the log files on exit. The log file
names need to be unique and obvious (in other words, the host name should
be a part of the log file name). The script executing in each co-process will
obtain the name of the host and the name of the log file as command line
arguments. The main script will prompt the user for the command to be
executed remotely, then pass each command to all the co-processes via the
co-process’ standard input. Be sure that when the main script exits, it gives
co-processes time to finish any incomplete commands.
5 – 36 EY-G994E-SG-0002
Common Symbols
Appendix A
EY-G994E-SG-0002 A–1
UNIX Shell Programming Featuring KornShell
A–2 EY-G994E-SG-0002
Common Symbols
List of Symbols
Symbol Table
Table A-1 is a list of common symbols and their definitions.
EY-G994E-SG-0002 A–3
UNIX Shell Programming Featuring KornShell
A–4 EY-G994E-SG-0002
Lab Solutions
Appendix B
EY-G994E-SG-0002 B–1
UNIX Shell Programming Featuring KornShell
B–2 EY-G994E-SG-0002
Lab Solutions
echo $*
2.2 Solution
#! /bin/ksh
#
# Program which takes one argument, optionally backs it up,
and
# then invokes vi on the file specified.
#
if (( $# != 1))
then
print -u2 "$0 takes exactly one argument"
exit 1
fi
if [[ "$ans" != "n" ]]
then
cp $1 $1.backup
fi
vi $1
EY-G994E-SG-0002 B–3
UNIX Shell Programming Featuring KornShell
2.3 Solution
#! /bin/ksh
#
# Script for entering data into a phone list.
#
LIST=./phonelist
read first?"Enter the first name (quit to quit): "
while [[ "$first" != quit ]]
do
read last?"Enter the last name: "
read extension?"Enter the phone extension: "
print $first $last $extension >> $LIST
read first?"Enter the first name (quit to quit): "
done
B–4 EY-G994E-SG-0002
Lab Solutions
2.4 Solution
Script started on Sat Jan 1 02:41:15 2000
$ dirtest /etc /etc/motd /mnt
sh: ./dirtest: Permission denied
$ chmod +x dirtest
$ dirtest /etc /etc/motd /mnt
./dirtest[3]: syntax error at line 4 : `if' unexpected
$ vi dirtest
$ cat dirtest
#!/bin/ksh
#dirtest - shell script with bugs
for i
do
if (-d i)
print "$i is a directory"
else
print "$1 is not a directory"
endif
end
$ dirtest /etc /etc/motd /mnt
./dirtest[3]: syntax error at line 8 : `else' unexpected
$ vi +8 dirtest
$ cat dirtest
#!/bin/ksh
#dirtest - shell script with bugs
for i
do
if (-d i)
then
print "$i is a directory"
else
print "$1 is not a directory"
endif
end
$ dirtest /etc /etc/motd /mnt
./dirtest[3]: syntax error at line 8 : `else' unmatched
$ vi +8 dirtest
$ cat dirtest
#!/bin/ksh
#dirtest - shell script with bugs
for i
do
if (-d i)
then
print "$i is a directory"
else
print "$1 is not a directory"
fi
end
EY-G994E-SG-0002 B–5
UNIX Shell Programming Featuring KornShell
B–6 EY-G994E-SG-0002
Lab Solutions
EY-G994E-SG-0002 B–7
UNIX Shell Programming Featuring KornShell
2.5 Solution
#! /bin/ksh
#
# A script doing file testing, illustrating many if statements
#
USAGE1="Usage: $0 [-r|-w] file"
USAGE2="If neither -r nor -w are supplied, -r is assumed."
# do the test
if [[ ! -f "$file" ]]
then
print "$file does not exist"
exit 0
fi
B–8 EY-G994E-SG-0002
Lab Solutions
2.6 Solution
#! /bin/ksh
#
# Back up lots of files. If we are not told which files to
back up,
# do all in the current directory.
#
if (( $# > 0 ))
then
files=$*
else
files=*
fi
2.7 Solution
#! /bin/ksh
ps -e | tail +1 | cut -c1-12 | sort -n
EY-G994E-SG-0002 B–9
UNIX Shell Programming Featuring KornShell
3.2 Solution
#! /bin/ksh
#
# function to extract certain lines from ps
#
function psg {
# The last grep prevents the 2nd grep from appearing in
the ps
# listing. We have to be careul; what if we are called
with "grep"
# as an argument?
ps ax | grep $1 | grep -v "grep $1"
}
3.4 Solution
#! /bin/ksh
#
# Script to locate a file either below the current dir or
below a
# dir specified by the user
case $# in
1) find . -name $1 -print ;;
2) find $2 -name $1 -print ;;
*) print -u2 "Usage: $0 file [dir]"
exit 1;;
esac
B – 10 EY-G994E-SG-0002
Lab Solutions
function byebye {
print -u2 "Caught a signal. Exiting."
exit 1
}
4.2 Solution
#! /bin/ksh
# print the hexadecimal of a decimal integer in $1
print "obase=16\n$1" | bc
#
# or
#
typeset -i16 hex
hex=$1
print $hex
EY-G994E-SG-0002 B – 11
UNIX Shell Programming Featuring KornShell
4.3 Solution
#! /bin/ksh
#
# A script illustrating arithmetic operations and non-base-
10 #integers.
#
typeset -i2 binary
n=$1
while (( $n != 1 ))
do
if (( $n % 2 == 0 ))
then
(( n = $n / 2 ))
else
binary=$n
print "$n $binary"
(( n = $n * 3 + 1 ))
fi
done
4.4 Solution
#! /bin/ksh
#
# Produce a histogram of the values in the array hist.
#
for value in ${hist[*]}
do
n=0
while (( $n < $value ))
do
print -n "*"
(( n = $n + 1 ))
done
print
done
B – 12 EY-G994E-SG-0002
Lab Solutions
4.5 Solution
#! /bin/ksh
#
# A replacement for rm whch stores the files in $TRASH,
compressed
# with a timestamp
#
TRASH=~/trashcan
if [[ ! -d $TRASH ]]
then
mkdir $TRASH
fi
for file
do
stamp=`date +%Y%m%d%H%M%S`
newfile=$TRASH/$file.$stamp
mv $file $newfile
compress $newfile
done
4.6 Solution
#! /bin/ksh
#
# Script which un-trashes a file trashed by the prior lab
exercise
#
for file
do
for possible in ~/trashcan/$file.*
do
local=${possible##*/}
read ans?"restore $local? [y/n]"
if [[ "$ans" = y ]]
then
mv $possible .
uncompress $local
local=${local%.Z} # uncompressed, it no longer ends in .Z
# remove timestamp
mv $local ${local%.[0-9]*}
break
fi
done
done
EY-G994E-SG-0002 B – 13
UNIX Shell Programming Featuring KornShell
ibase=10
obase=10
while getopts :r:odx opt
do
case $opt in
o) ibase=8;;
d) ibase=10;;
x) ibase=16;;
r) case $OPTARG in
o) obase=8;;
d) obase=10;;
x) obase=16;;
*) print -u2 "Unknown result base specified in
'$OPTARG'\n$USAGE"
exit 1;;
esac;;
:) print -u2 "Missing base for result.\n$USAGE"
exit 1;;
\?) print -u2 "Unknown argument '$OPTARG'\n$USAGE"
exit 1;;
esac
done
shift $OPTIND-1
B – 14 EY-G994E-SG-0002
Lab Solutions
5.2 Solution
#! /bin/ksh
#
# Run commands on multiple machines.
#
# The remote machines are specified as arguments on the
command
# line.
function die {
print -u2 $*
exit 1
}
# main loop
while read command?"Command to execute: "
do
fd=3
while (( $fd <= $topfd ))
do
print -u$fd "$command"
(( fd = $fd + 1 ))
done
done
EY-G994E-SG-0002 B – 15
UNIX Shell Programming Featuring KornShell
B – 16 EY-G994E-SG-0002