comments from readers

This commit is contained in:
tille 2006-09-28 09:42:45 +00:00
parent 6efa959449
commit b3221c8f43
9 changed files with 53 additions and 44 deletions

View File

@ -27,7 +27,7 @@ shell, intuitive and flexible. Probably most advisable for beginning users whil
of add-ons and plug-ins. This means that the Bourne Again shell is compatible with the Bourne shell: commands that work in <command>sh</command>, also work in
<command>bash</command>. However, the reverse is not always the case. All examples and exercises in this book use <command>bash</command>.</para></listitem>
<listitem><para><command>csh</command> or C shell: the syntax of this shell resembles that of the C programming language. Sometimes asked for by programmers.</para></listitem>
<listitem><para><command>tcsh</command> or Turbo C shell: a superset of the common C shell, enhancing user-friendliness and speed.</para></listitem>
<listitem><para><command>tcsh</command> or TENEX C shell: a superset of the common C shell, enhancing user-friendliness and speed. That is why some also call it the Turbo C shell.</para></listitem>
<listitem><para><command>ksh</command> or the Korn shell: sometimes appreciated
by people with a UNIX background. A superset of the Bourne shell; with standard configuration a nightmare for beginning users.</para></listitem>
</itemizedlist>

View File

@ -70,7 +70,7 @@ The exit code of this function is 0.
<command>if <parameter>[ $RETVAL -eq 0 ]</parameter>; then
&lt;start the daemon&gt;</command>
</screen>
<para>Or like this example from the <filename>/etc/init.d/amd</filename> script, where Bash's optimazation features are used:</para>
<para>Or like this example from the <filename>/etc/init.d/amd</filename> script, where Bash's optimization features are used:</para>
<screen>
<command><parameter>[ $RETVAL = 0 ]</parameter> &amp;&amp; touch <filename>/var/lock/subsys/amd</filename></command>
</screen>

View File

