%\documentclass[pdf,eliblue,slideColor,colorBG,accumulate,nototal]{prosper}
\documentclass[pdf,eliblue,slideBW,nocolorBG,accumulate,nototal]{prosper}
\title{Quick and Dirty Bash}
\author{Eli Billauer}
\email{http://www.billauer.co.il}
\begin{document}
\Logo(-1.7,-1.2){\includegraphics[width=1.5cm]{haifux.eps}}
\maketitle
%
\begin{slide}
{Lecture overview}
\begin{itemize} 
\item Introduction
\item Loops
\item Conditionals and their use
\item Backticking and similar methods
\item Making GUI in scripts
\item Service scripts
\item Summary
\end{itemize}  
\end{slide}
%
\begin{slide}
{Why command line?}
\begin{itemize} 
\item Use not limited to GUI design
\item No need to obey GUI's rules
\item GUI applications tend to be less stable
\item Easier to hack command-line tools
\item Command line applications usually ``do the job'' better
\item Repeatablilty (no memory from previous session)
\item Scriptability
\item Automation
\end{itemize}  
\end{slide}
%
\begin{slide}
{When to do scripting in Bash}
Do it in Bash...
\begin{itemize} 
\item ... at shell prompt
\item ... when there are a lot of application calls
\item ... for system scripts
\item ... if you don't want to get into the Perl vs. Python war
\end{itemize}
Don't to it in Bash (use Perl / Python instead) ...
\begin{itemize} 
\item ... when the script itself should do something nontrivial
\item ... when you want setuid root
\end{itemize}
\end{slide}
%
\begin{slide}
{Common use of bash scripts}
\begin{itemize}
\item \verb+.bashrc+, \verb+.bash_profile+, \verb+.bash_logout+
\item Services going on and off
\item \texttt{./configure}
\item In makefiles
\item One-liners at prompt
\end{itemize}  
\end{slide}
%
\begin{slide}
{Shebang and friends}
\begin{itemize} 
\item Comments in Bash scripts start with a \verb+#+
\item Bash scripts start with \verb+#!/bin/bash+ (``shebang'')
\item Line breaks are bridged with ``\verb+\+'' (backslash, like C)
\item Group commands: With '\texttt{\{}' and '\texttt{\}}'
\item Group commands in subshell: With '\texttt{(}' and '\texttt{)}'
\end{itemize}
... and a couple of special parameters:
\begin{itemize} 
\item \texttt{\$\$} expands to the current process number. Good for temporary files:\\
      \verb+tmpfile=delme-tmp-$$+
\item \texttt{\$1}, \texttt{\$2}, \texttt{\$3},... are the arguments passed to the script
\end{itemize}
\end{slide}
%
\begin{slide}
{Loops in bash}
\begin{itemize} 
\item \verb+for i in Hello World ; do echo $i ; done+%$
\item \verb+while [ 1 ] ; do echo Wow ; done+
\item \verb-for ((i=0 ; i<10 ; i++)); do echo $i; done-%$
\item Note: If you want to kill a loop (in absence of CTRL-C), you have
      to kill the bash process itself
\end{itemize}  
\end{slide}
%
\begin{slide}
{Conditionals in Bash}
\begin{itemize} 
\item Every exectable is a conditional by its return value:\\
      \verb+while true ; do echo Wow ; done+\\
      \verb+while grep -q audio /proc/modules+\\
      \verb+  do echo Audio! ; done ;+
\item ... but don't use \verb+true+ and \verb+false+!
\item \verb+if [ -d /etc ] ; then echo Yes ; fi+ \\
      '\verb+[+' and '\verb+]+' mean Bash \verb+test+, so it's the same as\\
      \verb+if test -d /etc ; then echo Yes ; fi+
\item '\verb+[[+' and '\verb+]]+' are ``enhanced'' but not sh-compatible. These
      two mean the same:\\
      \verb+if [ -d /etc -a -d /bin ] ; then echo Yes ; fi+\\
      \verb+if [[ -d /etc && -d /bin ]] ; then echo Yes ; fi+
\end{itemize}  
\end{slide}
%
\begin{slide}
{Conditionals in Bash (cont.)}
\begin{itemize} 
\item Now some binary operations. Below, all ``Yes'' will be printed, all ``No'' will not.
\item \verb+if [[ "12" == 12 ]] ; then echo Yes ; fi+
\item \verb+if [ "12" = 012 ] ; then echo Yes ; fi+
\item \verb+if [[ "12" == 012 ]] ; then echo No ; fi+
\item \verb+if [ "12" -eq 012 ] ; then echo Yes ; fi+
\item \verb+if [[ "12" -eq 012 ]] ; then echo No ; fi+
\item \verb+if [[ "12" -eq 12 ]] ; then echo Yes ; fi+
\item According to the man page, \verb+-eq+ and friends are
      \textbf{arithmetic} and \verb+==+ is stringwise lexicographic. (This is not Perl)
\item \verb+=+ is like \verb+==+ in test context (Yuck!)
\item Conclusion: RTFM, and think twice if you want to use this
\end{itemize}  
\end{slide}
%
\begin{slide}
{Using conditionals}
\begin{itemize} 
\item \verb+while+ loops as we've seen
\item \verb+rm -f *.o && make+\\
      ... which is the same as\\
      \verb+if rm -f *.o ; then make ; fi+
\item Note the semicolons!
\item '\verb+[+', '\verb+]+', '\verb+[[+' and '\verb+]]+' are tokens.
      Keep spaces around them!
\item Note the quotation marks! For example, \verb+-n+ is true when the string that follows
      has nonzero length. The first two works like you would expect, the third doesn't!\\
      \verb+empty=""; if [ -n "$empty" ] ; then echo No ; fi+\\
      \verb+empty=""; if [[ -n $empty ]] ; then echo No ; fi+\\
      \verb+empty=""; if [ -n $empty ] ; then echo Yes ; fi+%$
\end{itemize}  
\end{slide}
%
\begin{slide}
{Arithmetics}
\begin{itemize} 
\item The name of the game is  '\verb+((+' and '\verb+))+'
\item \verb=echo $((1+1)) and $((2**8))=
\item All arithmetics is with integers
\item Conditionals and autoincrement (instead of for-loop):\\
      \verb-i=0; while ((i<10)); do echo $((i++)); done-%$
\item \verb-i=1; while ((i<256)); do echo $((i*=2)); done-%$
\end{itemize}  
\end{slide}
%
\begin{slide}
{Example}
\begin{verbatim}
#!/bin/bash

if (($# < 1));
  then echo "Usage: $0 destination-path"; exit 1;
fi

if [ -a $1 ];
  then echo "File/dir $1 already exists"; exit 1;
fi

mkdir $1 || { echo "Failed to mkdir $1"; exit 1; }
\end{verbatim}
...
\end{slide}
%
\begin{slide}
{The almighty backtick}
\begin{itemize} 
\item Run a command (or commands) and organize standard output as arguments delimited by spaces:
\end{itemize}  
\begin{verbatim}
$ which bash
/usr/bin/bash

$ ls -l `which bash`
-rwxr-xr-x 1 root root 478720 Feb 19 2002 /usr/bin/bash

$ echo `find . -true`
. ./file1 ./file2 ./file3
\end{verbatim}%$
\end{slide}
%
\begin{slide}
{The ``for i in'' loop}
\begin{itemize} 
\item \verb+for i in file1.c file2.c+
      \verb+  do grep -H \#define $i ; done+%$
\item \verb+for i in *.c ; do grep -H \#define $i ; done+%$
\item \verb+for i in {a,b,c}-{d,e,f} ; do echo $i; done+%$
\item \verb+for i in `find . -name \*.c`+
      \verb+  do grep -H \#define $i ; done+%$
\end{itemize}  
\end{slide}
%
\begin{slide}
{The problems with backticks}
\begin{itemize} 
\item File names with spaces: ``\verb+my file.doc+'' looks like two files: ``\verb+my+'' and
      \verb+file.doc+
\item Quotation marks don't solve this!
\item May exceed maximal number of arguments for Bash.
\item Loop starts only when backticked command finishes: Slow response
\item The solution: Use the \verb+read+ builtin command:
\item \verb+find . -name \*.c | while read i ;+
      \verb+  do grep -H \#define "$i" ; done+%$
\item Note the quotation marks -- they take care of the spaces in the file names!
\end{itemize}
\end{slide}
%
\begin{slide}
{Read the ``find'' man page!}
\begin{itemize} 
\item This is not really about Bash, but still...
\end{itemize}
\begin{verbatim}
for dir in / ; do
  find /$dir -newer /etc/computer-bought-date \
       ! -type d >> $1/backup-files;
done;

{ tar -c --to-stdout --preserve \ 
      --files-from $1/backup-files; } | \ 
  { cd $1 && tar --preserve -v -x ; }
\end{verbatim}
... or who's eating my disk space?
\begin{verbatim}
find . -true -printf "%k %p\n" | sort -nr
\end{verbatim}
\end{slide}
%
\begin{slide}
{The xargs utility}
\begin{itemize} 
\item Show me 20 images at a time:\\
      \verb+find . -name \*.jpg -print0 | \+
      \verb+  xargs --null -n 20 kview+
\item To \verb+xargs+ white spaces in the input are delimiters, unless in quotes, or
      as above: \verb+print0+ and \verb+--null+
\item The \verb+-printf "\"%p\"\n"+ is the filename within double quotes
      (what if the file name includes quotes?)
\item If we change the second line to\\
      \verb+  xargs --null -P 4 -n 20 kview+\\
      we get four instances (windows) of \verb+kview+. Close one, another will pop up!
\item The inserted arguments don't have to be last ones with \verb+--replace=XXX+
\end{itemize}  
\end{slide}
%
\begin{slide}
{String operations}
\begin{itemize} 
\item \verb+find . -name \*.wav | while read i ;+
      \verb+  do lame -h "$i" "${i%.*}.mp3" ; done+%$
\item Or more specific:
\item \verb+find . -name \*.wav | while read i ;+
      \verb+  do lame -h "$i" "${i%.wav}.mp3" ; done+%$
\item \verb+%+ and \verb+%%+ chop off suffixes. \verb+#+ and \verb+##+ chop off prefixes.
\item \verb+%%+ and \verb+##+ are greedy. \verb+%+ and \verb+#+ match minimal characters.
\item Remove path (file name only): \verb+${i##*/}+%$
\item Remove ``\verb+./+'': \verb+${i#./}+%$
\item If no match is found, the string is left as is
\end{itemize}
\end{slide}
%
\begin{slide}
{My CD image generation script}
\begin{verbatim}
... and another string expansion:
#!/bin/bash

for i in cd-* ; do
  item=${i:3:5};
  today=`date +%y%m%d`;
  echo Now creating volume $today$item...
  mkisofs -R -J -graft-points -V $today$item \ 
          -o $i.iso "/=$i/";
done
\end{verbatim}%$
\begin{itemize} 
\item \verb+${i:3:5}+ is character 3 to 5 (counting from zero) in \verb+$i+.
\item Later on we'll see how Bash is used to burn the images...
\end{itemize}  
\end{slide}
%
\begin{slide}
{The \texttt{printf} builtin command}
\begin{itemize} 
\item Of course there's a \texttt{printf}!
\item This is how we find a unique dirXXXX directory name:\\
      \verb+i=1; while name=`printf dir%04d $i` && [ -e $name ]+\\
      \verb-  do ((i++)) ; done ;-
\item Note: No comma between format string and argument(s)
\end{itemize}  
\end{slide}
%
\begin{slide}
{Quick and dirty GUI}
This simple script is for serial CD burning
\begin{verbatim}
for i in *.iso;
  do Xdialog --msgbox "Now burning $i" 0 0;
  cdrecord dev=0,0,0 speed=24 -v -eject -dao $i;
done;
\end{verbatim}
\begin{itemize} 
\item \verb+Xdialog+ prompts the user with an ``OK'' message box
\item File selection (and then view):\\
      \verb+Xdialog --stdout --fselect "" 0 0 | \+\\
      \verb+{ read i ; kview "$i" ; }+%$
\item Basically a front end for GTk
\item The text-based version is \verb+dialog+
\item Several other widgets (edit boxes, progress meters, log boxes etc.)
\end{itemize}  
\end{slide}
%
\begin{slide}
{Functions}
\begin{verbatim}
$  Hello() { echo I got $1 ; return 5 ; }
$ Hello World
I got World
$ echo $?
5
\end{verbatim}%$
\begin{itemize} 
\item The function is run in the current environment
\item No new process is created
\end{itemize}  
\end{slide}
%
\begin{slide}
{The case statement}
\begin{verbatim}
#!/bin/bash
case "$1" in
[Hh]ello)
  echo "Nice to meet you"
  ;;
[Bb]ye)
  echo "See you later"
  ;;
*)
  echo "I am so glad to hear!"
esac
\end{verbatim}%$
\begin{itemize} 
\item The \verb+;;+ is not a ``break'' statement. It's syntactically necessary.
\end{itemize}  
\end{slide}
%
\begin{slide}
{Service scripts}
\begin{itemize} 
\item Scripts can be found somewhere like \verb+/etc/rc.d/init.d+
      (distribution dependent)
\item The scripts are called during bootup according to the services setup
\item ... or by \verb+service xxx start+. Or stop. Or restart.
\item The scripts are called with one argument, typically \verb+start+,
      \verb+stop+, \verb+restart+, \verb+status+, or other service-specific
      commands.
\item Let's see one!
\end{itemize}  
\end{slide}
%
\begin{slide}
{Summary}
We have seen:
\begin{itemize}
\item Loops and how to make meaningful loop indexes (file names...)
\item Conditionals and arithmetics
\item Backticking, \texttt{xargs} and while-read loops
\item String operations
\item Basic GUI
\item We went to the safari (... service scripts)
\item Bash is not Perl -- it doesn't cooperate
\item ... but it's still very useful
\end{itemize}  
\end{slide}
%
\begin{slide}
{Further reading}
\begin{itemize} 
\item \verb+man bash+
\item Orna's lecture about Bash: \verb+http://www.haifux.org/lectures/92-sil/+
\item Advanced Bash-Scripting Guide: \verb+http://tldp.org/LDP/abs/+
\item Linux Files and Command Reference: \verb+http://www.comptechdoc.org/os/linux/commands/+ 
\end{itemize}  
\end{slide}
%
\begin{slide}
{}
\begin{center}
\vspace{0.3\textheight}

Thank you!

\vspace{0.3\textheight}

The slides were made with \LaTeX \\
(\texttt{prosper} class)
\end{center} 
\end{slide}
%
\end{document}

