\chapter{Basic Shell} \label{cha:basic-shell-and-tools-approach} {\mns \subsection{Objectives} On completion of this module, you should be able to understand and use the Linux shell to create and combine tools. Topics covered include: \begin{itemize} \item An overview of the command line % (tick, cli 1,) \item The software tools model % (tick, overview & tools) \item File names and types % Nothing \item Shell programming % ??? \item Command scripts % ??? \item Job control % (tick, job controls) \item I/O --- pipes and redirection % (tick, overview, cli, tools) \end{itemize} \section{Introduction} \label{sec:basic-shell-and-tools-approach-intro} \begin{itemize} \item The standard command line interpreter under Linux is {\pgn bash} ({\fn /bin/bash} or {\fn /bin/sh}) \item An enhanced version of the classic Bourne shell \item Shares most features of other shells ({\pgn C}, {\pgn Korn}, etc) and has some more advanced features \begin{itemize} \item `Plumbing' --- transparent redirection and pipes \item Background processes \item Process suspension, resumption, termination \item Filename completion and wildcard generation \item History \end {itemize} \end {itemize} \section{Getting around the command line} \label{sec:basic-shell-and-tools-approach-getting-around} \begin{itemize} \item You can use the cursor keys to move around and edit the current line\footnote{This may not work on badly-configured systems} \item By default, {\pgn bash} uses {\pgn emacs}-like keystrokes for navigation and editing. Here are 4 examples: \\ \bigskip {\myss \begin{tabular}{|p{80pt}|>{\PBS\rr}p{253pt}|} \hline Keystroke & Action \\ \hline \hline {\cmdn \^{}a} & Move to the beginning of the line\\ \hline {\cmdn \^{}e} & Move to the end of the line\\ \hline {\cmdn \^{}k} & Delete to the end of the line\\ \hline {\cmdn \^{}w} & Delete the previous 'word'\\ \hline \end{tabular} } \vspace{12pt} \item To choose {\pgn emacs} or {\pgn vi}-like keystrokes: {\cmdn \begin{verbatim} $ set -o emacs $ set -o vi \end{verbatim} } \item {\pgn bash} man page gives details of all keystrokes \end{itemize} \section{History} \label{sec:basic-shell-and-tools-approach-bash-history} \begin{itemize} \item Bash remembers used commands (in a `history') \item Old commands are retrievable in different ways \item Repeat the previous command by typing {\cmdn !!} \item Execute the {\usb n}th previous command by typing {\cmdn !-{\usb n}} \item Typing {\cmdn !string} repeats the last command beginning with {\cmdn string} \item To view your history command by command, use the {\kbk up} and {\kbk down} cursor keys \item View your history at any time by typing {\cmdn history} \item History is a {\em very} useful feature, if used well \begin{itemize} \item Incrementally searchable using {\kbk CTRL-R} \end{itemize} \end{itemize} \section{Plumbing} \label{sec:basic-shell-and-tools-approach-Plumbing} \begin{itemize} \item Processes typically start with three files open: \begin{tabular}[t]{|p{177pt}|c|} \hline Name & Descriptor \\ \hline \hline {\kwd Standard input} & 0 \\ \hline {\kwd Standard output} & 1 \\ \hline {\kwd Standard error} & 2 \\ \hline \end{tabular} \vspace{16pt} \item Later we see how to refer to their {\kwd file descriptors} \item These are normally connected to the keyboard and your command-line terminal \\[12pt] % \vspace{10pt} % \input{cli1.latex} \includegraphics[width=280pt]{../images/cli2} \end{itemize} \section{Plumbing (continued)} \label{sec:basic-shell-and-tools-approach-Plumbing continued} \begin{itemize} \item Data can be redirected by the shell \begin{itemize} \item Transparently to the process concerned \item Any or all streams can be redirected \item You can redirect to/from a file or to/from another process \end{itemize} \item Redirection to a process is known as `piping' \end{itemize} \section{Output Redirection} \label{sec:basic-shell-and-tools-approach-output-redirection} \begin{itemize} \item Redirection of output is done using '{\kwd \verb|>|}' \item For example: \begin{verbatim} $ command > output \end{verbatim}%$ Creates the file {\fn output} (or overwrites it if it already exists) and places the standard output from {\fn command} into it \item We can append to a file rather than overwriting it by using {\kwd \verb|>>|} \item {\kwd \verb|>|} and {\kwd \verb|>>|} are actually shorthands for \verb|1>| and \verb|1>>| \item Error output can be redirected using \verb|2>| or \verb|2>>| \begin{verbatim} $ command 2> error.out \end{verbatim}%$ \includegraphics{../images/basic_shell_use_output_redirection} \end{itemize} \section{Input Redirection} \label{sec:basic-shell-and-tools-approach-input-redirection} \begin{itemize} \item {\kbk <} redirects standard input from a file, e.g. \begin{verbatim} $ command < input \end{verbatim} %$ \item {\fn command} will now take the contents of the file {\fn input} as its input \item This could also be written as {\cmdn 0<} \item Consistent with {\cmdn >} and {\cmdn 1>} \includegraphics{../images/basic_shell_use_input_redirection} \end{itemize} \section{Combining Redirection} \label{sec:basic-shell-and-tools-approach-combining-redirection} \begin{itemize} \item Redirect more than one descriptor by giving more than one redirection, e.g. \begin{verbatim} $ command 1> output 2> error \end{verbatim} \item Group redirections using the \verb|>&| operator, e.g. \begin{verbatim} $ command 1> output 2>&1 \end{verbatim} \begin{itemize} \item Output to the file called {\fn output} ( {\cmdn \verb|>| output} ) \item Send errors to the same place as the standard output ( {\cmdn \verb|2>&1|} ) \end{itemize} \item The order of these is {\em very} important \item The redirections are evaluated left-to-right, e.g. the following differs from the previous example \begin{verbatim} $ command 2>&1 > output \end{verbatim} %$ \begin{itemize} \item It sends error to the normal output and normal output to the file called {\fn output} \end{itemize} \end{itemize} \section{Pipelines} \label{sec:basic-shell-and-tools-approach-pipelines} \begin{itemize} \item You can output to another process with `{\cmdn |}' \begin{itemize} \item Known as the {\kwd pipe} symbol \end{itemize} \item A {\kwd pipe} connects the output of one process to the input of another \item The data waiting to be transferred is buffered \item The processes run concurrently \item Linux ensures that the processes keep in step \item For example: {\myss \begin{verbatim} $ sort document | uniq | mail lee \end{verbatim} %$ } \includegraphics[width=\linewidth]{../images/basic_shell_use_pipelines} \end{itemize} \section{Background Processes} \label{sec:basic-shell-and-tools-approach-background-processes} \begin{itemize} \item Most commands run to completion before you get your shell prompt back \item A `background' process continues while you get your prompt back immediately \item To launch a process in the background place {\cmdn \&} at the end of the line, e.g. \begin{verbatim} $ sort /var/log/maillog > output & \end{verbatim} %$ \item Unless you use redirection (plumbing), output and error continue to appear on your terminal \item Input is disconnected, so typing goes to the shell, not to the background process \item If a process needs user input, and can't take it from a file, it is 'stopped' \begin{itemize} \item It won't resume until brought to the foreground to receive input \end{itemize} \item You should normally start background processes with their output and error redirected to a file, e.g. \begin{verbatim} $ sort big_file > output 2> error_output & \end{verbatim} %$ \end{itemize} \section{Background Processes (continued)} \label{sec:basic-shell-and-tools-approach-background-processes-cont} \begin{itemize} \item Running processes can be put in the background \begin{itemize} \item Suspend the process by typing \verb|^Z| in the terminal that the process is running in \item Put the process in the background using {\cmdn bg} \end{itemize} \item Bring a process back to the foreground using {\cmdn fg} \item {\cmdn fg} and {\cmdn bg} operate on the most recent process by default \begin{itemize} \item Change to a process, by job number or name \end{itemize} \item {\cmdn jobs} displays current shell processes: \begin{verbatim} $ jobs [1]+ Stopped (tty output) top $ fg %1 \end{verbatim} \end{itemize} \section{Background Processes and {\cmdn nohup}} \label{sec:basic-shell-and-tools-approach-background-and-nohup} \begin{itemize} \item Sometimes it is necessary to start a process and leave it running when you log out \item If your shell is killed, any background processes will also be lost \item {\cmdn nohup} gets round this by detaching the process from the terminal \item Always redirect output and error with {\cmdn nohup}, e.g. \begin{verbatim} $ nohup sort bigfile > out 2>&1 err.out \end{verbatim} %$ \item If you don't redirect them then they will end up in {\fn ./nohup.out} and {\fn ./nohup.err} \end{itemize} \section{Command Grouping and Sub-shells} \label{sec:basic-shell-and-tools-approach-command-grouping-sub-shells} \begin{itemize} \item {\pgn bash} can execute multiple commands on a line \item Sequential commands are separated by `{\kbk ;}' {\myss \begin{verbatim} $ sort data ; mail lee < sorted_data \end{verbatim} %$ } \item It's possible to launch a sub-shell to execute a command or group of commands \begin{itemize} \item Put commands in parentheses, e.g. \begin{verbatim} $ (command1 ; command2) \end{verbatim} %$ \end{itemize} \item Can also put a subshell in background, e.g. \begin{verbatim} $ (command1 ; command2) & \end{verbatim} %$ \end{itemize} \section{Process Management} \label{sec:basic-shell-and-tools-approach-processes-management} \begin{itemize} \item {\pgn ps} (process status) prints info about a users' processes: {\myss \begin{verbatim} PID TTY STAT TIME COMMAND 22074 p0 S 0:02 Eterm -t trans 22075 p0 S 2:13 emacs -bg black 22081 p0 S 0:00 asclock 22590 p5 R 0:00 ps \end{verbatim} } \item {\pgn jobs} only prints info about processes belonging to the current shell \item {\pgn wait} postpones shell until process is finished \begin{itemize} \item Usually given a process id as an argument \item If no argument is given it waits until all the shell's processes have terminated \end{itemize} \item {\pgn kill} is used to send {\kwd signals} to processes \begin{itemize} \item Can terminate background processes \end{itemize} \item Some processes use signals to trigger tasks, e.g. log rotation, re-reading config files, etc \end{itemize} \section{Signals} \label{sec:basic-shell-and-tools-approach-signals} \begin{itemize} \item {\cmdn kill} can be given a signal name or number \item There are a variety of signals: \bigskip \\ {\myss \begin{tabular}{|p{90pt}|p{50pt}|>{\PBS\rr}p{193pt}|} \hline SIGHUP&1&Hangup detected on controlling terminal or death of controlling process \\ \hline SIGINT&2&Interrupt from keyboard\\ \hline SIGQUIT&3&Quit from keyboard\\ \hline SIGKILL&9&Kill signal\\ \hline SIGTERM&15&Termination signal\\ \hline SIGUSR1&30&User-defined signal 1\\ &10& \\ &16& \\ \hline SIGUSR2&31&User-defined signal 2\\ &12& \\ &17& \\ \hline \end{tabular} } \end{itemize} \section{Signals (continued)} \begin{itemize} \item Unless specified, {\pgn kill} sends a SIGTERM which causes most processes to terminate \item If a process is unresponsive, it can be forcibly killed by sending it SIGKILL {\myss \begin{alltt} $ \textbf{kill -9 1512} 1512: Terminated \end{alltt}%$ } or {\myss \begin{alltt} $ \textbf{kill -KILL 1512} 1512: Terminated \end{alltt}%$ } \item Can only signal your own processes \begin{itemize} \item Superuser can signal all \end{itemize} \end{itemize} \section{Background Processes: {\pgn top}} \label{sec:basic-shell-and-tools-approach-top} \begin{itemize} \item {\pgn top} displays the processes running on a machine \item Results can be sorted in various ways \item Options: \begin{itemize} \item See {\cmdn man top} for full details, including command-line options \item Inside {\pgn top} use {\kbk h} for help on interactive options \end{itemize} \item Typical output: \\[16pt] {\myts \begin{verbatim} PID USER PRI NI SIZE RSS SHARE STAT LIB %CPU %MEM TIME COMMAND 22594 user 10 0 736 736 556 R 0 8.2 0.5 0:00 top 1 root 0 0 144 96 76 S 0 0.0 0.0 0:03 init 2 root 0 0 0 0 0 SW 0 0.0 0.0 0:19 kflushd 3 root -12 -12 0 0 0 SW< 0 0.0 0.0 2:42 kswapd 486 root 5 5 3160 2356 804 S N 0 0.0 1.8 0:03 mysqld 869 root 0 0 68 12 12 S 0 0.0 0.0 0:00 mingetty 838 www 0 0 11468 6280 488 S 0 0.0 4.9 4:14 squid 48 root 0 0 100 80 48 S 0 0.0 0.0 0:01 kerneld 230 root 0 0 384 372 272 S 0 0.0 0.2 0:12 syslogd 239 root 0 0 164 120 72 S 0 0.0 0.0 0:00 klogd 250 daemon 0 0 164 132 88 S 0 0.0 0.1 0:00 atd 261 root 0 0 192 160 112 S 0 0.0 0.1 0:01 crond 272 bin 0 0 244 224 168 S 0 0.0 0.1 0:00 portmap 283 root 0 0 572 296 248 S 0 0.0 0.2 0:17 snmpd 295 root 1 0 136 88 60 S 0 0.0 0.0 0:00 inetd 306 root 0 0 516 488 224 S 0 0.0 0.3 0:06 named 317 root 0 0 124 56 48 S 0 0.0 0.0 0:00 lpd \end{verbatim} } \item N.B. {\pgn top} is not available on all unices \end{itemize} \section{Filename Generation} \label{sec:basic-shell-and-tools-approach-filename-generation} \begin{itemize} \item Some characters are `special' to the shell \\ \bigskip \begin{table}[htbp] \begin{center} {\myss \begin{tabular}[t]{|p{45pt}|>{\PBS\rr}p{295pt}|} \hline Chars & Meaning \\ \hline \hline {\uin *} & Matches any string, including the null string \\ {\uin ?} & Matches any single character\\ {\uin [...]} & Matches any one of the enclosed characters. A pair of characters separated by a minus sign denotes a range. Any character lexically between those two characters, inclusive, is matched. If the first character following the `{\uin [}' is a `{\uin !}' or a `\verb|^|' then any character not enclosed is matched. A `{\uin -}' or `{\uin ]}' may be matched by including it as the first or last character in the set. \\ \hline \end{tabular} } \caption{Special characters under {\pgn bash}} \label{tab:bash-special-chars} \end{center} \end{table} \vspace{-10pt} \item Special characters can be used to match filenames, e.g. to show files beginning with {\fn f} \begin{alltt} $ \textbf{echo f*} \end{alltt}%$ \item To show files starting with `{\kbk f}', followed by a vowel: \begin{alltt} $ \textbf{echo f[aeiou]*} \end{alltt}%$ \end{itemize} \section{Quoting Mechanisms} \label{sec:basic-shell-and-tools-approach-quoting-mechanisms} \begin{itemize} \item Sometimes it's necessary to ignore a character's special meaning \item Use a backslash (\bs) to quote a special character, e.g. to list a file called {\cmdn f*} \begin{alltt} $ \textbf{ls f\*} \end{alltt}%$ \item To quote a longer string, enclose it in quotes: \bigskip \begin{tabular}{p{30pt}p{303pt} } {\kbk '} & disable all interpretation \\ {\kbk "} & disable filename generation and blank space interpretation\\ \end{tabular} \end{itemize} \section{Shell built-in commands} \label{sec:basic-shell-and-tools-approach-shell-builtins} \begin{itemize} \item Some commands must be built in to the shell, because they can't be executed independently \begin{itemize} \item {\cmdn cd}, if executed independently would change its own directory, {\em not} that of your shell \item {\cmdn umask}, would change its umask, {\em not} the shell's \item {\cmdn logout} \item {\cmdn history} \end{itemize} \item Other commands are built in for speed e.g. \begin{itemize} \item {\cmdn pwd} \item {\cmdn echo} \end{itemize} \end{itemize} \section{Basic Shell Exercises} \label{sec:basic-shell-and-tools-approach-exercises} {\normalsize \subsubsection{What should I focus on?} You should: \begin{itemize} \item clearly understand what redirection is, and what a pipe is \item understand that it is the \emph{shell} that expands the filename generation symbols ({\cmdn *}, {\cmdn ?} and {\cmdn [...]}), and not {\pgn echo}, {\pgn ls},\ldots \item understand the differences between these three ways of quoting: {\cmdn '\ldots'}, {\cmdn "\ldots"}, and quoting a single character with `\bs' \item understand how to put a process into the background, bring it to the foreground, and how to interrupt it (\emph{not} with {\kbk Control-z}!) \item understand the difference between using {\kbk Control-c} and {\kbk Control-z} \item understand that subshells have their own working directories. \end{itemize} \subsubsection{The exercises} \begin{enumerate} \item {\em Redirection} \label{sec:cli-redirect-exes} \begin{enumerate} \item Try typing the following commands exactly as they appear here. Note that the \texttt{cat} command copies input files (or standard input) to standard output. If standard input comes from the keyboard, the keystroke \key{Control-d} means ``end of file'' (like \key{Control-z} in Windows). Refer to sections~\vref{sec:basic-shell-and-tools-approach-output-redirection} to \S\vref{sec:basic-shell-and-tools-approach-pipelines} first. Also refer to section~\vref{sec:basic-shell-and-tools-approach-command-grouping-sub-shells} before doing the last exercise. \begin{alltt} $ \textbf{cat} # Then type some words, followed by \key{Control-d} $ \textbf{cat > newfile 2> newfile.error} $ \textbf{car > newfile 2> newfile.error} $ \textbf{car} $ \textbf{Space Shuttle} $ \textbf{echo} $ \textbf{echo foo} $ \textbf{ech} $ \textbf{ech foo} $ \textbf{cat > newfile 2>&1} $ \textbf{car > newfile 2>&1} $ \textbf{cat < newfile} $ \textbf{echo foo | cat > newfile 2>&1} $ \textbf{ech foo | cat > newfile 2>&1} $ \textbf{echo foo | car > newfile 2>&1} $ \textbf{(ech foo | cat) > newfile 2>&1} \end{alltt} %$ After each step, examine the contents of \texttt{newfile} and \texttt{newfile.error} by typing: \begin{alltt} $ \textbf{cat newfile} $ \textbf{cat newfile.error} \end{alltt}%$ Make sure you understand what happens in each case, ask the tutor if you are not sure. \end{enumerate} \item{\em Filename expansion and Quoting} \label{sec:cli-expansion-and-quoting-exs} \begin{enumerate} \item Do the following in the {\fn /bin} directory; refer to section~\vref{sec:basic-shell-and-tools-approach-filename-generation} first. \begin{enumerate} \item List all filenames with exactly three characters. \item List all filenames with exactly three characters in which the second character is a vowel. \item List all filenames with a, b, c, or d as the last character. \item Construct a command to print the number of filenames consisting of exactly three characters. (You may combine commands together in a pipeline. You may find the wc utility useful here; check {\cmdn man wc} for more information.) \item Construct a command to print the total number of files with exactly two, three or four characters in their name. (Again, you may find the wc utility useful.) \end{enumerate} \item Compare the effect of the following commands. Refer to section~\vref{sec:basic-shell-and-tools-approach-quoting-mechanisms} first. Then search for ``quoting'' in the \textbf{bash} man page. \begin{alltt} $ \textbf{echo $HOME} $ \textbf{echo "$HOME"} $ \textbf{echo '$HOME'} $ \textbf{echo *} $ \textbf{echo "*"} $ \textbf{echo '*'} $ \textbf{echo $HOME/bs*} $ \textbf{echo "$HOME/bs*"} $ \textbf{echo '$HOME/bs*'} \end{alltt}%$ \item Change back to your home directory and try to create a file with the name \texttt{*}. Was this a sensible thing to do? How would you delete it? (Be {\em very} careful!) \item Create a file called {\fn --file}. Try to remove this. Use the {\pgn rm} {\pgn man} page to help you. \end{enumerate} \item{\em Background processes and {\cmdn nohup}} \label{sec:bg-nohup-exs} Refer to section~\S\vref{sec:basic-shell-and-tools-approach-background-processes} to \S\vref{sec:basic-shell-and-tools-approach-background-and-nohup} first. \begin{enumerate} \item Start the command {\cmdn sort /dev/random} in the background in your current shell \item Bring it back to the foreground and terminate it by typing \key{Control-c} \item Start it again, and once more so that you have two copies running in the background \item Bring them to the foreground and terminate them in the order you started them \item Start the same command in the background, and terminate it using {\cmdn kill} \end{enumerate} \item{\em Grouped commands} \label{sec:cli-aex-commands-grouped} Compare the following command sequences, and make sure you understand the differences. Refer to section~\S\vref{sec:basic-shell-and-tools-approach-command-grouping-sub-shells} first. \begin{enumerate} \item \begin{alltt} $ \textbf{cd /tmp} $ \textbf{cd /usr; ls} $ \textbf{pwd} \end{alltt}%$ \item \label{que:shell-basic-subshell}% \begin{alltt} $ \textbf{cd /tmp} $ \textbf{(cd /usr; ls)} $ \textbf{pwd} \end{alltt}%$ \item\label{que:shell-basic-bg}% \begin{alltt} $ \textbf{sleep 5 & sleep 5} \end{alltt}%$ \item \label{que:shell-basic-subshell-bg} \begin{alltt} $ \textbf{(sleep 5; sleep 5) &} \end{alltt}%$ \end{enumerate} Check you can use your history to get at and repeat any of the commands you have typed. \end{enumerate} \section{Basic Shell Solutions} \label{sec:basic-shell-and-tools-approach-cli-solutions} \includeversion{Solutions}% \excludeversion{noSolutions}% \begin{Solutions} \begin{enumerate} \stepcounter{enumi} \item \emph{Filename expansion \textbf{and Quoting}} \label{sec:cli-expansion-and-quoting-solutions} \begin{enumerate} \item These are solutions which will do the job, there may be other ways of achieving the same thing \begin{enumerate} \item {\uin ls ???} \item {\uin ls ?[aeiou]?} \item {\uin ls *[abcd]} \item {\uin ls ??? | wc -l} \item {\uin (ls ??; ls ???; ls ????) | wc -l}\\ or more simply,\\ {\uin ls ?? ??? ???? | wc -l} \end{enumerate} \item When not quoted \texttt{\$HOME} gives the name of your home directory. This is variable substitution. We can see that this substition still happens inside \texttt{"} quotes, but not inside \texttt{'} quotes. {\cmdn echo *} expands to all the filenames in the current directory. This is filename generation and doesn't happen in either type of quote. \item It is not a wise choice to name anything with a filename containing special characters. You can delete the file safely by quoting the \texttt{*} using any one of these ways: \begin{itemize} \item {\cmdn rm "*"} \item {\cmdn rm '*'} \item {\cmdn rm \bs*} \end{itemize} \item You can delete the file by using {\cmdn rm -- --file}\\ or with {\cmdn rm ./--file} \end{enumerate} \item{\em Background processes and {\cmdn nohup}} \label{sec:cli-bg-and-nohup--solutions} \begin{enumerate} \item \begin{alltt} $ \textbf{sort /dev/random \&} \end{alltt}%$ \item \begin{alltt} $ \textbf{fg} \textbf{^C} \end{alltt}%$ \item \begin{alltt} $ \textbf{sort /dev/random &} [1] 26409 $ \textbf{sort /dev/random &} [2] 26410 \end{alltt} \item \begin{alltt} $ \textbf{jobs} [1]- Running sort /dev/random & [2]+ Running sort /dev/random & $ \textbf{fg %1} sort /dev/random \textbf{^C} $ \textbf{fg %2} sort /dev/random \textbf{^C} \end{alltt}%$ \item \begin{alltt} $ \textbf{sort /dev/random &} [1] 26462 $ \textbf{kill 26462} # Or: $ \textbf{kill %1} \end{alltt}%$ \end{enumerate} \item The semicolon `\texttt{;}' is a separator, like the newline, to the shell, so in: \begin{alltt} $ \textbf{cd /usr; ls} \end{alltt}%$ first the \texttt{cd /usr} command is executed, then the \texttt{ls} command. In part \ref{que:shell-basic-subshell}, these commands are executed in their own subshell, so the \texttt{cd} does not change the current directory of the parent process (the process from which the subshell was \texttt{fork()}ed), so the \texttt{pwd} command shows that we are still in the \texttt{/tmp} directgory from which we started. In part \ref{que:shell-basic-subshell-bg}, the whole subshell is put into the background and the subshell terminates after 10 seconds, whereas in part~\ref{que:shell-basic-bg}, only the first \texttt{sleep 5} command is put into the background, so both \texttt{sleep 5} commands run in parallel and both terminate after 5 seconds. You can see this for yourself: \begin{alltt}\small $ \textbf{sleep 5 && echo 'done 1' & sleep 5 && echo 'done 2'} [3] 30269 done 1 done 2 [3]+ Done sleep 5 && echo done 1 \end{alltt}%$ You can also measure the time it takes for any command to complete with the \texttt{time} command: \begin{alltt}\small $ \textbf{time sleep 5 && echo 'done 1' & time sleep 5 && echo 'done 2'} [4] 30258 real 0m5.008s user 0m0.000s [3] Done time sleep 5 && echo 'done 2' sys 0m0.000s done 1 real 0m5.009s user 0m0.000s sys 0m0.000s done 2 [4]+ Done time sleep 5 && echo 'done 1' \end{alltt} And just for the fun of it, you can try: \begin{alltt}\small $ \textbf{time \{ sleep 5; time sleep 5; \}} real 0m5.010s user 0m0.000s sys 0m0.000s real 0m10.013s user 0m0.000s sys 0m0.000s $ \textbf{( time \{ sleep 5; time sleep 5; \} ) &} [3] 30455 $ real 0m5.010s user 0m0.000s sys 0m0.000s real 0m10.013s user 0m0.000s sys 0m0.000s [3]+ Done ( time \{ sleep 5; time sleep 5; \} ) \end{alltt} \end{enumerate} \end{Solutions} \begin{noSolutions} We will provide solutions soon. \end{noSolutions} } % End of {\normalsize \label{endofchapter-basicshellandtools} } % end mns from chapter start \excludeversion{Solutions}% \includeversion{noSolutions}% %%% Local Variables: %%% mode: latex %%% TeX-master: "planet_basic_course_masterfile" %%% End: