Corrected typos, incorporated reader remarks.

This commit is contained in:
tille 2005-09-05 12:15:43 +00:00
parent 34aacdcf72
commit 27db22da76
15 changed files with 76 additions and 249 deletions

View File

@ -29,16 +29,16 @@
<firstname>Machtelt</firstname>
<surname>Garrels</surname>
<affiliation>
<orgname>Xalasys.com
<orgname>CoreSequence.com
</orgname>
<address>
<email>tille wants no spam _at_ xalasys dot com</email>
<email>tille@coresequence.com</email>
</address>
</affiliation>
</author>
</authorgroup>
<edition>Version 1.6 Last updated 20050301</edition>
<edition>Version 1.1 Last updated 20040615</edition>
<keywordset>
<keyword>Linux</keyword>
<keyword>Scripts</keyword>
@ -51,12 +51,6 @@
<keyword>bash</keyword>
<keyword>scripting</keyword>
<keyword>Scripting</keyword>
<keyword>awk</keyword>
<keyword>sed</keyword>
<keyword>variables</keyword>
<keyword>functions</keyword>
<keyword>loops</keyword>
<keyword>conditionals</keyword>
</keywordset>
</bookinfo>
@ -70,7 +64,6 @@
<para>The primary reason for writing this document is that a lot of readers feel the existing <ulink url="http://tldp.org/HOWTO/Bash-Prog-Intro-HOWTO.html">HOWTO</ulink> to be too short and incomplete, while the <ulink url="http://tldp.org/LDP/abs/html/">Bash Scripting</ulink> guide is too much of a reference work. There is nothing in between these two extremes. I also wrote this guide on the general principal that not enough free basic courses are available, though they should be.</para>
<para>This is a practical guide which, while not always being too serious, tries to give real-life instead of theoretical examples. I partly wrote it because I don't get excited with stripped down and over-simplified examples written by people who know what they are talking about, showing some really cool Bash feature so much out of its context that you cannot ever use it in practical circumstances. You can read that sort of stuff after finishing this book, which contains exercises and examples that will help you survive in the real world.</para>
<para>From my experience as UNIX/Linux user, system administrator and trainer, I know that people can have years of daily interaction with their systems, without having the slightest knowledge of task automation. Thus they often think that UNIX is not userfriendly, and even worse, they get the impression that it is slow and old-fashioned. This problem is another one that can be remedied by this guide.</para>
</section>
<section id="intro_02">
@ -90,58 +83,18 @@
<listitem><para>Adding/removing software on your system</para></listitem>
</itemizedlist>
<para>See <ulink url="http://tldp.org/LDP/intro-linux/html/">Introduction to Linux</ulink> (or your local <ulink url="http://www.tldp.org/mirrors.html">TLDP mirror</ulink>) if you haven't mastered one or more of these topics. Additional information can be found in your system documentation (man and info pages), or at <ulink url="http://tldp.org">the Linux Documentation Project</ulink>.</para>
</section>
<section id="intro_03">
<title>New versions and availability</title>
<para>The most recent edition can be found at <ulink url="http://tille.xalasys.com/training/bash/" />. You should find the same version at <ulink url="http://tldp.org/LDP/Bash-Beginners-Guide/html/index.html" />.</para>
<para>This guide is available in print from <ulink url="http://store.fultus.com/product_info.php?products_id=66">Fultus.com</ulink>.</para>
<figure><title>Bash Guide for Beginners front cover</title>
<mediaobject>
<imageobject>
<imagedata fileref="images/bgb.jpg" format="JPG"></imagedata>
</imageobject>
<imageobject>
<imagedata fileref="images/bgb.eps" format="EPS"></imagedata>
</imageobject>
<textobject>
<phrase>Front cover of the Bash guide, red highlighted code on blue background.</phrase>
</textobject>
</mediaobject>
</figure>
<title>New versions of this guide</title>
<para>The most recent edition can be found at <ulink url="http://tille.soti.org/training/bash/" />. You should find the same version at <ulink url="http://tldp.org/LDP/Bash-Beginners-Guide/html/index.html" />.</para>
</section>
<section id="intro_04">
<title>Revision History</title>
<para>
<revhistory>
<revision>
<revnumber>1.6</revnumber>
<date>2005-03-01</date>
<authorinitials>MG</authorinitials>
<revremark>Minor debugging, added more keywords, info about new Bash 3.0, took out blank image.</revremark>
</revision>
<revision>
<revnumber>1.5</revnumber>
<date>2004-12-06</date>
<authorinitials>MG</authorinitials>
<revremark>Changes because of new domain, minor corrections.</revremark>
</revision>
<revision>
<revnumber>1.4</revnumber>
<date>2004-10-18</date>
<authorinitials>MG</authorinitials>
<revremark>Debugging, added a couple of notes in chap9, replaced screenshots with screen sections. Corrected some typos.</revremark>
</revision>
<revision>
<revnumber>1.3</revnumber>
<date>2004-07-09</date>
<authorinitials>MG</authorinitials>
<revremark>Added tracer image 1x1 pixel http://tille.xalasys.com/images/blank-bash.png, added textobjects for all pictures, fixed wrong links in index, made signal list more clear.</revremark>
</revision>
<revision>
<revnumber>1.2</revnumber>
<date>2004-06-15</date>
@ -185,36 +138,36 @@ Thanks to all the friends who helped (or tried to) and to my husband; your encou
<listitem><para>Gerg Ferguson, for ideas on the title</para></listitem>
<listitem><para>Mendel Leo Cooper, for making room</para></listitem>
<listitem><para>#linux.be, for keeping my feet on the ground</para></listitem>
<listitem><para>Frank Wang, for his detailed remarks on all the things I did wrong ;-)</para></listitem>
</itemizedlist>
<para>Special thanks to Tabatha Marshall, who volunteered to do a complete review and spell and grammar check. We make a great team: she works when I sleep. And vice versa ;-)</para>
</section>
<section id="intro_06">
<title>Feedback</title>
<para>
Missing information, missing links, missing characters, remarks? Mail it to
<address><email>tille wants no spam _at_ xalasys dot com</email></address>
<address><email>tille@coresequence.com</email></address>
the maintainer of this document.
</para>
</section>
<section id="intro_07">
<title>Copyright information</title>
<para>Copyright &#169; 2003-2005 Machtelt Garrels.</para>
<para>Copyright &copy; 2003 Machtelt Garrels.</para>
<para> Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation; with the Invariant Sections being "New versions of this document", "Contributions", "Feedback" and "Copyright information", with no Front-Cover Texts and no Back-Cover Texts. A copy of the license is included in <xref linkend="app_01" /> entitled "GNU Free Documentation License".</para>
<para>The author and publisher have made every effort in the preparation of this book to ensure the accuracy of the information. However, the information contained in this book is offered without warranty, either express or implied. Neither the author nor the publisher nor any dealer or distributor will be held liable for any damages caused or alleged to be caused either directly or indirectly by this book.</para>
<para>The logos, trademarks and symbols used in this book are the properties of
their respective owners.</para>
</section>
<section id="intro_08">
<title>What do you need?</title>
<para><command>bash</command>, available from <ulink url="http://www.gnu.org/directory/GNU/">http://www.gnu.org/directory/GNU/</ulink>. The Bash shell is available on nearly every Linux system, and can these days be found on a wide variety of UNIX systems.</para>
<para>Compiles easily if you need to make your own, tested on a wide variety of UNIX, Linux, MS Windows and other systems.</para>
</section>
<section id="intro_09">
<title>Conventions used in this document</title>
@ -298,14 +251,15 @@ is the heart of the system.</quote></entry>
within this guide.</entry>
</row>
<row>
<entry><ulink url="http://tille.xalasys.com">The author</ulink></entry>
<entry><ulink url="http://tille.soti.org">The author</ulink></entry>
<entry>Clickable link to an external web resource.</entry>
</row>
</tbody>
</tgroup>
</table>
</section>
</section>
<section id="intro_10">
<title>Organization of this document</title>
<para>This guide discusses concepts useful in the daily life of the serious Bash user. While a basic knowledge of the usage of the shell is required, we start with a discussion of the basic shell components and practices in the first three chapters.</para>
@ -352,7 +306,8 @@ next chapter.</para>
<para><xref linkend="chap_12" />: Catching signals: introduction to process signalling, trapping user-sent signals.</para>
</listitem>
</itemizedlist>
</section>
</section>