@ -394,7 +394,7 @@ bash: export: `1number=1': not a valid identifier
<screen>
<prompt>franky ~&gt;</prompt> <command><varname>MYVAR1</varname>=<parameter>"2"</parameter></command>
<prompt>franky ~7gt;</prompt> <command>echo <varname>$MYVAR1</varname></command>
<prompt>franky ~&gt;</prompt> <command>echo <varname>$MYVAR1</varname></command>
2
<prompt>franky ~&gt;</prompt> <command><varname>first_name</varname>=<parameter>"Franky"</parameter></command>

View File

@ -138,11 +138,8 @@ floppy:x:19:
xfs:x:43:
nfsnobody:x:65534:
postfix:x:89:
<prompt>cathy ~&gt;</prompt> <command>ls <filename>*[1-9].xml</filename></command>
app1.xml chap1.xml chap2.xml chap3.xml chap4.xml
</screen>
<para>In the example, all the lines containing either a <quote>y</quote> or <quote>f</quote> character are first displayed, followed by an example of using a range with the <command>ls</command> command.</para>
<para>In the example, all the lines containing either a <quote>y</quote> or <quote>f</quote> character are displayed.</para>
</sect3>
<sect3 id="sect_04_02_02_04"><title>Wildcards</title>
@ -169,11 +166,11 @@ cheesecloth
cheetah
--output omitted--
</screen>
<para>If you want to find the literal asterisk character in a file or output, use <command>grep <option>-F</option></command>:</para>
<para>If you want to find the literal asterisk character in a file or output, use single quotes. Cathy in the example below first tries finding the asterisk character in <filename>/etc/profile</filename> without using quotes, which does not return any lines. Using quotes, output is generated:</para>
<screen>
<prompt>cathy ~&gt;</prompt> <command>grep <parameter>*</parameter> <filename>/etc/profile</filename></command>
<prompt>cathy ~&gt;</prompt> <command>grep <option>-F</option> <parameter>'*'</parameter> <filename>/etc/profile</filename></command>
<prompt>cathy ~&gt;</prompt> <command>grep <parameter>'*'</parameter> <filename>/etc/profile</filename></command>
for i in /etc/profile.d/*.sh ; do
</screen>
</sect3>

View File

@ -344,7 +344,7 @@ END { print "&lt;/pre&gt;\n&lt;/body&gt;\n&lt;/html&gt;" }
<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>
<para>Other things you should know about <command>awk</command>:</para>
<itemizedlist>
<listitem><para>The language remains well-known on UNIX and alikes, but for executing similar tasks, <application>Perl</application> is now more commonly used. However, <command>awk</command> has a much steeper learning curve. In other words, <application>Perl</application> is more difficult to learn.</para></listitem>
<listitem><para>The language remains well-known on UNIX and alikes, but for executing similar tasks, <application>Perl</application> is now more commonly used. However, <command>awk</command> has a much steeper learning curve (meaning that you learn a lot in a very short time). In other words, <application>Perl</application> is more difficult to learn.</para></listitem>
<listitem><para>Both <application>Perl</application> and <command>awk</command> share the reputation of being incomprehensible, even to the actual authors of the programs that use these languages. So document your code!</para></listitem>
</itemizedlist>
</sect1>

View File

@ -197,7 +197,7 @@ WEEKOFFSET=$[ $(date +"%V") % 2 ]
if [ $WEEKOFFSET -eq "0" ]; then
echo "Sunday evening, put out the garbage cans." | mail -s "Garbage cans out" your@your_domain.org
fi
</screen>
</sect3>
@ -253,6 +253,9 @@ How come the lady hasn't got a drink yet?
<prompt>freddy scripts&gt;</prompt>
</screen>
<important><title>[] vs. [[]]</title>
<para>Contrary to <parameter>[</parameter>, <parameter>[[</parameter> prevents word splitting of variable values. So, if <varname>VAR="var with spaces"</varname>, you do not need to double quote <varname>$VAR</varname> in a test - eventhough using quotes remains a good habit. Also, <parameter>[[</parameter> prevents pathname expansion, so literal strings with wildcards do not try to expand to filenames. Using <parameter>[[</parameter>, <parametrer>==</parameter> and <parameter>!=</parameter> interpret strings to the right as shell glob patterns to be matched against the value to the left, for instance: <parameter>[[ "value" == val* ]]</parameter>.</para>
</important>
<para>Like the <command>CONSEQUENT-COMMANDS</command> list following the <command>then</command> statement, the <command>ALTERNATE-CONSEQUENT-COMMANDS</command> list following the <command>else</command> statement can hold any UNIX-style command that returns an exit status.</para>
<para>Another example, extending the one from <xref linkend="sect_07_01_02_01" />:</para>
<screen>
@ -289,7 +292,7 @@ your account is managed from the local /etc/passwd file
#!/bin/bash
# This script prints a message about your weight if you give it your
# weight in kilos and hight in centimeters.
# weight in kilos and height in centimeters.
weight="$1"
height="$2"
@ -317,7 +320,7 @@ You should eat a bit more fat.
#!/bin/bash
# This script prints a message about your weight if you give it your
# weight in kilos and hight in centimeters.
# weight in kilos and height in centimeters.
if [ ! $# == 2 ]; then
echo "Usage: $0 weight_in_kilos length_in_centimeters"
@ -365,6 +368,9 @@ else
fi
</screen>
<para>Note that the file is referred to using a variable; in this case it is the first argument to the script. Alternatively, when no arguments are given, file locations are usually stored in variables at the beginning of a script, and their content is referred to using these variables. Thus, when you want to change a file name in a script, you only need to do it once.</para>
<tip><title>Filenames with spaces</title>
<para>The above example will fail if the value of <varname>$1</varname> can be parsed as multiple words. In that case, the <command>if</command> command can be fixed either using double quotes around the filename, or by using <parameter>[[</parameter> instead of <parameter>[</parameter>.</para>
</tip>
</sect3>
</sect2>
<sect2 id="sect_07_02_02"><title>if/then/elif/else constructs</title>
@ -547,7 +553,7 @@ case $space in
Message="I'm drowning here! There's a partition at $space %!"
;;
*)
Message="I seem to be running with an nonexitent amount of disk space..."
Message="I seem to be running with an nonexistent amount of disk space..."
;;
esac
@ -630,6 +636,7 @@ esac
<listitem><para>Edit the <filename>leaptest.sh</filename> script from <xref linkend="sect_07_02_04" /> so that it requires one argument, the year. Test that exactly one argument is supplied.</para></listitem>
<listitem><para>Write a script called <filename>whichdaemon.sh</filename> that checks if the <command>httpd</command> and <command>init</command> daemons are running on your system. If an <command>httpd</command> is running, the script should print a message like, <quote>This machine is running a web server.</quote> Use <command>ps</command> to check on processes.</para></listitem>
<listitem><para>Write a script that makes a backup of your home directory on a remote machine using <command>scp</command>. The script should report in a log file, for instance <filename>~/log/homebackup.log</filename>. If you don't have a second machine to copy the backup to, use <command>scp</command> to test copying it to the localhost. This requires SSH keys between the two hosts, or else you have to supply a password. The creation of SSH keys is explained in <command>man <parameter>ssh-keygen</parameter></command>.</para>
<listitem><para>Adapt the script from the first example in <xref linkend="sect_07_03_01" /> to include the case of exactly 90% disk space usage, and lower than 10% disk space usage.</para></listitem>
<para>The script should use <command>tar <option>cf</option></command> for the creation of the backup and <command>gzip</command> or <command>bzip2</command> for compressing the <filename>.tar</filename> file. Put all filenames in variables. Put the name of the remote server and the remote directory in a variable. This will make it easier to re-use the script or to make changes to it in the future.</para>
<para>The script should check for the existence of a compressed archive. If this exists, remove it first in order to prevent output generation.</para>
<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>

View File

@ -296,7 +296,18 @@ lrwx------ 1 michel michel 64 Jan 23 12:11 /proc/self/fd/0 -> /dev/pts/6
lrwx------ 1 michel michel 64 Jan 23 12:11 /proc/self/fd/1 -> /dev/pts/6
lrwx------ 1 michel michel 64 Jan 23 12:11 /proc/self/fd/2 -> /dev/pts/6
</screen>
<para>Note that each process has its own view of the files under <filename>/proc/self</filename>, as it is actually a symbolic link to <filename>/proc/&lt;process_ID&gt;</filename>.</para>
<para>You might want to check <command>info MAKEDEV</command> and <command>info proc</command> for more information about <filename>/proc</filename> subdirectories and the way your system handles standard file descriptors for each running process.</para>
<para>When excuting a given command, the following steps are excuted, in order:</para>
<itemizedlist>
<listitem><para>If the standard output of a previous command is being piped to the standard input of the current command, then <filename>/proc/&lt;current_process_ID&gt;/fd/0</filename> is updated to target the same anonymous pipe as <filename>/proc/&lt;previous_process_ID/fd/1</filename>.</para></listitem>
<listitem><para>If the standard output of the current command is being piped to the standard input of the next command, then <filename>/proc/&lt;current_process_ID&gt;/fd/1</filename> is updated to target another anonymous pipe.</para></listitem>
<listitem><para>Redirection for the current command is processed from left to right.</para></listitem>
<listitem><para>Redirection <quote>N&gt;&amp;M</quote> or <quote>N&lt;&amp;M</quote> after a command has the effect of creating or updating the symbolic link <filename>/proc/self/fd/N</filename> with the same target as the symbolic link <filename>/proc/self/fd/M</filename>.</para></listitem>
<listitem><para>The redirections <quote>N&gt; file</quote> and <quote>N&lt; file</quote> have the effect of creating or updating the symbolic link <filename>/proc/self/fd/N</filename> with the target file.</para></listitem>
<listitem><para>File descriptor closure <quote>N&gt;&amp;-</quote> has the effect of deleting the symbolic link <filename>/proc/self/fd/N</filename>.</para></listitem>
<listitem><para>Only now is the current command executed.</para></listitem>
</itemizedlist>
<para>When you run a script from the command line, nothing much changes because the child shell process will use the same file descriptors as the parent. When no such parent is available, for instance when you run a script using the <emphasis>cron</emphasis> facility, the standard file descriptors are pipes or other (temporary) files, unless some form of redirection is used. This is demonstrated in the example below, which shows output from a simple <command>at</command> script:</para>
<screen>
<prompt>michel ~&gt;</prompt> <command>date</command>
@ -336,11 +347,11 @@ lr-x------ 1 michel michel 64 Jan 24 11:32 3 -> /proc/21974/fd
<para>From the previous examples, it is clear that you can provide input and output files for a script (see <xref linkend="sect_08_02_04" /> for more), but some tend to forget about redirecting errors - output which might be depended upon later on. Also, if you are lucky, errors will be mailed to you and eventual causes of failure might get revealed. If you are not as lucky, errors will cause your script to fail and won't be caught or sent anywhere, so that you can't start to do any worthwhile debugging.</para>
<para>When redirecting errors, note that the order of precedence is significant. For example, this command, issued in <filename>/var/spool</filename></para>
<screen>
<command>ls <option>-l</option> <filename>*</filename> <parameter>2</parameter> &gt; <filename>/var/tmp/unaccessible-in-spool</filename></command>
<command>ls <option>-l</option> <filename>*</filename> <parameter>2</parameter>&gt; <filename>/var/tmp/unaccessible-in-spool</filename></command>
</screen>
<para>will redirect output of the <command>ls</command> command to the file <filename>unaccessible-in-spool</filename> in <filename>/var/tmp</filename>. The command</para>
<para>will redirect standard output of the <command>ls</command> command to the file <filename>unaccessible-in-spool</filename> in <filename>/var/tmp</filename>. The command</para>
<screen>
<command>ls <option>-l</option> <filename>*</filename> &gt; <filename>/var/tmp/spoollist</filename> <parameter>2</parameter> &gt;&amp; <parameter>1</parameter></command>
<command>ls <option>-l</option> <filename>*</filename> &gt; <filename>/var/tmp/spoollist</filename> <parameter>2</parameter>&gt;&amp;<parameter>1</parameter></command>
</screen>
<para>will direct both standard input and standard error to the file <filename>spoollist</filename>. The command</para>
<screen>
@ -374,13 +385,13 @@ This text is printed at the end of each print job.
</sect3>
<sect3 id="sect_08_02_04_02"><title>Read and exec</title>
<sect4 id="sect_08_02_04_02_01"><title>Assigning file descriptors to files</title>
<para>Another way of looking at file descriptors is thinking of them as a way to assign a numeric value to a file. Instead of using the file name, you can use the file descriptor number. The <command>exec</command> built-in command is used to assign a file descriptor to a file. Use</para>
<para>Another way of looking at file descriptors is thinking of them as a way to assign a numeric value to a file. Instead of using the file name, you can use the file descriptor number. The <command>exec</command> built-in command can be used to replace the shell of the current process or to alter the file descriptors of the current shell. For example, it can be used to assign a file descriptor to a file. Use</para>
<cmdsynopsis><command>exec fdN&gt; <filename>file</filename></command></cmdsynopsis>
<para>for assigning file descriptor N to <filename>file</filename> for output, and</para>
<cmdsynopsis><command>exec fdN&lt; <filename>file</filename></command></cmdsynopsis>
<para>for assigning file descriptor N to <filename>file</filename> for input. After a file descriptor has been assigned to a file, it can be used with the shell redirection operators, as is demonstrated in the following example:</para>
<screen>
<prompt>michel ~&gt;</prompt> <command>exec <filename>4</filename> &gt; <filename>result.txt</filename></command>
<prompt>michel ~&gt;</prompt> <command>exec <filename>4</filename>&gt; <filename>result.txt</filename></command>
<prompt>michel ~&gt;</prompt> <command>filter <filename>body.txt</filename> | cat <filename>header.txt /dev/fd/0 footer.txt</filename> &gt;&amp; <filename>4</filename></command>
@ -410,8 +421,10 @@ rm "$CONFIG" 2&gt;/dev/null
echo "Output will be saved in $CONFIG."
# create fd 7 with same target as fd 0 (save stdin "value")
exec 7&lt;&amp;0
# update fd 0 to target file /etc/passwd
exec &lt; /etc/passwd
# Read the first line of /etc/passwd
@ -421,6 +434,7 @@ echo "Saving root account info..."
echo "Your root account info:" &gt;&gt; "$CONFIG"
echo $rootpasswd &gt;&gt; "$CONFIG"
# update fd 0 to target fd 7 target (old fd 0 target); delete fd 7
exec 0&lt;&amp;7 7&lt;&amp;-
echo -n "Enter comment or [ENTER] for no comment: "
@ -481,13 +495,17 @@ in central DNS
INPUTDIR="$1"
# fd 6 targets fd 1 target (console out) in current shell
exec 6&gt;&amp;1
# fd 1 targets pipe, fd 2 targets fd 1 target (pipe),
# fd 1 targets fd 6 target (console out), fd 6 closed, execute ls
ls "$INPUTDIR"/* 2&gt;&amp;1 &gt;&amp;6 6&gt;&amp;- \
# Closes fd 6 for awk, but not for ls.
| awk 'BEGIN { FS=":" } { print "YOU HAVE NO ACCESS TO" $2 }' 6&gt;&amp;-
# fd 6 closed for current shell
exec 6&gt;&amp;-
</screen>
</sect3>

View File

@ -53,6 +53,9 @@ for i in "$LIST"; do
done
</screen>
<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>
<tip><title>The basename command</title>
<para>Instead of using <command>sed</command> to replace the <filename>html</filename> suffix with <filename>php</filename>, it would be cleaner to use the <command>basename</command> command. Read the man page for more info.</para>
</tip>
</sect3>
</sect2>
@ -248,7 +251,7 @@ done
</sect2>
</sect1>
<sect1 id="sect_09_04"><title>I/0 redirection and loops</title>
<sect1 id="sect_09_04"><title>I/O redirection and loops</title>
<sect2 id="sect_09_04_01"><title>Input redirection</title>
<para>Instead of controlling a loop by testing the result of a command or by user input, you can specify a file from which to read input that controls the loop. In such cases, <command>read</command> is often the controlling command. As long as input lines are fed into the loop, execution of the loop commands continues. As soon as all the input lines are read the loop exits.</para>
<para>Since the loop construct is considered to be one command structure (such as <command>while TEST-COMMAND; do CONSEQUENT-COMMANDS; done</command>), the redirection should occur after the <command>done</command> statement, so that it complies with the form</para>
@ -269,9 +272,12 @@ done
ARCHIVENR=`date +%Y%m%d`
DESTDIR="$PWD/archive-$ARCHIVENR"
mkdir $DESTDIR
mkdir "$DESTDIR"
# using quotes to catch file names containing spaces, using read -d for more
# fool-proof usage:
find "$PWD" -type f -a -mtime +5 | while read -d $'\000' file
find $PWD -type f -a -mtime +5 | while read file
do
gzip "$file"; mv "$file".gz "$DESTDIR"
echo "$file archived"
@ -513,10 +519,10 @@ fi
while (( "$#" )); do
if [[ "$(ls $1)" == "" ]]; then
if [[ $(ls "$1") == "" ]]; then
echo "Empty directory, nothing to be done."
else
find $1 -type f -a -atime +365 -exec rm -i {} \;
find "$1" -type f -a -atime +365 -exec rm -i {} \;
fi
shift
@ -536,7 +542,7 @@ if [ $# -lt 1 ]; then
exit 1
fi
while (($#)); do
yum install $1 &lt;&lt; CONFIRM
yum install "$1" &lt;&lt; CONFIRM
y
CONFIRM
shift

View File

@ -439,12 +439,6 @@
<para>Print lines matching a pattern.</para>
</glossdef>
</glossentry>
<glossentry id="groff">
<glossterm>groff</glossterm>
<glossdef>
<para>Emulate nroff command with groff.</para>
</glossdef>
</glossentry>
<glossentry id="grub">
<glossterm>grub</glossterm>
<glossdef>
@ -1011,12 +1005,6 @@
</glossdef>
</glossentry>
<glossentry id="roff">
<glossterm>roff</glossterm>
<glossdef>
<para>A survey of the roff typesetting system.</para>
</glossdef>
</glossentry>
<glossentry id="rpm">
<glossterm>rpm</glossterm>
@ -1231,13 +1219,6 @@
</glossdef>
</glossentry>
<glossentry id="troff">
<glossterm>troff</glossterm>
<glossdef>
<para>Format documents.</para>
</glossdef>
</glossentry>
<glossentry id="twm">
<glossterm>twm</glossterm>
<glossdef>