\documentclass{ictlab} \RCS $Revision: 1.2 $ \usepackage{alltt,key,color,amstext,answer2,float} \usepackage[nooneline,hang,bf]{caption2} \ifx\pdftexversion\undefined \else \usepackage[pdfpagemode=None,pdfauthor={Nick Urbanik}]{hyperref} \fi \renewcommand*{\subject}{Operating Systems and Systems Integration} \newcommand*{\labTitle}{Lab 4, 5 Shell Programming Supplement} \definecolor{light-blue}{rgb}{0.4,0.4,1} \newcommand*{\gl}[1]{\textcolor{light-blue}{#1}} % good link \newcommand*{\ex}[1]{\textcolor{green}{#1}} % executable file \newcommand*{\bl}[1]{\colorbox{red}{\textcolor{white}{\textbf{#1}}}} % bad link \renewcommand{\floatpagefraction}{0.75} % default is .5, to increase % density. \renewcommand*{\bottomfraction}{0.6} % default is 0.3 \renewcommand*{\topfraction}{0.85} % default is 0.7 \renewcommand*{\textfraction}{0.1} % default is 0.2 \setlength{\extrarowheight}{1pt} \floatstyle{ruled} \floatname{program}{Script} \newfloat{program}{tbh}{lop} \begin{document} \section{Exercise 1} \label{sec:exercise-1} \begin{enumerate} \item Make a directory $\sim$\texttt{/bin} in your home directory: \begin{alltt} $ \textbf{cd} $ \textbf{mkdir bin} \end{alltt} \item Copy the following files from the network directory \texttt{/home/nfs/ossi-part-time/scripts} to your $\sim$\texttt{/bin} directory: \begin{alltt} $ \textbf{cp -a /home/nfs/ossi-part-time/scripts/* \(\sim\)/bin} \end{alltt}%$ \item Run and understand each of demo files: \begin{itemize} \item \texttt{var1} (see script~\vref{prg:var1.sh}), \texttt{var2} (see script~\vref{prg:var2.sh}), \texttt{var3} (see script~\vref{prg:var3.sh}) \item \texttt{if1} (see script~\vref{prg:if1.sh}), \texttt{if2} (see script~\vref{prg:if2.sh}) \item \texttt{arith} (see script~\vref{prg:arith.sh}) \item \texttt{loop} (see script~\vref{prg:loop.sh}), \texttt{loop2} (see script~\vref{prg:loop2.sh}) \item \texttt{case} (see script~\vref{prg:case.sh}) \item \texttt{file1} (see script~\vref{prg:file1.sh}), \texttt{file2} (see script~\vref{prg:file2.sh}) \end{itemize} \end{enumerate} \section{Exercise 2} \label{sec:exercise-2} \begin{enumerate} \item Write a script which displays ``\texttt{Good morning}'', ``\texttt{Good afternoon}'' or ``\texttt{Good evening}'', on the monitor, depending on the time of running the script. \begin{explanation} Have a look at the \texttt{date} command: do \texttt{man date}. You will see that there are options to output the time in any format; for example, \texttt{date +\%j} will print what day of the year today is, i.e., from 1 to 366. You will probably want to use \emph{command substitution}, i.e., use \emph{backticks}, \texttt{`...`} that is the single quotes on the left of your keyboard. There is an example on Joe's slide ``shell variable (2), slide 13 of the latest PowerPoint slides on shell scripting, and also in script~\vref{prg:var2.sh}, and script~\vref{prg:loop.sh}, where it is used with the external \texttt{expr} command to do arithmetic, as an alternative to the (easier) built in \texttt{let} command. Of course, you will also need to use an \texttt{if}\ldots\texttt{elif}\ldots\texttt{else}\ldots\texttt{fi} statement; see script~\vref{prg:if2.sh}. \end{explanation} \end{enumerate} \section{Exercise 3} \label{sec:exercise-3} Write a script which: \begin{enumerate} \item prompts to read your name and age: \begin{alltt} Enter your name: \textbf{Joe} Enter your age: \textbf{25} \end{alltt} \begin{explanation} Use the built in \texttt{read} command to read input from the user. Use \texttt{echo -n} to print the prompt without a newline at the end. See script~\vref{prg:if2.sh} and script~\vref{prg:loop.sh}. \end{explanation} \item Write the read name to the first line of a file named \texttt{my\_info}. \begin{explanation} Use file redirection (\texttt{>}) to do this. \end{explanation} \item Change your age to $\text{age}\times 3-3$ and write the value to the second line of \texttt{my\_info}. \begin{explanation} You can use \texttt{let} to do the arithemtic. Use file redirection with appending (\texttt{>>}) to do this. \end{explanation} \item Content of \texttt{my\_info}: \begin{alltt} my name is Joe my modified age is 72 \end{alltt} \end{enumerate} \section{Exercise 4} \label{sec:exercise-4} \begin{enumerate} \item Write a script which reads a number in units of seconds and converts it to the units hours:minutes:seconds and prints the result to standard output. \item Your script must prompt for re-input if a negative value is input \begin{alltt} Enter number of seconds: 12345 Result: 12345 seconds is 3:25:45 \end{alltt} \begin{explanation} This is an exercise in arithmetic evaluation. The best bet is to use the built in \texttt{let} command, but you could also use the external \texttt{eval} command with command substitution (i.e., backticks \texttt{`...`}). You will also need a loop to prompt for re-input. \end{explanation} \end{enumerate} \section{Exercise 5} \label{sec:exercise-5} \begin{enumerate} \item Write a script \texttt{calculate}, which accepts 4 arguments \emph{a}, \emph{b}, \emph{c}, \emph{d} and prints the value of $a \times 20-b\times 2+c\div d$ to standard output. \item An example of executing the script: \begin{alltt} $ \textbf{calculate 2 12 5 2} result of "2*20 - 12*2 + 5/2" is 18 \end{alltt}%$ \begin{explanation} This is an exercise in arithmetic evaluation. The best bet is to use the built in \texttt{let} command. \end{explanation} \end{enumerate} \appendix \section{The Shell Script Examples} \label{sec:examples} \begin{program} \begin{verbatim} #! /bin/sh # This script shows how changes to variables made by a script # disappear after execution of the script. echo "Before re-assignment by this script, environment variable \$HOME is $HOME" HOME=/root echo "After re-assignment by this script, environment variable \$HOME is $HOME" echo "After execution of this script, echo \$HOME" \end{verbatim} \caption{The script \texttt{var1} shows how variable settings disappear after a script stops running.} \label{prg:var1.sh} \end{program} \begin{program} \begin{verbatim} #! /bin/sh # This script shows how to use variables. # Variable declaration and assignment: VAR1=abc VAR2="this is a variable" VAR3="today is `date` and VAR1 is $VAR1" VAR4="\$VAR1" # display content of variables: echo "VAR1 is ${VAR1}" echo "VAR2 is ${VAR2}" echo "VAR3 is ${VAR3}" echo "VAR4 is ${VAR4}" echo "dollar sign is \$, backquote is \`, backslash is \\" \end{verbatim}%$ \caption{\texttt{var2} shows how variables are assigned and read.} \label{prg:var2.sh} \end{program} \begin{program} \begin{verbatim} #!/bin/sh # This script shows the use of positional parameters # Please run with 4 parameters, like this: # var3 first_parameter second third fourth echo "command name is $0" echo "1st parameter is $1" echo "2nd parameter is $2" echo "3rd parameter is $3" echo "4th parameter is $4" echo "total number of parameters is $#" \end{verbatim} \caption{\texttt{var3} shows handling of command line parameters.} \label{prg:var3.sh} \end{program} \begin{program} \begin{verbatim} #!/bin/sh echo -n "input an integer (1 to 10): " read INPUT_VAR if [ $INPUT_VAR -le 5 ] then echo "input less than or equal to 5" else echo "input is greater than 5" fi \end{verbatim}%$ \caption{\texttt{{if1} shows a basic application of an \texttt{if}\ldots\texttt{else} statement.}} \label{prg:if1.sh} \end{program} \begin{program} \begin{verbatim} #!/bin/sh echo -n "input an integer (1 to 10): " read INPUT_VAR if [ $INPUT_VAR -le 2 ] then echo "input less than or equal to 2" elif [ $INPUT_VAR -lt 4 ] && [ $INPUT_VAR -gt 2 ] then echo "2 < input < 4" else echo "input >= 4 " fi \end{verbatim} \caption{\texttt{if2} shows the use of \texttt{if}\ldots\texttt{elif}\ldots\texttt{fi}, and also shows one use of the ``\texttt{\&\&}'' operator.} \label{prg:if2.sh} \end{program} \begin{program} \begin{verbatim} #!/bin/sh # let works with + - * / % #note that there are no spaces on either the left or right side # of +, - , *, / , %, unless you quote the expression. # let SUM=1 + 2 (this is wrong) let "SUM = 1 + 2" # Okay, since quoted the spaces let SUM=1+2 # okay, no spaces, no need for quotes let SUB=5-1 let MUL=2*5 let DIV=10/3 let REMAINDER=10%3 let 'EQUATION = 1 + 2 - 5 * 4 / 10' echo "SUM is ${SUM}" echo "SUB is ${SUB}" echo "MUL is ${MUL}" echo "DIV is ${DIV}" echo "REMAINDER is ${REMAINDER}" echo "EQUATION is ${EQUATION}" \end{verbatim} \caption{\texttt{arith} shows how to use \texttt{let} to assign arithmetic experssions to variables.} \label{prg:arith.sh} \end{program} \begin{program} \begin{verbatim} #!/bin/sh echo "input an integer less than 4" read VAR n=0 while [ $VAR -lt 10 ] do VAR=`expr $VAR + 1` n=`expr $n + 1` echo "loop $n: VAR is currently equal to $VAR" done \end{verbatim}%$ \caption{\texttt{loop} shows the use of a \texttt{while} loop, and also shows the use of the external program \texttt{expr} as an alternative to using \texttt{let}. Note that \texttt{expr} is more portable, but \texttt{let} is easier to use.} \label{prg:loop.sh} \end{program} \begin{program} \begin{verbatim} #!/bin/sh echo "input an integer less than 4" read VAR n=0 while [ $VAR -lt 10 ] do let "VAR = VAR + 1" let "n = n + 1" echo "loop $n: VAR is currently equal to $VAR" done \end{verbatim}%$ \caption{\texttt{loop2} is the same as script {prg:loop1.sh}, but uses \texttt{let} instead of \texttt{expr}.} \label{prg:loop2.sh} \end{program} \begin{program} \begin{verbatim} #!/bin/sh #case control flow echo -n "input any integer: " read VAR case $VAR in "1") echo "input is 1" ;; "2") echo "input is 2" ;; "3") echo "input is 3" ;; "4") echo "input is 4" ;; "5") echo "input is 5" ;; "6") echo "input is 6" ;; "7") echo "input is 7" ;; "8") echo "input is 8" ;; "9") echo "input is 9" ;; "10") echo "input is 10" ;; *) echo "input is greater than 10" ;; #default case esac \end{verbatim}%$ \caption{\texttt{case} shows how to use the \texttt{case} statement.} \label{prg:case.sh} \end{program} \begin{program} \begin{verbatim} #!/bin/sh # first create a file (test) for writing # then appending to this file # open a file (test) for writing and assign a file descriptor 3 to this file # file descriptor is used later for identifying this file # if this file does not exist, it will be created: exec 3>test #redirect all std output of any command to this opened file (test) echo "message redirect from std out to file (test)" 1>&3 # close opened file: exec 3>&- # open a file (test) for appending and assign a file descriptor 4 to this file # file descriptor is used later for identifying this file exec 4>>test #redirect all std output of any command to this opened file (test) echo "appended message redirect from std out to file (test)" 1>&4 # close opened file: exec 4>&- \end{verbatim} \caption{\texttt{file1} shows techniques you can use to write to more than one file at a time.} \label{prg:file1.sh} \end{program} \begin{program} \begin{verbatim} #!/bin/sh #read content of a file line by line and echo read line to monitor # Open an existed file (test) for reading and # assign a file descriptor 3 to this file. # File descriptor is used later for identifying this file exec 3&- \end{verbatim}%$ \caption{This script, \texttt{file2}, combines the use of \texttt{read} with a \texttt{while} loop, and some fancy file redirection.} \label{prg:file2.sh} \end{program} \end{document}