View File

@ -51,7 +51,6 @@ in the active terminal. The system finds the directory where the name occurs us
[mia@post21 ~]$
</screen>
</sect2>
</sect1>
<sect1 id="sect_01_02"><title>Advantages of the Bourne Again SHell</title>
@ -244,7 +243,6 @@ the shell expansions or by the <command>let</command> built-in.</para>
</sect3>
</sect2>
</sect1>
<sect1 id="sect_01_03"><title>Executing commands</title>
@ -349,7 +347,6 @@ the shell expansions or by the <command>let</command> built-in.</para>
</sect3>
</sect2>
</sect1>
<sect1 id="sect_01_05"><title>Developing good scripts</title>
@ -508,7 +505,6 @@ exit 0
</screen>
<para>The <command>case</command> statement often used in this kind of script is described in <xref linkend="sect_07_02_05" />.</para>
</sect2>
</sect1>
<sect1 id="sect_01_06"><title>Summary</title>
@ -521,7 +517,6 @@ exit 0
<para>Bash behaves different when in interactive mode and also has a POSIX compliant and a restricted mode.</para>
<para>Shell commands can be split up in three groups: the shell functions, shell built-ins and existing commands in a directory on your system. Bash supports additional built-ins not found in the plain Bourne shell.</para>
<para>Shell scripts consist of these commands arranged as shell syntax dictates. Scripts are read and executed line per line and should have a logical structure.</para>
</sect1>
<sect1 id="sect_01_07"><title>Exercises</title>
@ -549,7 +544,6 @@ exit 0
<listitem><para>How many processes are currently running on your system? Use <command>ps</command> and <command>wc</command>, the first line of output of <command>ps</command> is not a process!</para></listitem>
<listitem><para>How to display the system hostname? Only the name, nothing more!</para></listitem>
</orderedlist>
</sect1>

View File

@ -74,7 +74,7 @@ declare -- OTHERVAR="blah"
<para>As soon as you restrict assignment of values to a variable, it can only hold that type of data. Possible restrictions are either integer, constant or array.</para>
<para>See the Bash info pages for information on return status.</para>
</sect2>
<sect2 id="sect_10_01_03"><title>Constants</title>
<sect2 id="sect10_01_03"><title>Constants</title>
<para>In Bash, constants are created by making a variable read-only. The <command>readonly</command> built-in marks each specified variable as unchangeable. The syntax is:</para>
<cmdsynopsis><command>readonly <option>OPTION</option> <varname>VARIABLE(s)</varname></command></cmdsynopsis>
<para>The values of these variables can then no longer be changed by subsequent assignment. If the <option>-f</option> option is given, each variable refers to a shell function; see <xref linkend="chap_11" />. If <option>-a</option> is specified, each variable refers to an array of variables. If no arguments are given, or if <option>-p</option> is supplied, a list of all read-only variables is displayed. Using the <option>-p</option> option, the output can be reused as input.</para>
@ -86,7 +86,6 @@ declare -- OTHERVAR="blah"
bash: TUX: readonly variable
</screen>
</sect2>
</sect1>
<sect1 id="sect_10_02"><title>Array variables</title>
<sect2 id="sect_10_02_01"><title>Creating arrays</title>
@ -149,14 +148,8 @@ one three four
# $Id$
# $Log$
# Revision 1.5 2004/12/06 12:27:09 tille
# changes for new domainname, minor corrections
#
# Revision 1.6 2004/10/18 18:58:06 tille
# debugging, typos removed, replaced screenshots in chap9 with screen sections.
#
# Revision 1.5 2004/06/24 14:02:48 tille
# dded tracer image
# Revision 1.2 2004/06/15 13:28:57 tille
# more markup, correction of some errors and typos, added alphabetical index
#
# Revision 1.4 2004/06/15 08:47:12 tille
# more markup, index
@ -268,7 +261,6 @@ Reminder: the list of demos is here:
EOF
</screen>
</sect2>
</sect1>
<sect1 id="sect_10_03"><title>Operations on variables</title>
<sect2 id="sect_10_03_01"><title>Arithmetic on variables</title>
@ -370,7 +362,7 @@ avery
<cmdsynopsis><command>${<varname>VAR</varname>##<parameter>WORD</parameter>}</command></cmdsynopsis>
<para>These constructs are used for deleting the pattern matching the expansion of <parameter>WORD</parameter> in <varname>VAR</varname>. <parameter>WORD</parameter> is expanded to produce a pattern just as in file name expansion. If the pattern matches the beginning of the expanded value of <varname>VAR</varname>, then the result of the expansion is the expanded value of <varname>VAR</varname> with the shortest matching pattern (<quote>#</quote>) or the longest matching pattern (indicated with <quote>##</quote>).</para>
<para>If <varname>VAR</varname> is <varname>*</varname> or <varname>@</varname>, the pattern removal operation is applied to each positional parameter in turn, and the expansion is the resultant list.</para>
<para>If <varname>VAR</varname> is an array variable subscribed with <quote>*</quote> or <quote>@</quote>, the pattern removal operation is applied to each member of the array in turn, and the expansion is the resultant list. This is shown in the examples below:</para>
<para>If <varname>VAR</varname> is an array variable subscribed with <quote>*</quote> or <quote>*</quote>, the pattern removal operation is applied to each member of the array in turn, and the expansion is the resultant list. This is shown in the examples below:</para>
<screen>
<prompt>[bob in ~]</prompt> <command>echo <varname>${ARRAY[*]}</varname></command>
one two one three one four
@ -410,13 +402,11 @@ thisisaverylongstring
<para>More information can be found in the Bash info pages.</para>
</sect3>
</sect2>
</sect1>
<sect1 id="sect_10_04"><title>Summary</title>
<para>Normally, a variable can hold any type of data, unless variables are declared explicitly. Constant variables are set using the <command>readonly</command> built-in command.</para>
<para>An array holds a set of variables. If a type of data is declared, then all elements in the array will be set to hold only this type of data.</para>
<para>Bash features allow for substitution and transformation of variables <quote>on the fly</quote>. Standard operations include calculating the length of a variable, arithmetic on variables, substituting variable content and substituting part of the content.</para>
</sect1>
<sect1 id="sect_10_05"><title>Exercises</title>
<para>Here are some brain crackers:</para>

View File

@ -100,7 +100,6 @@ dir ()
}
</screen>
</sect2>
</sect1>
<sect1 id="sect_11_02"><title>Examples of functions in scripts</title>
<sect2 id="sect_11_02_01"><title>Recycling</title>
@ -218,12 +217,10 @@ echo -e "Remote backup `date` SUCCESS\n----------" &gt;&gt; "$LOGFILE"
<para>is equivalent to</para>
<cmdsynopsis><command>command &gt; <filename>file</filename> 2&gt;&amp;1</command></cmdsynopsis>
</sect2>
</sect1>
<sect1 id="sect_11_03"><title>Summary</title>
<para>Functions provide an easy way of grouping commands that you need to execute repetitively. When a function is running, the positional parameters are changed to those of the function. When it stops, they are reset to those of the calling program. Functions are like mini-scripts, and just like a script, they generate exit or return codes.</para>
<para>While this was a short chapter, it contains important knowledge needed for achieving the ultimate state of laziness that is the typical goal of any system administrator.</para>
</sect1>
<sect1 id="sect_11_04"><title>Exercises</title>
@ -234,7 +231,6 @@ echo -e "Remote backup `date` SUCCESS\n----------" &gt;&gt; "$LOGFILE"
</listitem>
<listitem><para>Create a subdirectory in your home directory in which you can store function definitions. Put a couple of functions in that directory. Useful functions might be, amongs others, that you have the same commands as on DOS or a commercial UNIX when working with Linux, or vice versa. These functions should then be imported in your shell environment when <filename>~/.bashrc</filename> is read.</para></listitem>
</orderedlist>
</sect1>
</chapter>

View File

@ -34,9 +34,11 @@
<row><entry>Standard key combination</entry><entry>Meaning</entry></row>
</thead>
<tbody>
<row><entry><keycap>Ctrl</keycap>+<keycap>C</keycap></entry><entry>The interrupt signal, sends SIGINT to the job running in the foreground.</entry></row>
<row><entry><keycap>Ctrl</keycap>+<keycap>Y</keycap></entry><entry>The <emphasis>delayed suspend</emphasis> character. Causes a running process to be stopped when it attempts to read input from the terminal. Control is returned to the shell, the user can foreground, background or kill the process. Delayed suspend is only available on operating systems supporting this feature.</entry></row>
<row><entry><keycap>Ctrl</keycap>+<keycap>Z</keycap></entry><entry>The <emphasis>suspend</emphasis> signal, sends a <emphasis>SIGTSTP</emphasis> to a running program, thus stopping it and returning control to the shell.</entry></row>
<row><entry><keycap>Ctrl</keycap>+<keycap>C</keycap></entry><entry>The interrupt signal.</entry></row>
<row><entry><keycap>Ctrl</keycap>+<keycap>S</keycap></entry><entry>Suspend output (XOFF)</entry></row>
<row><entry><keycap>Ctrl</keycap>+<keycap>Q</keycap></entry><entry>Resume output (XON)</entry></row>
<row><entry><keycap>Ctrl</keycap>+<keycap>Y</keycap></entry><entry>The <emphasis>delayed suspend</emphasis> character. Causes a running process to be stopped when it attempts to read input from the terminal. Control is returned to the shell, the user can foreground, background or kill the process.</entry></row>
<row><entry><keycap>Ctrl</keycap>+<keycap>Z</keycap></entry><entry>The <emphasis>suspend</emphasis> character. Stops a running program and returns control to the shell.</entry></row>
</tbody>
</tgroup>
</table>
@ -70,8 +72,7 @@
<note><title>SIGKILL and SIGSTOP</title>
<para><emphasis>SIGKILL</emphasis> and <emphasis>SIGSTOP</emphasis> can not be caught, blocked or ignored.</para>
</note>
<para>When killing a process or series of processes, it is common sense to start trying with the least dangerous signal, <emphasis>SIGTERM</emphasis>. That way, programs that care about an orderly shutdown get the chance to follow the procedures that they have been designed to execute when getting the <emphasis>SIGTERM</emphasis> signal, such as cleaning up and closing open files. If you send a <emphasis>SIGKILL</emphasis> to a process, you remove any chance for the process to do a tidy cleanup and shutdown, which might have unfortunate consequences.</para>
<para>But if a clean termination does not work, the <emphasis>INT</emphasis> or<emphasis>KILL</emphasis> signals might be the only way. For instance, when a process does not die using <keycap>Ctrl</keycap>+<keycap>C</keycap>, it is best to use the <command>kill <option>-9</option></command> on that process ID:</para>
<para>When killing a process or series of processes, it is common sense to start trying with the least dangerous signal, <emphasis>SIGTERM</emphasis>. If that does not work, use the <emphasis>INT</emphasis> or<emphasis>KILL</emphasis> signals. For instance, when a process does not die using <keycap>Ctrl</keycap>+<keycap>C</keycap>, it is best to use the <command>kill <option>-9</option></command> on that process ID:</para>
<screen>
<prompt>maud: ~&gt;</prompt> <command>ps <option>-ef</option> | grep <parameter>stuck_process</parameter></command>
maud 5607 2214 0 20:05 pts/5 00:00:02 stuck_process
@ -143,12 +144,10 @@ exit 0
</screen>
</sect3>
</sect2>
</sect1>
<sect1 id="sect_12_03"><title>Summary</title>
<para>Signals can be sent to your programs using the <command>kill</command> command or keyboard shortcuts. These signals can be caught, upon which action can be performed, using the <command>trap</command> statement.</para>
<para>Some programs ignore signals. The only signal that no program can ignore is the <emphasis>KILL</emphasis> signal.</para>
</sect1>
<sect1 id="sect_12_04"><title>Exercises</title>
<para>A couple of practical examples:</para>
@ -156,6 +155,5 @@ exit 0
<listitem><para>Create a script that writes a boot image to a diskette using the <command>dd</command> utility. If the user tries to interrupt the script using <keycap>Ctrl</keycap>+<keycap>C</keycap>, display a message that this action will make the diskette unusable.</para></listitem>
<listitem><para>Write a script that automates the installation of a third-party package of your choice. The package must be downloaded from the Internet. It must be decompressed, unarchived and compiled if these actions are appropriate. Only the actual installation of the package should be uninterruptable.</para></listitem>
</orderedlist>
</sect1>
</chapter>

View File

@ -30,9 +30,6 @@
<imagedata fileref="images/script1.sh.eps" format="EPS"></imagedata></imageobject><imageobject>
<imagedata fileref="images/script1.sh.png" format="PNG"></imagedata>
</imageobject>
<textobject>
<phrase>Example script using statements like "echo hello", "echo hello $USER" and "VARIABLE=value".</phrase>
</textobject>
</mediaobject>
</figure>
@ -106,7 +103,6 @@ I'm giving you back your prompt now.
<prompt>willy:~/scripts&gt;</prompt>
</screen>
</sect2>
</sect1>
<sect1 id="sect_02_02"><title>Script basics</title>
<sect2 id="sect_02_02_01"><title>Which shell will run the script?</title>
@ -194,10 +190,6 @@ And this is a number:
I'm giving you back your prompt now.
+ echo
</screen>
<note><title>Future Bash Features</title>
<para>There is now a full-fledged debugger for Bash, available at <ulink url="http://bashdb.sourceforge.net">SourceForge</ulink>. Right now however, you need a patched version of bash-2.05. The new debugging features might become available in bash-3.0.</para>
</note>
</sect2>
<sect2 id="sect_02_03_02"><title>Debugging on part(s) of the script</title>
<para>Using the <command>set</command> Bash built-in you can run in normal mode those portions of the script of which you are sure they are without fault, and display debugging information only for troublesome zones. Say we are not sure what the <command>w</command> command will do in the example <filename>commented-script1.sh</filename>, then we could enclose it in the script like this:</para>
@ -288,13 +280,11 @@ echo "debug message: now attempting to start w command"; w
echo "Variable VARNAME is now set to $VARNAME."
</screen>
</sect2>
</sect1>
<sect1 id="sect_02_05"><title>Summary</title>
<para>A shell script is a reusable series of commands put in an executable text file. Any text editor can be used to write scripts.</para>
<para>Scripts start with <emphasis>#!</emphasis> followed by the path to the shell executing the commands from the script. Comments are added to a script for your own future reference, and also to make it understandable for other users. It is better to have too many explanations than not enough.</para>
<para>Debugging a script can be done using shell options. Shell options can be used for partial debugging or for analyzing the entire script. Inserting <command>echo</command> commands at strategic locations is also a common troubleshooting technique.</para>
</sect1>
<sect1 id="sect_02_06"><title>Exercises</title>
<para>This exercise will help you to create your first script.</para>
@ -306,6 +296,5 @@ echo "Variable VARNAME is now set to $VARNAME."
<listitem><para>Run the script in normal mode and in debug mode. It should run without errors.</para></listitem>
<listitem><para>Make errors in your script: see what happens if you misspell commands, if you leave out the first line or put something unintelligible there, or if you misspell shell variable names or write them in lower case characters after they have been declared in capitals. Check what the debug comments say about this.</para></listitem>
</orderedlist>
</sect1>
</chapter>

View File

@ -222,9 +222,6 @@ clear
<imageobject>
<imagedata fileref="images/prompt.png" format="PNG"></imagedata>
</imageobject>
<textobject>
<phrase>Prompt 1 is "franky ~&gt;; prompt is then changed with "export PS1="\[\033[1;42m\]$USER is in \w\[\033[0m\] " resulting in a green reverse video prompt displaying username and present working directory in humanly readable form. Prompt for root is set using a similar PS1 configuration to be bright red reverse video.</phrase>
</textobject>
</mediaobject>
</figure>
<para>Most shell scripts execute in a private environment: variables are not inherited by child processes unless they are exported by the parent shell. Sourcing a file containing shell commands is a way of applying changes to your own environment and setting variables in the current shell.</para>
@ -241,7 +238,6 @@ export PS1="[some value]"
echo "PS1 is now set to $PS1"
</screen>
</sect2>
</sect1>
<sect1 id="sect_03_02"><title>Variables</title>
@ -259,7 +255,7 @@ CFLAGS=-O2 -fomit-frame-pointer
COLORTERM=gnome-terminal
CXXFLAGS=-O2 -fomit-frame-pointer
DISPLAY=:0
DOMAIN=hq.xalasys.com
DOMAIN=hq.soti.org
e=
TOR=vi
FCEDIT=vi
@ -275,7 +271,7 @@ HISTFILESIZE=5000
history_control=ignoredups
HISTSIZE=2000
HOME=/nethome/franky
HOSTNAME=octarine.hq.xalasys.com
HOSTNAME=octarine.hq.soti.org
INPUTRC=/etc/inputrc
IRCNAME=franky
JAVA_HOME=/usr/java/j2sdk1.4.0
@ -309,7 +305,7 @@ PATH=/nethome/franky/bin.Linux:/nethome/franky/bin:/usr/local/bin:/usr/local/sbi
PS1=\[\033[1;44m\]franky is in \w\[\033[0m\]
PS2=More input>
PWD=/nethome/franky
SESSION_MANAGER=local/octarine.hq.xalasys.com:/tmp/.ICE-unix/22106
SESSION_MANAGER=local/octarine.hq.soti.org:/tmp/.ICE-unix/22106
SHELL=/bin/bash
SHELL_LOGIN=--login
SHLVL=2
@ -341,7 +337,7 @@ YACC=bison -y
<para>Below is a diff file made by comparing <command>printenv</command> and <command>set</command> output, after leaving out the functions which are also displayed by the <command>set</command> command:</para>
<screen>
<prompt>franky ~&gt;</prompt> <command>diff <filename>set.sorted</filename> <filename>printenv.sorted</filename></command> | <command>grep <parameter>"&lt;"</parameter></command> | <command>awk <parameter>'{ print $2 }'</parameter></command>
BASE=/nethome/franky/.Shell/hq.xalasys.com/octarine.aliases
BASE=/nethome/franky/.Shell/hq.soti.org/octarine.aliases
BASH=/bin/bash
BASH_VERSINFO=([0]="2"
BASH_VERSION='2.05b.0(1)-release'
@ -713,7 +709,6 @@ echo backup succeeded &gt; $LOGFILE
<para>The above is purely an example that everybody can understand, using a small directory and a host on the same subnet. Depending on your bandwidth, the size of the directory and the location of the remote server, it can take an awful lot of time to make backups using this mechanism. For larger directories and lower bandwidth, use <command>rsync</command> to keep the directories at both ends synchronized.</para>
</note>
</sect2>
</sect1>
<sect1 id="sect_03_03"><title>Quoting characters</title>
@ -771,7 +766,6 @@ I'd say: "Go for it!"
<para>A double-quoted string preceded by a dollar sign will cause the string to be translated according to the current locale. If the current locale is <quote>C</quote> or <quote>POSIX</quote>, the dollar sign is ignored. If the string is translated and replaced, the replacement is double-quoted.</para>
</sect2>
</sect1>
<sect1 id="sect_03_04"><title>Shell expansion</title>
@ -851,7 +845,7 @@ Thu Feb 6 10:06:20 CET 2003
<sect2 id="sect_03_04_05"><title>Arithmetic expansion</title>
<para>Arithmetic expansion allows the evaluation of an arithmetic expression and the substitution of the result. The format for arithmetic expansion is:</para><cmdsynopsis><command>$(( EXPRESSION ))</command></cmdsynopsis>
<para>The expression is treated as if it were within double quotes, but a double quote inside the parentheses is not treated specially. All tokens in the expression undergo parameter expansion, command substitution, and quote removal. Arithmetic substitutions may be nested.</para>
<para>Evaluation of arithmetic expressions is done in fixed-width integers with no check for overflow - although division by zero is trapped and recognized as an error. The operators are the same as in the C programming language. In order of decreasing precedence, the list looks like this:</para>
<para>Evaluation of arithmetic expressions is done in fixed-width integers with no check for overflow - although division by zero is trapped and recognized as an error. The operators are roughly the same as in the C programming language. In order of decreasing precedence, the list looks like this:</para>
<table id="table_03_04" frame="all">
<title>Arithmetic operators</title>
<tgroup cols="2" align="left" colsep="1" rowsep="1">
@ -868,7 +862,7 @@ Thu Feb 6 10:06:20 CET 2003
<row><entry>+ and -</entry><entry>addition, subtraction</entry></row>
<row><entry>&lt;&lt; and &gt;&gt;</entry><entry>left and right bitwise shifts</entry></row>
<row><entry>&lt;=, &gt;=, &lt; and &gt;</entry><entry>comparison operators</entry></row>
<row><entry>== and !==</entry><entry>equality and inequality</entry></row>
<row><entry>== and !=</entry><entry>equality and inequality</entry></row>
<row><entry>&amp;</entry><entry>bitwise AND</entry></row>
<row><entry>^</entry><entry>bitwise exclusive OR</entry></row>
<row><entry>|</entry><entry>bitwise OR</entry></row>
@ -904,7 +898,7 @@ leading <quote>0x</quote> or <quote>0X</quote> denotes hexadecimal. Otherwise,
</sect2>
<sect2 id="sect_03_04_07"><title>Word splitting</title>
<para>The shell scans the results of parameter expansion, command substitution, and arithmetic expansion that did not occur within double quotes for word splitting.</para>
<para>The shell treats each character of <varname>$IFS</varname> as a delimiter, and splits the results of the other expansions into words on these characters. If <varname>IF</varname> is unset, or its value is exactly <quote>'&lt;space&gt;&lt;tab&gt;&lt;newline&gt;'</quote>, the default, then any sequence of <varname>IFS</varname> characters serves to delimit words. If <varname>IFS</varname> has a value other than the default, then sequences of the whitespace characters <quote>space</quote> and <quote>Tab</quote> are ignored at the beginning and end of the word, as long as the whitespace character is in the value of <varname>IFS</varname> (an <varname>IFS</varname> whitespace character). Any character in <varname>IFS</varname> that is not <varname>IFS</varname> whitespace, along with any adjacent <varname>IF</varname> whitespace characters, delimits a field. A sequence of <varname>IFS</varname> whitespace characters is also treated as a delimiter. If the value of <varname>IFS</varname> is null, no word splitting occurs.</para>
<para>The shell treats each character of <varname>$IFS</varname> as a delimiter, and splits the results of the other expansions into words on these characters. If <varname>IFS</varname> is unset, or its value is exactly <quote>'&lt;space&gt;&lt;tab&gt;&lt;newline&gt;'</quote>, the default, then any sequence of <varname>IFS</varname> characters serves to delimit words. If <varname>IFS</varname> has a value other than the default, then sequences of the whitespace characters <quote>space</quote> and <quote>Tab</quote> are ignored at the beginning and end of the word, as long as the whitespace character is in the value of <varname>IFS</varname> (an <varname>IFS</varname> whitespace character). Any character in <varname>IFS</varname> that is not <varname>IFS</varname> whitespace, along with any adjacent <varname>IF</varname> whitespace characters, delimits a field. A sequence of <varname>IFS</varname> whitespace characters is also treated as a delimiter. If the value of <varname>IFS</varname> is null, no word splitting occurs.</para>
<para>Explicit null arguments (<quote>""</quote> or <quote>''</quote>) are retained. Unquoted implicit null arguments, resulting from the expansion of parameters that have no values, are removed. If a parameter with no value is expanded within double quotes, a null argument results and is retained.</para>
<note><title>Expansion and word splitting</title><para>If no expansion occurs, no splitting is performed.</para></note>
</sect2>
@ -913,7 +907,6 @@ leading <quote>0x</quote> or <quote>0X</quote> denotes hexadecimal. Otherwise,
<para>When a pattern is used for file name generation, the character <quote>.</quote> at the start of a file name or immediately following a slash must be matched explicitly, unless the shell option <option>dotglob</option> is set. When matching a file name, the slash character must always be matched explicitly. In other cases, the <quote>.</quote> character is not treated specially.</para>
<para>The <varname>GLOBIGNORE</varname> shell variable may be used to restrict the set of file names matching a pattern. If <varname>GLOBIGNORE</varname> is set, each matching file name that also matches one of the patterns in <varname>GLOBIGNORE</varname> is removed from the list of matches. The file names <filename>.</filename> and <filename>..</filename> are always ignored, even when <varname>GLOBIGNORE</varname> is set. However, setting <varname>GLOBIGNORE</varname> has the effect of enabling the <option>dotglob</option> shell option, so all other file names beginning with a <quote>.</quote> will match. To get the old behavior of ignoring file names beginning with a <quote>.</quote>, make <quote>.*</quote> one of the patterns in <varname>GLOBIGNORE</varname>. The <option>dotglob</option> option is disabled when <varname>GLOBIGNORE</varname> is unset.</para>
</sect2>
</sect1>
<sect1 id="sect_03_05"><title>Aliases</title>
@ -946,8 +939,8 @@ alias ping='ping -vc1'
alias sb='ssh blubber'
alias sl='ls'
alias ss='ssh octarine'
alias sss='ssh -C server1.us.xalasys.com'
alias sssu='ssh -C -l root server1.us.xalasys.com'
alias sss='ssh -C server1.us.soti.org'
alias sssu='ssh -C -l root server1.us.soti.org'
alias tar='gtar'
alias tmp='cd /tmp'
alias unaliasall='unalias -a'
@ -991,7 +984,6 @@ bash: dh: command not found
<tip><title>Functions are faster</title><para>Aliases are looked up after functions and thus resolving is slower. While aliases are easier to understand, shell functions are preferred over aliases for almost every purpose.</para></tip>
</sect2>
</sect1>
<sect1 id="sect_03_06"><title>More Bash options</title>
<sect2 id="sect_03_06_01"><title>Displaying options</title>
@ -1068,7 +1060,6 @@ bash: VAR: unbound variable
-rw-rw-r-- 1 willy willy 0 Feb 27 13:37 *
</screen>
</sect2>
</sect1>
@ -1078,7 +1069,6 @@ bash: VAR: unbound variable
<para>Except for the reserved Bourne shell, Bash and special parameters, variable names can be chosen more or less freely.</para>
<para>Because a lot of characters have double or even triple meanings, depending on the environment, Bash uses a system of quoting to take away special meaning from one or multiple characters when special treatment is not wanted.</para>
<para>Bash uses various methods of expanding command line entries in order to determine which commands to execute.</para>
</sect1>
<sect1 id="sect_03_08"><title>Exercises</title>
<para>For this exercise, you will need to read the <command>useradd</command> man pages, because we are going to use the <filename>/etc/skel</filename> directory to hold default shell configuration files, which are copied to the home directory of each newly added user.</para>
@ -1096,6 +1086,5 @@ bash: VAR: unbound variable
<listitem><para>Write a script in which you assign two integer values to two variables. The script should calculate the surface of a rectangle which has these proportions. It should be aired with comments and generate elegant output.</para></listitem>
</orderedlist>
<para>Don't forget to <command>chmod</command> your scripts!</para>
</sect1>
</chapter>

View File

@ -178,7 +178,6 @@ for i in /etc/profile.d/*.sh ; do
</screen>
</sect3>
</sect2>
</sect1>
<sect1 id="sect_04_03"><title>Pattern matching using Bash features</title>
<sect2 id="sect_04_03_01"><title>Character ranges</title>
@ -224,7 +223,6 @@ drwxrwxr-x 4 cathy cathy 4096 Jul 11 2002 OpenOffice.org1.0/
<para>Regular expressions are powerful tools for selecting particular lines from files or output. A lot of UNIX commands use regular expressions: <command>vim</command>, <command>perl</command>, the <application>PostgreSQL</application> database and so on. They can be made available in any language or application using external libraries, and they even found their way to non-UNIX systems. For instance, regular expressions are used in the Excell spreadsheet that comes with the MicroSoft Windows Office suite. In this chapter we got the feel of the <command>grep</command> command, which is indispensable in any UNIX environment.</para>
<note><para>The <command>grep</command> command can do much more than the few tasks we discussed here; we only used it as an example for regular expressions. The GNU <command>grep</command> version comes with plenty of documentation, which you are strongly advised to read!</para></note>
<para>Bash has built-in features for matching patterns and can recognize character classes and ranges.</para>
</sect1>
<sect1 id="sect_04_05"><title>Exercises</title>
<para>These exercises will help you master regular expressions.</para>
@ -243,7 +241,6 @@ drwxrwxr-x 4 cathy cathy 4096 Jul 11 2002 OpenOffice.org1.0/
<listitem><para>Make a script that checks whether a user exists in <filename>/etc/passwd</filename>. For now, you can specify the user name in the script, you don't have to work with arguments and conditionals at this stage.</para></listitem>
<listitem><para>Display configuration files in <filename>/etc</filename> that contain numbers in their names.</para></listitem>
</orderedlist>
</sect1>
</chapter>

View File

@ -222,7 +222,6 @@ This is the final line.
<cmdsynopsis><command>grep <parameter>sed</parameter> <filename>*</filename></command></cmdsynopsis>
</tip>
</sect2>
</sect1>
<sect1 id="sect_05_03"><title>Non-interactive editing</title>
<sect2 id="sect_05_03_01"><title>Reading sed commands from a file</title>
@ -297,12 +296,10 @@ line3
<note><title>Easy sed</title>
<para>Advanced editors, supporting syntax highlighting, can recognize <command>sed</command> syntax. This can be a great help if you tend to forget backslashes and such.</para></note>
</sect2>
</sect1>
<sect1 id="sect_05_04"><title>Summary</title>
<para>The <command>sed</command> stream editor is a powerful command line tool, which can handle streams of data: it can take input lines from a pipe. This makes it fit for non-interactive use. The <command>sed</command> editor uses <command>vi</command>-like commands and accepts regular expressions.</para>
<para>The <command>sed</command> tool can read commands from the command line or from a script. It is often used to perform find-and-replace actions on lines containing a pattern.</para>
</sect1>
<sect1 id="sect_05_05"><title>Exercises</title>
<para>These exercises are meant to further demonstrate what <command>sed</command> can do.</para>
@ -316,6 +313,5 @@ line3
<listitem><para>A long listing of the root directory, <filename>/</filename>, is used for input. Create a file holding <command>sed</command> commands that check for symbolic links and plain files. If a file is a symbolic link, precede it with a line like <quote>--This is a symlink--</quote>. If the file is a plain file, add a string on the same line, adding a comment like <quote>&lt;--- this is a plain file</quote>.</para></listitem>
<listitem><para>Create a script that shows lines containing trailing white spaces from a file. This script should use a <command>sed</command> script and show sensible information to the user.</para></listitem>
</orderedlist>
</sect1>
</chapter>

View File

@ -45,14 +45,11 @@ contain function definitions, loops, conditions and other programming constructs
<imageobject>
<imagedata fileref="images/awk.png" format="PNG"></imagedata>
</imageobject>
<textobject>
<phrase>Fields as interpreted by awk: first column is $1, second column is $2 and so on.</phrase>
</textobject>
</mediaobject>
</figure>
<para>In the output of <command>ls <option>-l</option></command>, there are 9 columns. The <command>print</command> statement uses these fields as follows:</para>
<screen>
<prompt>kelly@octarine ~/test&gt;</prompt> <command>ls <option>-l</option> | awk <parameter>'{ print $9 $5 }'</parameter></command>
<prompt>kelly@octarine ~/test&gt;</prompt> <command>ls <option>-l</option> | awk <parameter>'{ print $5 $9 }'</parameter></command>
160orig
121script.sed
120temp_file
@ -125,9 +122,9 @@ Partition /home : 70% full!
</screen>
<para>Slashes need to be escaped, because they have a special meaning to the <command>awk</command> program.</para>
<para>Below another example where we search the <filename>/etc</filename> directory for files ending in <quote>.conf</quote> and starting with either <quote>a</quote> <emphasis>or</emphasis> <quote>x</quote>, using extended regular expressions:</para>
<para>Below another example where we search the <filename>/etc</filename> directory for files ending in <quote>.conf</quote> and starting with either <quote>a</quote> or <quote>x</quote>:</para>
<screen>
<prompt>kelly is in /etc&gt;</prompt> <command>ls <option>-l</option> | awk <parameter>'/\&lt;(a|x).*\.conf$/ { print $9 }'</parameter></command>
<prompt>kelly is in /etc&gt;</prompt> <command>ls <option>-l</option> | awk <parameter>'/\&lt;[a|x].*\.conf$/ { print $9 }'</parameter></command>
amd.conf
antivir.conf
xcdroast.conf
@ -187,7 +184,6 @@ Partition /usr : 97% full!
<note><title>Syntax highlighting</title>
<para>Awk is a programming language. Its syntax is recognized by most editors that can do syntax highlighting for other languages, such as C, Bash, HTML, etc.</para></note>
</sect2>
</sect1>
<sect1 id="sect_06_03"><title>Gawk variables</title>
<para>As <command>awk</command> is processing the input file, it uses several variables. Some are editable, some are read-only.</para>
@ -318,7 +314,7 @@ Total revenue: 19500
<prompt>kelly@octarine ~/html&gt;</prompt> <command>cat <filename>make-html-from-text.awk</filename></command>
BEGIN { print "&lt;html&gt;\n&lt;head&gt;&lt;title&gt;Awk-generated HTML&lt;/title&gt;&lt;/head&gt;\n&lt;body bgcolor=\"#ffffff\"&gt;\n&lt;pre&gt;" }
{ print $0 }
END { print "&lt;/pre&gt;\n&lt;/body&gt;\n&lt;/html&gt;" }
END { print "&lt;/pre&gt;\n&lt;/body&gt;\n&lt;/html&lt;" }
</screen>
<para>And the command to execute is also much more straightforward when using <command>awk</command> instead of <command>sed</command>:</para>
<screen>
@ -339,7 +335,6 @@ END { print "&lt;/pre&gt;\n&lt;/body&gt;\n&lt;/html&gt;" }
<para>The <command>gawk</command> utility interprets a special-purpose programming language, handling simple data-reformatting jobs with just a few lines of code. It is the free version of the general UNIX <command>awk</command> command.</para>
<para>This tools reads lines of input data and can easily recognize columned output. The <command>print</command> program is the most common for filtering and formatting defined fields.</para>
<para>On-the-fly variable declaration is straightforward and allows for simple calculation of sums, statistics and other operations on the processed input stream. Variables and commands can be put in <command>awk</command> scripts for background processing.</para>
</sect1>
<sect1 id="sect_06_05"><title>Exercises</title>

View File

@ -175,7 +175,7 @@ not a local account
<prompt>anny &gt;</prompt> <command>echo <varname>$num</varname></command>
201
<prompt>anny &gt;</prompt> <command>if <parameter>[ "num" &gt; 150 ]</parameter></command>
<prompt>anny &gt;</prompt> <command>if <parameter>[ "num" &gt; "150" ]</parameter></command>
<prompt>More input&gt;</prompt> <command>then echo ; echo <parameter>"you've worked hard enough for today."</parameter></command>
<prompt>More input&gt;</prompt> <command>echo ; fi</command>
@ -211,9 +211,15 @@ fi
</screen>
<para>With Bash, you can shorten this type of construct. The compact equivalent of the above test is as follows:</para>
<screen>
[ "$(whoami)" != 'root' ] &amp;&amp; echo you are using a non-privileged account
[ "$(whoami)" != 'root' ] &amp;&amp; ( echo you are using a non-privileged account; exit 1 )
</screen>
<para>Regular expressions may also be used:</para>
<note><title>Real Programmers</title>
<para>Most programmers will even prefer to use <command>test</command>, which is equivalent to using the square brackets, like this:</para>
<screen>
test "$(whoami)" != 'root' &amp;&amp; ( echo you are using a non-privileged account; exit 1)
</screen>
</note>
<para>Regular expressions may also be used in comparisons:</para>
<screen>
<prompt>anny &gt;</prompt> <command><varname>gender</varname>=<parameter>"female"</parameter></command>
@ -268,9 +274,6 @@ your account is managed from the local /etc/passwd file
<imagedata fileref="images/penguin.sh.eps" format="EPS"></imagedata></imageobject><imageobject>
<imagedata fileref="images/penguin.sh.png" format="PNG"></imagedata>
</imageobject>
<textobject>
<phrase>Simple if/then/else/fi construct: if [ "$1" == fish ]; then echo "Tux likes this"; else echo "Tux wants fish!"; fi</phrase>
</textobject>
</mediaobject>
</figure>
<para>Here's another example, using two arguments:</para>
@ -364,7 +367,7 @@ fi
<cmdsynopsis><command>CONSEQUENT-COMMANDS;</command></cmdsynopsis>
<cmdsynopsis><command>elif MORE-TEST-COMMANDS; then</command></cmdsynopsis>
<cmdsynopsis><command>MORE-CONSEQUENT-COMMANDS;</command></cmdsynopsis>
<cmdsynopsis><command>else ALTERNATE-CONSEQUENT-COMMANDS;</command></cmdsynopsis>
<cmdsynopsis><command>else ALTERNATE-CONSEQUENT-COMMANDS; then</command></cmdsynopsis>
<cmdsynopsis><command>fi</command></cmdsynopsis>
<para>The <command>TEST-COMMANDS</command> list is executed, and if its return status is zero, the <command>CONSEQUENT-COMMANDS</command> list is executed. If
<command>TEST-COMMANDS</command> returns a non-zero status, each <command>elif</command> list is executed in turn, and if its exit status is zero, the corresponding <command>MORE-CONSEQUENT-COMMANDS</command> is executed and the command completes. If <command>else</command> is followed by an <command>ALTERNATE-CONSEQUENT-COMMANDS</command> list, and the final command in the final <command>if</command> or <command>elif</command> clause has a non-zero exit status, then <command>ALTERNATE-CONSEQUENT-COMMANDS</command> is executed. The return status is the exit status of the last command executed, or zero if no condition tested true.</para>
@ -390,7 +393,7 @@ fi
</sect2>
<sect2 id="sect_07_02_03"><title>Nested if statements</title>
<para>Inside the <command>if</command> statement, you can use another <command>if</command> statement. You may use as many levels of nested <command>if</command>s as you can logically manage.</para>
<para>Inside the <command>if</command> statement, you can use another <command>if</command> statement. You may virtually use as many levels of nested <command>if</command>s as you can logically manage (actually the number of nested <command>if</command>s is limited to 2500, but it is dubious that anybody would ever need that many).</para>
<para>This is an example testing leap years:</para>
<screen>
<prompt>anny ~/testdir&gt;</prompt> <command>cat <filename>testleap.sh</filename></command>
@ -427,9 +430,6 @@ This is not a leap year.
<imagedata fileref="images/leaptest.sh.eps" format="EPS"></imagedata></imageobject><imageobject>
<imagedata fileref="images/leaptest.sh.png" format="PNG"></imagedata>
</imageobject>
<textobject>
<phrase>year=`date +%Y`; if (( ("$year" % 400) == "0" )) || (( ("$year" % 4 == "0") &amp;&amp; ("$year" % 100 != "0") )); then echo "this is a leap year."; else echo "not a leap year"; fi</phrase>
</textobject>
</mediaobject>
</figure>
<para>We use the double brackets for testing an arithmetic expression, see <xref linkend="sect_03_04_05" />. This is equivalent to the <command>let</command> statement. You will get stuck using angular brackets here, if you try something like <command>$[$year % 400]</command>, because here, the angular brackets don't represent an actual command by themselves.</para>
@ -609,7 +609,6 @@ esac
<para>In this chapter we learned how to build conditions into our scripts so that different actions can be undertaken upon success or failure of a command. The actions can be determined using the <command>if</command> statement. This allows you to perform arithmetic and string comparisons, and testing of exit code, input and files needed by the script.</para>
<para>A simple <command>if/then/fi</command> test often preceeds commands in a shell script in order to prevent output generation, so that the script can easily be run in the background or through the <application>cron</application> facility. More complex definitions of conditions are usually put in a <command>case</command> statement.</para>
<para>Upon successful condition testing, the script can explicitly inform the parent using the <command>exit 0</command> status. Upon failure, any other number may be returned. Based on the return code, the parent program can take appropriate action.</para>
</sect1>
<sect1 id="sect_07_05"><title>Exercises</title>
<para>Here are some ideas to get you started using <command>if</command> in scripts:</para>
@ -625,6 +624,5 @@ esac
<para>The script should also check for available diskspace. Keep in mind that at any given moment you could have the data in your home directory, the data in the <filename>.tar</filename> file and the data in the compressed archive all together on your disk. If there is not enough diskspace, exit with an error message in the log file.</para>
<para>The script should clean up the compressed archive before it exits.</para></listitem>
</orderedlist>
</sect1>
</chapter>

View File

@ -152,7 +152,6 @@ Usage of the feed script: ./feed.sh food-on-menu animal-name
</table>
<para>For more information about the <command>printf</command> command and the way it allows you to format output, see the Bash info pages.</para>
</sect2>
</sect1>
<sect1 id="sect_08_02"><title>Catching user input</title>
<sect2 id="sect_08_02_01"><title>Using the read built-in command</title>
@ -570,12 +569,10 @@ Transaction(s) Complete
</sect3>
</sect2>
</sect1>
<sect1 id="sect_08_03"><title>Summary</title>
<para>In this chapter, we learned how to provide user comments and how to prompt for user input. This is usually done using the <command>echo</command>/<command>read</command> combination. We also discussed how files can be used as input and output using file descriptors and redirection, and how this can be combined with getting input from the user.</para>
<para>We stressed the importance of providing ample message for the users of our scripts. As always when others use your scripts, it is better to give too much information than not enough. <emphasis>Here</emphasis> documents is a type of shell construct that allows creation of lists, holding choices for the users. This construct can also be used to execute otherwise interactive tasks in the background, without intervention.</para>
</sect1>
<sect1 id="sect_08_04"><title>Exercises</title>
<para>These exercises are practical applications of the constructs discussed in this chapter. When writing the scripts, you may test by using a test directory that does not contain too much data. Write each step, then test that portion of code, rather than writing everything at once.</para>
@ -593,7 +590,7 @@ Transaction(s) Complete
<listitem><para>Compress the backup using any compression tool. Inform the user that the script is doing this, because it might take some time, during which the user might start worrying if no output appears on the screen.</para></listitem>
<listitem><para>Print a message informing the user about the size of the compressed backup.</para></listitem>
</itemizedlist>
<para>See <command>info tar</command> or <ulink url="http://tille.xalasys.com/training/tldp/c4540.html#sect_09_01_01">Introduction to Linux</ulink>, chapter 9: <quote>Preparing your data</quote> for background information.</para>
<para>See <command>info tar</command> or <ulink url="http://tille.soti.org/training/tldp/c4540.html#sect_09_01_01">Introduction to Linux</ulink>, chapter 9: <quote>Preparing your data</quote> for background information.</para>
</listitem>
<listitem><para>Write a script called <filename>simple-useradd.sh</filename> that adds a local user to the system. This script should:</para>
<itemizedlist>
@ -607,6 +604,5 @@ Transaction(s) Complete
</listitem>
<listitem><para>Rewrite the script from <xref linkend="sect_07_02_01_04" /> so that it reads input from the user instead of taking it from the first argument.</para></listitem>
</orderedlist>
</sect1>
</chapter>

View File

@ -55,7 +55,6 @@ done
<para>Since we don't do a line count here, there is no way of knowing the line number from which to start deleting lines until reaching the end. The problem is solved using <command>tac</command>, which reverses the lines in a file.</para>
</sect3>
</sect2>
</sect1>
<sect1 id="sect_09_02"><title>The while loop</title>
<sect2 id="sect_09_02_01"><title>What is it?</title>
@ -84,31 +83,14 @@ done
</sect3>
<sect3 id="sect_09_02_02_02"><title>Nested while loops</title>
<para>The example below was written to copy pictures that are made with a webcam to a web directory. Every five minutes a picture is taken. Every hour, a new directory is created, holding the images for that hour. Every day, a new directory is created containing 24 subdirectories. The script runs in the background.</para>
<screen>
#!/bin/bash
# This script copies files from my homedirectory into the webserver directory.
# (use scp and SSH keys for a remote directory)
# A new directory is created every hour.
PICSDIR=/home/carol/pics
WEBDIR=/var/www/carol/webcam
while true; do
DATE=`date +%Y%m%d`
HOUR=`date +%H`
mkdir $WEBDIR/"$DATE"
while [ $HOUR -ne "00" ]; do
DESTDIR=$WEBDIR/"$DATE"/"$HOUR"
mkdir "$DESTDIR"
mv $PICDIR/*.jpg "$DESTDIR"/
sleep 3600
HOUR=`date +%H`
done
done
</screen>
<figure><title>Nested while loops - picturesort.sh</title>
<mediaobject>
<imageobject>
<imagedata fileref="images/picturesort.sh.eps" format="EPS"></imagedata></imageobject><imageobject>
<imagedata fileref="images/picturesort.sh.png" format="PNG"></imagedata>
</imageobject>
</mediaobject>
</figure>
<para>Note the use of the <command>true</command> statement. This means: continue execution until we are forcibly interrupted (with <command>kill</command> or <keycap>Ctrl</keycap>+<keycap>C</keycap>).</para>
<para>This small script can be used for simulation testing; it generates files:</para>
<screen>
@ -121,10 +103,7 @@ touch pic-`date +%s`.jpg
sleep 300
done
</screen>
<para>Note the use of the <command>date</command> command to generate all kinds of file and directory names. See the man page for more.</para>
<note><title>Use the system</title>
<para>The previous example is for the sake of demonstration. Regular checks can easily be achieved using the system's <emphasis>cron</emphasis> facility. Do not forget to redirect output and errors when using scripts that are executed from your crontab!</para>
</note>
<para>Note the use of the <command>date</command> command to generate all kinds of file and directory names.</para>
</sect3>
<sect3 id="sect_09_02_02_03"><title>Using keyboard input to control the while loop</title>
<para>This script can be interrupted by the user when a <keycap>Ctrl</keycap>+<keycap>C</keycap> sequence is entered:</para>
@ -198,7 +177,6 @@ echo "Exiting."
</sect3>
</sect2>
</sect1>
<sect1 id="sect_09_03"><title>The until loop</title>
<sect2 id="sect_09_03_01"><title>What is it?</title>
@ -210,43 +188,16 @@ echo "Exiting."
<sect2 id="sect_09_03_02"><title>Example</title>
<para>An improved <filename>picturesort.sh</filename> script (see <xref linkend="sect_09_02_02_02" />), which tests for available disk space. If not enough disk space is available, remove pictures from the previous months:</para>
<screen>
#!/bin/bash
# This script copies files from my homedirectory into the webserver directory.
# A new directory is created every hour.
# If the pics are taking up too much space, the oldest are removed.
while true; do
DISKFUL=$(df -h $WEBDIR | grep -v File | awk '{print $5 }' | cut -d "%" -f1 -)
until [ $DISKFUL -ge "90" ]; do
DATE=`date +%Y%m%d`
HOUR=`date +%H`
mkdir $WEBDIR/"$DATE"
while [ $HOUR -ne "00" ]; do
DESTDIR=$WEBDIR/"$DATE"/"$HOUR"
mkdir "$DESTDIR"
mv $PICDIR/*.jpg "$DESTDIR"/
sleep 3600
HOUR=`date +%H`
done
DISKFULL=$(df -h $WEBDIR | grep -v File | awk '{ print $5 }' | cut -d "%" -f1 -)
done
TOREMOVE=$(find $WEBDIR -type d -a -mtime +30)
for i in $TOREMOVE; do
rm -rf "$i";
done
done
</screen>
<figure><title>More nested while loops - safesort.sh</title>
<mediaobject>
<imageobject>
<imagedata fileref="images/safesort.sh.eps" format="EPS"></imagedata></imageobject><imageobject>
<imagedata fileref="images/safesort.sh.png" format="PNG"></imagedata>
</imageobject>
</mediaobject>
</figure>
<para>Note the initialization of the <varname>HOUR</varname> and <varname>DISKFULL</varname> variables and the use of options with <command>ls</command> and <command>date</command> in order to obtain a correct listing for <varname>TOREMOVE</varname>.</para>
</sect2>
</sect1>
<sect1 id="sect_09_04"><title>I/0 redirection and loops</title>
<sect2 id="sect_09_04_01"><title>Input redirection</title>
@ -279,7 +230,6 @@ done
</screen>
<para>Files are compressed before they are moved into the archive directory.</para>
</sect2>
</sect1>
<sect1 id="sect_09_05"><title>Break and continue</title>
<sect2 id="sect_09_05_01"><title>The break built-in</title>
@ -419,7 +369,6 @@ new name for TEST is test
</screen>
<para>The <command>tr</command> is part of the <emphasis>textutils</emphasis> package; it can perform all kinds of character transformations.</para>
</sect2>
</sect1>
<sect1 id="sect_09_06"><title>Making menus with the select built-in</title>
<sect2 id="sect_09_06_01"><title>General</title>
@ -488,7 +437,6 @@ rm "$QUIT"
<para>Any statement within a <command>select</command> construct can be another <command>select</command> loop, enabling (a) submenu(s) within a menu.</para>
<para>By default, the <varname>PS3</varname> variable is not changed when entering a nested <command>select</command> loop. If you want a different prompt in the submenu, be sure to set it at the appropriate time(s).</para>
</sect2>
</sect1>
<sect1 id="sect_09_07"><title>The shift built-in</title>
<sect2 id="sect_09_07_01"><title>What does it do?</title>
@ -515,6 +463,7 @@ while (( "$#" )); do
if [[ "$(ls $1)" == "" ]]; then
echo "Empty directory, nothing to be done."
shift
else
find $1 -type f -a -atime +365 -exec rm -i {} \;
fi
@ -523,11 +472,6 @@ shift
done
</screen>
<note><title>-exec vs. xargs</title>
<para>The above <command>find</command> command can be replaced with the following:</para>
<cmdsynopsis><command>find <option>options</option> | xargs [commands_to_execute_on_found_files</command></cmdsynopsis>
<para>The <command>xargs</command> command builds and executes command lines from standard input. This has the advantage that the command line is filled until the system limit is reached. Only then will the command to execute be called, in the above example this would be <command>rm</command>. If there are more arguments, a new command line will be used, until that one is full or until there are no more arguments. The same thing using <command>find <option>-exec</option></command> calls on the command to execute on the found files every time a file is found. Thus, using <command>xargs</command> greatly speeds up your scripts and the performance of your machine.</para>
</note>
<para>In the next example, we modified the script from <xref linkend="sect_08_02_04_04" /> so that it accepts multiple packages to install at once:</para>
<screen>
#!/bin/bash
@ -543,14 +487,12 @@ while (($#)); do
done
</screen>
</sect2>
</sect1>
<sect1 id="sect_09_08"><title>Summary</title>
<para>In this chapter, we discussed how repetitive commands can be incorporated in loop constructs. Most common loops are built using the <command>for</command>, <command>while</command> or <command>until</command> statements, or a combination of these commands. The <command>for</command> loop executes a task a defined number of times. If you don't know how many times a command should execute, use either <command>until</command> or <command>while</command> to specify when the loop should end.</para>
<para>Loops can be interrupted or reiterated using the <command>break</command> and <command>continue</command> statements.</para>
<para>A file can be used as input for a loop using the input redirection operator, loops can also read output from commands that is fed into the loop using a pipe.</para>
<para>The <command>select</command> construct is used for printing menus in interactive scripts. Looping through the command line arguments to a script can be done using the <command>shift</command> statement.</para>
</sect1>
<sect1 id="sect_09_09"><title>Exercises</title>
<para>Remember: when building scripts, work in steps and test each step before incorporating it in your script.</para>
@ -571,6 +513,5 @@ done
</itemizedlist>
</listitem>
</orderedlist>
</sect1>
</chapter>

View File

@ -1386,13 +1386,6 @@
</glossdiv>
<glossdiv id="X"><title>X</title>
<glossentry id="xargs">
<glossterm>xargs</glossterm>
<glossdef>
<para>Build and execute command lines from standard input.</para>
</glossdef>
</glossentry>
<glossentry id="xauth">
<glossterm>xauth</glossterm>
<glossdef>

View File

@ -139,7 +139,7 @@
<glossentry id="charclass">
<glossterm>character classes</glossterm>
<glossdef>
<para><xref linkend="sect_04_02_02_03" />, <xref linkend="sect_04_03_02" /></para>
<para><xref linkend="sect_04_02_02_02" />, <xref linkend="sect_04_03_02" /></para>
</glossdef>
</glossentry>
@ -255,7 +255,7 @@
<glossentry id="else">
<glossterm>else</glossterm>
<glossdef>
<para><xref linkend="sect_07_02_01" /></para>
<para><xref linkend="Sect_07_02_01" /></para>
</glossdef>
</glossentry>
@ -338,7 +338,7 @@
<glossentry id="exit">
<glossterm>exit</glossterm>
<glossdef>
<para><xref linkend="sect_07_02_05" /></para>
<para><xref linkend="sect_07__02_06" /></para>
</glossdef>
</glossentry>
<glossentry id="exitstatus">
@ -380,7 +380,7 @@
<glossentry id="fileexpand">
<glossterm>file name expansion</glossterm>
<glossdef>
<para><xref linkend="sect_03_04_08" /></para>
<para><xref linkend="sect_03_04_09" /></para>
</glossdef>
</glossentry>
<glossentry id="findreplace">
@ -948,7 +948,7 @@
<glossentry id="stdout">
<glossterm>standard output</glossterm>
<glossdef>
<para><xref linkend="sect_08_02_03_01" /></para>
<para><xref linkend="sect_08_02_03_0" /></para>
</glossdef>
</glossentry>