This commit is contained in:
gferg 2003-05-12 14:45:05 +00:00
parent 738864a37c
commit 1023b2f15b
10 changed files with 772 additions and 200 deletions

View File

@ -3,6 +3,80 @@ RELEASE HISTORY
Change log Change log
Version 1.8 [Cleanups & revisions]
Working toward 'BREADFRUIT' release
1) Revised "self-document.sh" to remove unnecessary 'cat.'
2) In "cvt.sh" example, quoted target file name and added exercise.
3) Updated Jordi Sanfeliu's e-mail address in "Credits" chapter and in
"tree.sh" example script.
4) In "blot-out.sh" script, updated the Peter Gutmann URL.
5) In "Miscellaneous" subsection of "System and Administrative Commands"
chapter"
Added "watch" command.
6) In the introduction, in reason not to use shell scripts,
Removed misleading reference to Open Source (thank you, Peter Lietz, for
pointing this out).
7) In "Quoting" chapter:
Added footnote about problem double quoting "!" and "\!".
(Thanks, Wayne Pollock.)
8) In "Internal Commands" chapter:
Added caution about 'cd //' problem. (Thanks, Wayne Pollock.)
Added short example of "$!" usage. (Thanks, Jacques Lederer.)
9) In "Arrays" chapter:
Replaced "empty-array.sh" with an extended version.
Added note that Bash treats variables as arrays, even if not declared as
such.
Added example of nested arrays.
Added example of copying and concatenating arrays.
(All the above thanks to Michael Zick.)
10) In "Tests" chapter:
Fixed up "Tests Constructs" section link (finally!).
11) In "Command Substitution" chapter:
Added mention of $(<$file) construct.
12) In "Functions" chapter:
Added material to nested functions in-line examples.
13) In the "Portability Issues" section of the "Miscellany" chapter:
Added short list of Bash-specific features.
14) In "File and Archiving Commands" section of "External Commands" Chapter:
Added "dos2unix" utility.
15) In "Gotchas" chapter:
Added short in-line example of using an uninitialized variable.
Added in-line example showing DOS-formatted script failing to run.
16) In "Contributed Scripts" appendix:
Added Michael Zick's "directory-info.sh" script.
17) In "Bibliography" section:
Updated "The UNIX CD Bookshelf" reference.
Added Eric Pement's sed resources page.
Removed outdated "Sed F.A.Q." reference.
Updated Frisch entry.
Updated Shelldorado and Giles Orr entries.
18) Updated sample .bashrc file (Appendix G).
19) A few minor error corrections and clean ups at various places in the
text.
Version 1.7 (minor update) Version 1.7 (minor update)
'COCONUT' release 'COCONUT' release
01/05/03 01/05/03

View File

@ -17,6 +17,8 @@ read-r.sh
rnd.sh rnd.sh
rot13.sh rot13.sh
here-function.sh here-function.sh
directory-info.sh (lines 273 and 353)
bashrc (comments on lines 596 and 618)
have the "&lt;" and "&gt;" in place of angle brackets (< and >), or &amp; in have the "&lt;" and "&gt;" in place of angle brackets (< and >), or &amp; in
place of the ampersand (&). This is necessary for the Docbook SGML place of the ampersand (&). This is necessary for the Docbook SGML

View File

@ -268,6 +268,8 @@ Uncomment line below to generate index.
<!ENTITY brokenlink SYSTEM "broken-link.sh"> <!ENTITY brokenlink SYSTEM "broken-link.sh">
<!ENTITY continuenex SYSTEM "continue-n.example"> <!ENTITY continuenex SYSTEM "continue-n.example">
<!ENTITY pickcard SYSTEM "pick-card.sh"> <!ENTITY pickcard SYSTEM "pick-card.sh">
<!ENTITY copyarray SYSTEM "CopyArray.sh">
<!ENTITY directoryinfo SYSTEM "directory-info.sh">
<!ENTITY evalex SYSTEM "eval.example"> <!ENTITY evalex SYSTEM "eval.example">
<!ENTITY namesdata SYSTEM "names.data"> <!ENTITY namesdata SYSTEM "names.data">
<!ENTITY gen0data SYSTEM "gen0"> <!ENTITY gen0data SYSTEM "gen0">
@ -277,20 +279,20 @@ Uncomment line below to generate index.
<book> <book>
<bookinfo> <bookinfo>
<title>Advanced Bash-Scripting Guide</title> <title>Advanced Bash-Scripting Guide</title>
<subtitle>An in-depth exploration of the gentle art of shell scripting</subtitle> <subtitle>An in-depth exploration of the art of shell scripting</subtitle>
<author> <author>
<firstname>Mendel</firstname> <firstname>Mendel</firstname>
<surname>Cooper</surname> <surname>Cooper</surname>
<affiliation> <affiliation>
<orgname>Brindle-Phlogiston Associates</orgname> <orgname></orgname>
<address><email>thegrendel@theriver.com</email></address> <address><email>thegrendel@theriver.com</email></address>
</affiliation> </affiliation>
</author> </author>
<releaseinfo>1.7</releaseinfo> <releaseinfo>1.8</releaseinfo>
<pubdate>05 January 2003</pubdate> <pubdate>10 May 2003</pubdate>
<revhistory> <revhistory>
@ -395,6 +397,14 @@ Uncomment line below to generate index.
more script.</revremark> more script.</revremark>
</revision> </revision>
<revision>
<revnumber>1.8</revnumber>
<date>10 May 2003</date>
<authorinitials>mc</authorinitials>
<revremark>'BREADFRUIT' release: a number of bugfixes, more scripts
and material.</revremark>
</revision>
</revhistory> </revhistory>
@ -402,7 +412,7 @@ Uncomment line below to generate index.
<para>This tutorial assumes no previous knowledge of <para>This tutorial assumes no previous knowledge of
scripting or programming, but progresses rapidly toward an scripting or programming, but progresses rapidly toward an
intermediate/advanced level of instruction <emphasis>...all intermediate/advanced level of instruction <emphasis>. . . all
the while sneaking in little snippets of UNIX wisdom and the while sneaking in little snippets of UNIX wisdom and
lore</emphasis>. It serves as a textbook, a manual for lore</emphasis>. It serves as a textbook, a manual for
self-study, and a reference and source of knowledge on shell self-study, and a reference and source of knowledge on shell
@ -415,7 +425,7 @@ Uncomment line below to generate index.
linkend="bzipref">bzip2-ed</link> <quote>tarball</quote> linkend="bzipref">bzip2-ed</link> <quote>tarball</quote>
including both the SGML source and including both the SGML source and
rendered HTML, may be downloaded from <ulink rendered HTML, may be downloaded from <ulink
url="http://personal.riverusers.com/~thegrendel/abs-guide-1.7.tar.bz2"> url="http://personal.riverusers.com/~thegrendel/abs-guide-1.8.tar.bz2">
the author's home site</ulink>. See the <ulink the author's home site</ulink>. See the <ulink
url="http://personal.riverusers.com/~thegrendel/Change.log">change url="http://personal.riverusers.com/~thegrendel/Change.log">change
log</ulink> for a revision history.</para> log</ulink> for a revision history.</para>
@ -456,7 +466,7 @@ Uncomment line below to generate index.
<para>A working knowledge of shell scripting is essential to anyone <para>A working knowledge of shell scripting is essential to anyone
wishing to become reasonably adept at system administration, wishing to become reasonably proficient at system administration,
even if they do not anticipate ever having to actually write a even if they do not anticipate ever having to actually write a
script. Consider that as a Linux machine boots up, it executes the script. Consider that as a Linux machine boots up, it executes the
shell scripts in <filename class="directory">/etc/rc.d</filename> shell scripts in <filename class="directory">/etc/rc.d</filename>
@ -510,7 +520,7 @@ Uncomment line below to generate index.
<para>cross-platform portability required (use C instead)</para> <para>cross-platform portability required (use C instead)</para>
</listitem> <listitem> </listitem> <listitem>
<para>complex applications, where structured programming is <para>complex applications, where structured programming is
a necessity (need typechecking of variables, function a necessity (need type-checking of variables, function
prototypes, etc.)</para> prototypes, etc.)</para>
</listitem> <listitem> </listitem> <listitem>
<para>mission-critical applications upon which you are betting the <para>mission-critical applications upon which you are betting the
@ -539,8 +549,9 @@ Uncomment line below to generate index.
</listitem> <listitem> </listitem> <listitem>
<para>need to use libraries or interface with legacy code</para> <para>need to use libraries or interface with legacy code</para>
</listitem> <listitem> </listitem> <listitem>
<para>proprietary, closed-source applications (shell scripts are <para>proprietary, closed-source applications (shell scripts put the
necessarily Open Source)</para> source code right out in the open for all the world to see)</para>
</listitem> </listitem>
</itemizedlist></para> </itemizedlist></para>
@ -562,19 +573,19 @@ Uncomment line below to generate index.
and even a few from the updated <emphasis>ksh93</emphasis> and even a few from the updated <emphasis>ksh93</emphasis>
have been merged into Bash.</para></footnote> have been merged into Bash.</para></footnote>
and the C Shell and its variants. (Note that C Shell programming and the C Shell and its variants. (Note that C Shell programming
is not recommended due to certain inherent problems, as pointed out is not recommended due to certain inherent problems, as pointed out
in an October, 1993 <ulink in an October, 1993 <ulink
url="http://www.etext.org/Quartz/computer/unix/csh.harmful.gz">Usenet url="http://www.etext.org/Quartz/computer/unix/csh.harmful.gz">Usenet
post</ulink> by Tom Christiansen). post</ulink> by Tom Christiansen.)
</para> </para>
<para>What follows is a tutorial on shell scripting. It relies <para>What follows is a tutorial on shell scripting. It relies
heavily on examples to illustrate various features of the shell. heavily on examples to illustrate various features of the shell.
As far as possible, the example scripts have been tested, The example scripts work -- they've been tested -- and some
and some of them may even be useful in real life. The of them are even useful in real life. The reader can play with
reader should use the actual examples in the source archive the actual working code of the examples in the source archive
(<filename>something-or-other.sh</filename>), (<filename>scriptname.sh</filename>),
<footnote><para>By convention, user-written shell scripts that are <footnote><para>By convention, user-written shell scripts that are
Bourne shell compliant generally take a name with a Bourne shell compliant generally take a name with a
@ -585,13 +596,13 @@ Uncomment line below to generate index.
give them execute permission (<userinput>chmod u+rx give them execute permission (<userinput>chmod u+rx
scriptname</userinput>), then run them to see what happens. scriptname</userinput>), then run them to see what happens.
Should the source archive not be available, then cut-and-paste from Should the source archive not be available, then cut-and-paste from
the HTML, pdf, or text rendered versions. Be aware that some of the HTML, pdf, or text rendered versions. Be aware that some of
the scripts below introduce features before they are explained, the scripts below introduce features before they are explained,
and this may require the reader to temporarily skip ahead for and this may require the reader to temporarily skip ahead for
enlightenment.</para> enlightenment.</para>
<para>Unless otherwise noted, the book author wrote the example <para>Unless otherwise noted, the author of this book wrote the
scripts that follow.</para> example scripts that follow.</para>
</chapter> <!-- Why Shell Programming? --> </chapter> <!-- Why Shell Programming? -->
@ -906,9 +917,9 @@ fi</programlisting>
<note><para>Of course, an escaped <token>#</token> in an <note><para>Of course, an escaped <token>#</token> in an
<command>echo</command> statement does <command>echo</command> statement does
<emphasis>not</emphasis> begin a comment. Likewise, a <emphasis>not</emphasis> begin a comment. Likewise, a
<token>#</token> appears in <link linkend="psub2">certain <token>#</token> appears in <link linkend="psub2">certain parameter
parameter substitution constructs</link> and in <link substitution constructs</link> and in <link linkend="numconstants">
linkend="numconstants">numerical constant expressions</link>. numerical constant expressions</link>.
<programlisting>echo "The # here does not begin a comment." <programlisting>echo "The # here does not begin a comment."
echo 'The # here does not begin a comment.' echo 'The # here does not begin a comment.'
@ -2884,6 +2895,7 @@ arch=$(uname -m)</programlisting></para>
<sect1 id="untyped"> <sect1 id="untyped">
<title>Bash Variables Are Untyped</title> <title>Bash Variables Are Untyped</title>
<para><anchor id="bvuntyped"></para>
<para>Unlike many other programming languages, Bash does not segregate <para>Unlike many other programming languages, Bash does not segregate
its variables by <quote>type</quote>. Essentially, Bash its variables by <quote>type</quote>. Essentially, Bash
variables are character strings, but, depending on context, Bash variables are character strings, but, depending on context, Bash
@ -2946,10 +2958,11 @@ arch=$(uname -m)</programlisting></para>
any other process.</para> any other process.</para>
<para>Every time a shell starts, it creates shell variables that <para>Every time a shell starts, it creates shell variables that
correspond to its own environmental variables. Updating or correspond to its own environmental variables. Updating
adding new shell variables causes the shell to update its or adding new environmental variables causes the shell
environment, and all the shell's child processes (the commands to update its environment, and all the shell's child
it executes) inherit this environment.</para> processes (the commands it executes) inherit this
environment.</para>
</note> </note>
@ -3185,8 +3198,45 @@ fi
enclose it in double quotes (<token>" "</token>). This enclose it in double quotes (<token>" "</token>). This
preserves all special characters within the variable name, preserves all special characters within the variable name,
except <token>$</token>, <token>`</token> (backquote), except <token>$</token>, <token>`</token> (backquote),
and <token>\</token> (escape). Keeping <token>$</token> and <token>\</token> (escape).
as a special character permits referencing a quoted variable
<footnote>
<para>Encapsulating <quote>!</quote> within double
quotes gives an error when used <emphasis>from the command
line</emphasis>. Apparently this is interpreted as a <link
linkend="histcommands">history command</link>. Within a script,
though, this problem does not occur.</para>
<para>Of more concern is the inconsistent behavior of
<quote>\</quote> within double quotes.
<screen>
<prompt>bash$ </prompt><userinput>echo hello\!</userinput>
<computeroutput>hello!</computeroutput>
<prompt>bash$ </prompt><userinput>echo "hello\!"</userinput>
<computeroutput>hello\!</computeroutput>
<prompt>bash$ </prompt><userinput>echo -e x\ty</userinput>
<computeroutput>xty</computeroutput>
<prompt>bash$ </prompt><userinput>echo -e "x\ty"</userinput>
<computeroutput>x y</computeroutput>
</screen>
(Thank you, Wayne Pollock, for pointing this out.)
</para>
</footnote>
Keeping <token>$</token> as a special character within
double quotes permits referencing a quoted variable
(<replaceable>"$variable"</replaceable>), that is, replacing the (<replaceable>"$variable"</replaceable>), that is, replacing the
variable with its value (see <xref linkend="ex9">, above).</para> variable with its value (see <xref linkend="ex9">, above).</para>
@ -3750,7 +3800,9 @@ echo "exit status of \"! true\" = $?" # 1
<command>if/then</command> construct.</para> <command>if/then</command> construct.</para>
<sect1 id="testconstructs"> <sect1 id="testconstructs">
<title><anchor id="testconstructs1">Test Constructs</title> <title>Test Constructs</title>
<para><anchor id="testconstructs1"></para>
<itemizedlist id="testingref"> <itemizedlist id="testingref">
@ -3993,8 +4045,8 @@ fi</programlisting>
</indexterm> </indexterm>
<para><anchor id="dblbrackets">The <token>[[ ]]</token> construct <para><anchor id="dblbrackets">The <token>[[ ]]</token> construct
is the shell equivalent of <token>[ ]</token>. This is the is the more versatile Bash version of <token>[ ]</token>. This
<emphasis>extended test command</emphasis>, adopted from is the <emphasis>extended test command</emphasis>, adopted from
<emphasis>ksh88</emphasis>.</para> <emphasis>ksh88</emphasis>.</para>
<note><para>No filename expansion or word splitting takes place <note><para>No filename expansion or word splitting takes place
@ -6468,7 +6520,28 @@ echo "$@" # 3 4 5
<secondary>last job background</secondary> <secondary>last job background</secondary>
</indexterm> </indexterm>
<listitem> <listitem>
<para>PID (process id) of last job run in background</para> <para>PID (process id) of last job run in background</para>
<para>
<programlisting>LOG=$0.log
COMMAND1="sleep 100"
echo "Logging PIDs background commands for script: $0" >> "$LOG"
# So they can be monitored, and killed as necessary.
echo >> "$LOG"
# Logging commands.
echo -n "PID of \"$COMMAND1\": " >> "$LOG"
${COMMAND1} &
echo $! >> "$LOG"
# PID of "sleep 100": 1506
# Thank you, Jacques Lederer, for suggesting this.</programlisting>
</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -8791,6 +8864,19 @@ done</programlisting></para>
linkend="oldpwd">$OLDPWD</link>, the previous working linkend="oldpwd">$OLDPWD</link>, the previous working
directory.</para> directory.</para>
<para><anchor id="doubleslashref"></para>
<caution><para>The <command>cd</command> command does not function
as expected when presented with two forward slashes.
<screen>
<prompt>bash$ </prompt><userinput>cd //</userinput>
<prompt>bash$ </prompt><userinput>pwd</userinput>
<computeroutput>//</computeroutput>
</screen>
The output should, of course, be <computeroutput>/</computeroutput>.
This is a problem both from the command line and in a script.</para></caution>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -10914,11 +11000,17 @@ find /etc -type f -exec cat '{}' \; | tr -c '.[:digit:]' '\n' \
<programlisting>sleep 3 <programlisting>sleep 3
# Pauses 3 seconds.</programlisting> # Pauses 3 seconds.</programlisting>
</para> </para>
<note><para>The <command>sleep</command> command defaults to <note><para>The <command>sleep</command> command defaults to
seconds, but minute, hours, or days may also be specified. seconds, but minute, hours, or days may also be specified.
<programlisting>sleep 3 h <programlisting>sleep 3 h
# Pauses 3 hours!</programlisting> # Pauses 3 hours!</programlisting>
</para></note> </para></note>
<note><para>The <link linkend="watchref">watch</link> command may
be a better choice than <command>sleep</command> for running
commands at timed intervals.</para></note>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -13142,6 +13234,9 @@ gzip -cd patchXX.gz | patch -p0
<programlisting>&fileintegrity;</programlisting> <programlisting>&fileintegrity;</programlisting>
</example> </example>
<para>See also <xref linkend="directoryinfo"> for a creative use of
the <command>md5sum</command> command.</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -13348,6 +13443,23 @@ echo "tempfile name = $tempfile"
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><command>dos2unix</command></term>
<indexterm>
<primary>dos2unix</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>file converter</secondary>
</indexterm>
<listitem>
<para>This utility, written by Benjamin Lin and collaborators,
converts DOS-formatted text files (lines terminated by
CR-LF) to UNIX format (lines terminated by LF only),
and vice-versa.</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><command>ptx</command></term> <term><command>ptx</command></term>
<indexterm> <indexterm>
@ -17609,6 +17721,24 @@ print "even when I don't know where to find Perl.\n";
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><anchor id="watchref"><command>watch</command></term>
<indexterm>
<primary>watch</primary>
</indexterm>
<indexterm>
<primary>command</primary>
<secondary>periodic</secondary>
</indexterm>
<listitem>
<para>Run a command repeatedly, at specified time intervals.</para>
<para>The default is two-second intervals, but this may be changed
with the <option>-n</option> option.</para>
<para><programlisting>watch -n 5 tail /var/log/messages
# Shows tail end of system log, /var/log/messages, every five seconds.</programlisting></para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><command>strip</command></term> <term><command>strip</command></term>
<indexterm> <indexterm>
@ -17849,7 +17979,11 @@ echo "$dir_listing" # quoted
<programlisting>variable1=`&lt;file1` # Set "variable1" to contents of "file1". <programlisting>variable1=`&lt;file1` # Set "variable1" to contents of "file1".
variable2=`cat file2` # Set "variable2" to contents of "file2". variable2=`cat file2` # Set "variable2" to contents of "file2".
# Be aware that the variables may contain embedded whitespace, # Note 1:
# Removes newlines.
#
# Note 2:
# The variables may contain embedded whitespace,
#+ or even (horrors), control characters.</programlisting> #+ or even (horrors), control characters.</programlisting>
</para> </para>
@ -17951,8 +18085,11 @@ echo $greeting</programlisting>
<note><para>The <command>$(COMMAND)</command> form has <note><para>The <command>$(COMMAND)</command> form has
superseded backticks for command substitution. superseded backticks for command substitution.
<programlisting>output=$(sed -n /"$1"/p $file) <programlisting>output=$(sed -n /"$1"/p $file) # From "grp.sh" example.
# From "grp.sh" example.</programlisting></para></note>
# Setting a variable to the contents of a text file.
File_contents1=$(cat $file1)
File_contents2=$(&lt;$file2) # Bash permits this also.</programlisting></para></note>
@ -18003,7 +18140,7 @@ echo $greeting</programlisting>
</indexterm> <indexterm> </indexterm> <indexterm>
<primary>arithmetic</primary> <secondary>expansion</secondary> <primary>arithmetic</primary> <secondary>expansion</secondary>
</indexterm> <listitem> </indexterm> <listitem>
<para><programlisting>z=`expr $z + 3` # 'expr' does the expansion.</programlisting></para> <para><programlisting>z=`expr $z + 3` # The 'expr' command performs the expansion.</programlisting></para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -18026,12 +18163,13 @@ echo $greeting</programlisting>
convenient <command>let</command> construction. convenient <command>let</command> construction.
<programlisting>z=$(($z+3)) <programlisting>z=$(($z+3))
# $((EXPRESSION)) is arithmetic expansion. # Not to be confused with # $((EXPRESSION)) is arithmetic expansion. # Not to be confused with
# command substitution. #+ command substitution.
let z=z+3 let z=z+3
let "z += 3" #If quotes, then spaces and special operators allowed. let "z += 3" # Quotes permit the use of spaces and special operators.
# 'let' is actually arithmetic evaluation, rather than expansion.</programlisting> # The 'let' operator actually performs arithmetic evaluation,
#+ rather than expansion.</programlisting>
All the above are equivalent. You may use whichever one All the above are equivalent. You may use whichever one
<quote>rings your chimes</quote>. <quote>rings your chimes</quote>.
@ -19767,9 +19905,12 @@ route -n |
<para>The function definition must precede the first call to <para>The function definition must precede the first call to
it. There is no method of <quote>declaring</quote> the function, it. There is no method of <quote>declaring</quote> the function,
as, for example, in C. as, for example, in C.
<programlisting># f1 <programlisting>f1
# Will give an error message, since function "f1" not yet defined. # Will give an error message, since function "f1" not yet defined.
declare -f f1 # This doesn't help either.
f1 # Still an error message.
# However... # However...
@ -19784,11 +19925,11 @@ f2 ()
echo "Function \"f2\"." echo "Function \"f2\"."
} }
f1 # Function "f2" is not actually called until this point, f1 # Function "f2" is not actually called until this point,
# although it is referenced before its definition. #+ although it is referenced before its definition.
# This is permissable. # This is permissable.
# Thanks, S.C.</programlisting> # Thanks, S.C.</programlisting>
</para> </para>
<para>It is even possible to nest a function within another function, <para>It is even possible to nest a function within another function,
@ -19803,14 +19944,16 @@ f1 # Function "f2" is not actually called until this point,
} }
# f2 f2 # Gives an error message.
# Gives an error message. # Even a preceding "declare -f f2" wouldn't help.
f1 # Does nothing, since calling "f1" does not automatically call "f2". echo
f2 # Now, it's all right to call "f2",
# since its definition has been made visible by calling "f1".
# Thanks, S.C.</programlisting> f1 # Does nothing, since calling "f1" does not automatically call "f2".
f2 # Now, it's all right to call "f2",
#+ since its definition has been made visible by calling "f1".
# Thanks, S.C.</programlisting>
</para> </para>
<para>Function declarations can appear in unlikely places, even where a <para>Function declarations can appear in unlikely places, even where a
@ -20419,6 +20562,25 @@ false && ( true || echo false ) # (nothing echoed)
<programlisting>&ex66;</programlisting> <programlisting>&ex66;</programlisting>
</example> </example>
<note><para>Bash permits array operations on variables, even if
the variables are not explicitly declared as arrays.
<programlisting>string=abcABC123ABCabc
echo ${string[@]} # abcABC123ABCabc
echo ${string[*]} # abcABC123ABCabc
echo ${string[0]} # abcABC123ABCabc
echo ${string[1]} # No output!
# Why?
echo ${#string[@]} # 1
# One element in the array.
# The string itself.
# Thank you, Michael Zick, for pointing this out.</programlisting>
Once again this demonstrates that <link linkend="bvuntyped">Bash
variables are untyped</link>.
</para></note>
<example id="poem"> <example id="poem">
<title>Formatting a poem</title> <title>Formatting a poem</title>
<programlisting>&poem;</programlisting> <programlisting>&poem;</programlisting>
@ -20522,7 +20684,15 @@ element_count=${#array1[*]}
echo $element_count # 8</programlisting> echo $element_count # 8</programlisting>
</para> </para>
</tip> </tip>
<para>Clever scripting makes it possible to add array operations.</para>
<example id="copyarray">
<title>Copying and concatenating arrays</title>
<programlisting>&copyarray;</programlisting>
</example>
<para>--</para>
<para>Arrays permit deploying old familiar algorithms as shell scripts. <para>Arrays permit deploying old familiar algorithms as shell scripts.
Whether this is necessarily a good idea is left to the reader to Whether this is necessarily a good idea is left to the reader to
@ -20536,6 +20706,28 @@ echo $element_count # 8</programlisting>
<para>--</para> <para>--</para>
<para>Is it possible to nest arrays within arrays?</para>
<para><programlisting>#!/bin/bash
# Nested array.
# Michael Zick provided this example.
AnArray=( $(ls --inode --ignore-backups --almost-all \
--directory --full-time --color=none --time=status \
--sort=time -l ${PWD} ) ) # Commands and options.
# Spaces are significant . . . and don't quote anything in the above.
SubArray=( ${AnArray[@]:11:1} ${AnArray[@]:6:5} )
# Array has two elements, each of which is in turn an array.
echo "Current directory and date of last status change:"
echo "${SubArray[@]}"
exit 0</programlisting></para>
<para>--</para>
<para>Arrays enable implementing a shell script version of the <emphasis>Sieve of <para>Arrays enable implementing a shell script version of the <emphasis>Sieve of
Eratosthenes</emphasis>. Of course, a resource-intensive application of this Eratosthenes</emphasis>. Of course, a resource-intensive application of this
nature should really be written in a compiled language, such as C. It nature should really be written in a compiled language, such as C. It
@ -21296,6 +21488,7 @@ trap 'echo "Control-C disabled."' 2
</programlisting></para> </programlisting></para>
<para><anchor id="invocationoptionsref"></para>
<para>It is also possible to enable script options from the command <para>It is also possible to enable script options from the command
line. Some options that will not work with line. Some options that will not work with
<command>set</command> are available this way. Among these <command>set</command> are available this way. Among these
@ -21471,9 +21664,9 @@ do_something do_something
<para><anchor id="wsbad">Using <link <para><anchor id="wsbad">Using <link
linkend="whitespaceref">whitespace</link> inappropriately linkend="whitespaceref">whitespace</link> inappropriately.
(in contrast to other programming languages, Bash can be quite In contrast to other programming languages, Bash can be quite
finicky about whitespace). finicky about whitespace.
<programlisting>var1 = 23 # 'var1=23' is correct. <programlisting>var1 = 23 # 'var1=23' is correct.
# On line above, Bash attempts to execute command "var1" # On line above, Bash attempts to execute command "var1"
@ -21486,10 +21679,18 @@ if [ $a -le 5] # if [ $a -le 5 ] is correct.
# [[ $a -le 5 ]] also works.</programlisting> # [[ $a -le 5 ]] also works.</programlisting>
</para> </para>
<para>Assuming uninitialized variables (variables before a value is <para>
Assuming uninitialized variables (variables before a value is
assigned to them) are <quote>zeroed out</quote>. An assigned to them) are <quote>zeroed out</quote>. An
uninitialized variable has a value of <quote>null</quote>, uninitialized variable has a value of <quote>null</quote>,
<emphasis>not</emphasis> zero.</para> <emphasis>not</emphasis> zero.
<programlisting>#!/bin/bash
echo "uninitialized_var = $uninitialized_var"
# uninitialized_var =</programlisting>
</para>
<para>Mixing up <emphasis>=</emphasis> and <emphasis>-eq</emphasis> in <para>Mixing up <emphasis>=</emphasis> and <emphasis>-eq</emphasis> in
a test. Remember, <emphasis>=</emphasis> is for comparing literal a test. Remember, <emphasis>=</emphasis> is for comparing literal
@ -21593,11 +21794,27 @@ fi
<command>sh</command> to <command>bash</command>, but this does <command>sh</command> to <command>bash</command>, but this does
not necessarily hold true for a generic UNIX machine.</para> not necessarily hold true for a generic UNIX machine.</para>
<para>A script with DOS-type newlines (<replaceable>\r\n</replaceable>) <para>
A script with DOS-type newlines (<replaceable>\r\n</replaceable>)
will fail to execute, since <userinput>#!/bin/bash\r\n</userinput> will fail to execute, since <userinput>#!/bin/bash\r\n</userinput>
is not recognized, <emphasis>not</emphasis> the same as the is not recognized, <emphasis>not</emphasis> the same as the
expected <userinput>#!/bin/bash\n</userinput>. The fix is to expected <userinput>#!/bin/bash\n</userinput>. The fix is to
convert the script to UNIX-style newlines.</para> convert the script to UNIX-style newlines.
<programlisting>#!/bin/bash
echo "Here"
unix2dos $0 # Script changes itself to DOS format.
chmod 755 $0 # Change back to execute permission.
# The 'unix2dos' command removes execute permission.
./$0 # Script tries to run itself again.
# But it won't work as a DOS file.
echo "There"
exit 0</programlisting>
</para>
<para>A shell script headed by <userinput>#!/bin/sh</userinput> <para>A shell script headed by <userinput>#!/bin/sh</userinput>
may not run in full Bash-compatibility mode. Some Bash-specific may not run in full Bash-compatibility mode. Some Bash-specific
@ -21654,6 +21871,9 @@ exit 0</programlisting>
undesirable behavior as far as CGI is concerned. Moreover, it is undesirable behavior as far as CGI is concerned. Moreover, it is
difficult to <quote>cracker-proof</quote> shell scripts.</para> difficult to <quote>cracker-proof</quote> shell scripts.</para>
<para>Bash does not handle the <link linkend="doubleslashref">double slash
(<token>//</token>) string</link> correctly.</para>
<para>Bash scripts written for Linux or BSD systems may need <para>Bash scripts written for Linux or BSD systems may need
fixups to run on a commercial UNIX machine. Such scripts fixups to run on a commercial UNIX machine. Such scripts
often employ GNU commands and filters which have greater often employ GNU commands and filters which have greater
@ -22796,12 +23016,46 @@ fi</programlisting>
features to the latest versions of Bash.</para> features to the latest versions of Bash.</para>
<para>On a commercial UNIX machine, scripts using GNU-specific <para>On a commercial UNIX machine, scripts using GNU-specific
features of standard commands may not work. This has become features of standard commands may not work. This has become less
less of a problem in the last few years, as the GNU utilities of a problem in the last few years, as the GNU utilities have
have pretty much displaced their proprietary counterparts even pretty much displaced their proprietary counterparts even on
on <quote>big-iron</quote> UNIX. Caldera's recent release of <quote>big-iron</quote> UNIX. Caldera's release of the source
the source to many of the original UNIX utilities will only to many of the original UNIX utilities will only accelerate
accelerate the trend.</para> the trend.</para>
<para>Bash has certain features that the traditional Bourne shell
lacks. Among these are:
<itemizedlist>
<listitem>
<para>Certain extended <link
linkend="invocationoptionsref">invocation options</link></para>
</listitem>
<listitem>
<para><link linkend="commandsubref">Command substitution</link> using
<command>$( )</command> notation</para>
</listitem>
<listitem>
<para>Certain <link linkend="stringmanip">string manipulation</link>
operations</para>
</listitem>
<listitem>
<para><link linkend="processsubref">Process substitution</link></para>
</listitem>
<listitem>
<para>Bash-specific <link linkend="builtinref">builtins</link></para>
</listitem>
</itemizedlist>
</para>
<para>See the <ulink url="ftp://ftp.cwru.edu/pub/bash/FAQ">Bash
F.A.Q.</ulink> for a complete listing.</para>
</sect1> <!-- Portability Issues --> </sect1> <!-- Portability Issues -->
@ -23035,7 +23289,7 @@ fi</programlisting>
an instructive example script.</para> an instructive example script.</para>
<para>Many thanks to <ulink <para>Many thanks to <ulink
url="mailto:mikaku@arrakis.es">Jordi Sanfeliu</ulink> url="mailto:mikaku@fiwix.org">Jordi Sanfeliu</ulink>
for giving permission to use his fine tree script (<xref for giving permission to use his fine tree script (<xref
linkend="tree">).</para> linkend="tree">).</para>
@ -23075,6 +23329,10 @@ fi</programlisting>
linkend="cutref">cut</link> and <link linkend="cutref">cut</link> and <link
linkend="pidofref">pidof</link>.</para> linkend="pidofref">pidof</link>.</para>
<para>Michael Zick extended the <link linkend="emptyarray">empty
array</link> example to demonstrate some surprising array
properties. He also provided other examples of this.</para>
<para>Marc-Jano Knopp sent corrections on DOS batch files.</para> <para>Marc-Jano Knopp sent corrections on DOS batch files.</para>
<para>Hyun Jin Cha found several typos in the document in the <para>Hyun Jin Cha found several typos in the document in the
@ -23162,18 +23420,18 @@ fi</programlisting>
<author><firstname>Aeleen</firstname><surname>Frisch</surname></author> <author><firstname>Aeleen</firstname><surname>Frisch</surname></author>
</authorgroup> </authorgroup>
<title>Essential System Administration</title> <title>Essential System Administration</title>
<edition>2nd edition</edition> <edition>3rd edition</edition>
<publisher> <publisher>
<publishername>O'Reilly and Associates</publishername> <publishername>O'Reilly and Associates</publishername>
</publisher> </publisher>
<copyright> <copyright>
<year>1995</year> <year>2002</year>
</copyright> </copyright>
<isbn>1-56592-127-5</isbn> <isbn>0-596-00343-9</isbn>
<abstract><para>This excellent sys admin manual has a decent introduction to shell <abstract><para>This excellent sys admin manual has a decent introduction to shell
scripting for sys administrators and does a nice job of explaining the scripting for sys administrators and does a nice job of explaining the
startup and initialization scripts. The book is long overdue for a third startup and initialization scripts. The long overdue third edition of this
edition (are you listening, Tim O'Reilly?).</para> classic has finally been released.</para>
<para>*</para> <para>*</para>
</abstract> </abstract>
</biblioentry> </biblioentry>
@ -23459,21 +23717,20 @@ fi</programlisting>
<biblioentry> <biblioentry>
<title>The UNIX CD Bookshelf</title> <title>The UNIX CD Bookshelf</title>
<edition>2nd edition</edition> <edition>3rd edition</edition>
<publisher> <publisher>
<publishername>O'Reilly and Associates</publishername> <publishername>O'Reilly and Associates</publishername>
</publisher> </publisher>
<copyright> <copyright>
<year>2000</year> <year>2003</year>
</copyright> </copyright>
<isbn>1-56592-815-6</isbn> <isbn>0-596-00392-7</isbn>
<abstract><para>An array of six UNIX books on CD ROM, including <abstract><para>An array of seven UNIX books on CD ROM, including
<emphasis>UNIX Power Tools</emphasis>, <emphasis>Sed <emphasis>UNIX Power Tools</emphasis>, <emphasis>Sed
and Awk</emphasis>, and <emphasis>Learning the Korn and Awk</emphasis>, and <emphasis>Learning the Korn
Shell</emphasis>. A complete set of all the UNIX references Shell</emphasis>. A complete set of all the UNIX references
and tutorials you would ever need at about $70. Buy this one, and tutorials you would ever need at about $130. Buy this one,
even if it means going into debt and not paying the rent.</para> even if it means going into debt and not paying the rent.</para>
<para>Unfortunately, out of print at present.</para>
<para>*</para> <para>*</para>
</abstract> </abstract>
</biblioentry> </biblioentry>
@ -23545,8 +23802,7 @@ fi</programlisting>
<biblioentry> <biblioentry>
<abstract> <abstract>
<para>Example shell scripts at <ulink <para>Example shell scripts at <ulink
url="http://www.oase-shareware.org/shell/scripts">SHELLdorado url="http://www.shelldorado.com">SHELLdorado </ulink>.</para>
</ulink>.</para>
</abstract> </abstract>
</biblioentry> </biblioentry>
@ -23577,19 +23833,11 @@ fi</programlisting>
<biblioentry> <biblioentry>
<abstract> <abstract>
<para>Giles Orr's <ulink <para>Giles Orr's <ulink
url="http://www.tldp.org/HOWTO/Bash-Prompt-HOWTO.html">Bash-Prompt url="http://www.tldp.org/HOWTO/Bash-Prompt-HOWTO/">Bash-Prompt
HOWTO</ulink>.</para> HOWTO</ulink>.</para>
</abstract> </abstract>
</biblioentry> </biblioentry>
<biblioentry>
<abstract>
<para>The <ulink
url="http://www.dbnet.ece.ntua.gr/~george/howto/sed/">sed F.A.Q. /
Do It With Sed</ulink>.</para>
</abstract>
</biblioentry>
<biblioentry> <biblioentry>
<abstract> <abstract>
<para>Very nice <command>sed</command>, <para>Very nice <command>sed</command>,
@ -23599,6 +23847,14 @@ fi</programlisting>
</abstract> </abstract>
</biblioentry> </biblioentry>
<biblioentry>
<abstract>
<para>Eric Pement's
<ulink url="http://www.student.northpark.edu/pemente/sed/">sed resources page</ulink>.</para>
</abstract>
</biblioentry>
<biblioentry> <biblioentry>
<abstract> <abstract>
<para>The GNU <command>gawk</command> <ulink <para>The GNU <command>gawk</command> <ulink
@ -23839,6 +24095,16 @@ fi</programlisting>
<programlisting>&string;</programlisting> <programlisting>&string;</programlisting>
</example> </example>
<para>Michael Zick's complex array example uses the <link
linkend="md5sumref">md5sum</link> check sum command to encode directory
information.</para>
<example id="directoryinfo">
<title>Directory information</title>
<programlisting>&directoryinfo;</programlisting>
</example>
<para>Stephane Chazelas demonstrates object-oriented programming in a <para>Stephane Chazelas demonstrates object-oriented programming in a
Bash script.</para> Bash script.</para>

View File

@ -1,19 +1,26 @@
#=============================================================== #===============================================================
# #
# PERSONAL $HOME/.bashrc FILE for bash-2.05 (or later) # PERSONAL $HOME/.bashrc FILE for bash-2.05a (or later)
#
# Last modified: Tue Apr 15 20:32:34 CEST 2003
# #
# This file is read (normally) by interactive shells only. # This file is read (normally) by interactive shells only.
# Here is the place to define your aliases, functions and # Here is the place to define your aliases, functions and
# other interactive features like your prompt. # other interactive features like your prompt.
# #
# This file was designed (originally) for Solaris. # This file was designed (originally) for Solaris but based
# on Redhat's default .bashrc file
# --> Modified for Linux. # --> Modified for Linux.
# The majority of the code you'll find here is based on code found
# on Usenet (or internet).
# This bashrc file is a bit overcrowded - remember it is just # This bashrc file is a bit overcrowded - remember it is just
# just an example. Tailor it to your needs # just an example. Tailor it to your needs
#
# #
#=============================================================== #===============================================================
# --> Comments added by HOWTO author. # --> Comments added by HOWTO author.
# --> And then edited again by ER :-)
#----------------------------------- #-----------------------------------
# Source global definitions (if any) # Source global definitions (if any)
@ -25,38 +32,69 @@ fi
#------------------------------------------------------------- #-------------------------------------------------------------
# Automatic setting of $DISPLAY (if not set already) # Automatic setting of $DISPLAY (if not set already)
# This works for linux and solaris - your mileage may vary.... # This works for linux - your mileage may vary....
# The problem is that different types of terminals give
# different answers to 'who am i'......
# I have not found a 'universal' method yet
#------------------------------------------------------------- #-------------------------------------------------------------
function get_xserver ()
{
case $TERM in
xterm )
XSERVER=$(who am i | awk '{print $NF}' | tr -d ')''(' )
XSERVER=${XSERVER%%:*}
;;
aterm | rxvt)
# find some code that works here.....
;;
esac
}
if [ -z ${DISPLAY:=""} ]; then if [ -z ${DISPLAY:=""} ]; then
DISPLAY=$(who am i) get_xserver
DISPLAY=${DISPLAY%%\!*} if [[ -z ${XSERVER} || ${XSERVER} == $(hostname) || ${XSERVER} == "unix" ]]; then
if [ -n "$DISPLAY" ]; then DISPLAY=":0.0" # Display on local host
export DISPLAY=$DISPLAY:0.0 else
else DISPLAY=${XSERVER}:0.0 # Display on remote host
export DISPLAY=":0.0" # fallback
fi fi
fi fi
export DISPLAY
#--------------- #---------------
# Some settings # Some settings
#--------------- #---------------
ulimit -S -c 0 # Don't want any coredumps
set -o notify set -o notify
set -o noclobber set -o noclobber
set -o ignoreeof set -o ignoreeof
set -o nounset set -o nounset
#set -o xtrace # useful for debuging #set -o xtrace # useful for debuging
# Enable options:
shopt -s cdspell shopt -s cdspell
shopt -s cdable_vars shopt -s cdable_vars
shopt -s checkhash shopt -s checkhash
shopt -s checkwinsize shopt -s checkwinsize
shopt -s mailwarn shopt -s mailwarn
shopt -s sourcepath shopt -s sourcepath
shopt -s no_empty_cmd_completion shopt -s no_empty_cmd_completion # bash>=2.04 only
shopt -s histappend histreedit shopt -s cmdhist
shopt -s extglob # useful for programmable completion shopt -s histappend histreedit histverify
shopt -s extglob # necessary for programmable completion
# Disable options:
shopt -u mailwarn
unset MAILCHECK # I don't want my shell to warn me of incoming mail
export TIMEFORMAT=$'\nreal %3R\tuser %3U\tsys %3S\tpcpu %P\n'
export HISTIGNORE="&:bg:fg:ll:h"
export HOSTFILE=$HOME/.hosts # Put a list of remote hosts in ~/.hosts
#----------------------- #-----------------------
# Greeting, motd etc... # Greeting, motd etc...
@ -75,26 +113,37 @@ NC='\e[0m' # No Color
# Looks best on a black background..... # Looks best on a black background.....
echo -e "${CYAN}This is BASH ${RED}${BASH_VERSION%.*}${CYAN} - DISPLAY on ${RED}$DISPLAY${NC}\n" echo -e "${CYAN}This is BASH ${RED}${BASH_VERSION%.*}${CYAN} - DISPLAY on ${RED}$DISPLAY${NC}\n"
date date
if [ -x /usr/games/fortune ]; then if [ -x /usr/games/fortune ]; then
/usr/games/fortune -s # makes our day a bit more fun.... :-) /usr/games/fortune -s # makes our day a bit more fun.... :-)
fi fi
function _exit() # function to run upon exit of shell function _exit() # function to run upon exit of shell
{ {
echo -e "${RED}Hasta la vista, baby${NC}" echo -e "${RED}Hasta la vista, baby${NC}"
} }
trap _exit 0 trap _exit EXIT
#--------------- #---------------
# Shell prompt # Shell Prompt
#--------------- #---------------
if [[ "${DISPLAY#$HOST}" != ":0.0" && "${DISPLAY}" != ":0" ]]; then
HILIT=${red} # remote machine: prompt will be partly red
else
HILIT=${cyan} # local machine: prompt will be partly cyan
fi
# --> Replace instances of \W with \w in prompt functions below
#+ --> to get display of full path name.
function fastprompt() function fastprompt()
{ {
unset PROMPT_COMMAND unset PROMPT_COMMAND
case $TERM in case $TERM in
*term | rxvt ) *term | rxvt )
PS1="[\h] \W > \[\033]0;[\u@\h] \w\007\]" ;; PS1="${HILIT}[\h]$NC \W > \[\033]0;\${TERM} [\u@\h] \w\007\]" ;;
linux )
PS1="${HILIT}[\h]$NC \W > " ;;
*) *)
PS1="[\h] \W > " ;; PS1="[\h] \W > " ;;
esac esac
@ -105,17 +154,16 @@ function powerprompt()
_powerprompt() _powerprompt()
{ {
LOAD=$(uptime|sed -e "s/.*: \([^,]*\).*/\1/" -e "s/ //g") LOAD=$(uptime|sed -e "s/.*: \([^,]*\).*/\1/" -e "s/ //g")
TIME=$(date +%H:%M)
} }
PROMPT_COMMAND=_powerprompt PROMPT_COMMAND=_powerprompt
case $TERM in case $TERM in
*term | rxvt ) *term | rxvt )
PS1="${cyan}[\$TIME \$LOAD]$NC\n[\h \#] \W > \[\033]0;[\u@\h] \w\007\]" ;; PS1="${HILIT}[\A \$LOAD]$NC\n[\h \#] \W > \[\033]0;\${TERM} [\u@\h] \w\007\]" ;;
linux ) linux )
PS1="${cyan}[\$TIME - \$LOAD]$NC\n[\h \#] \w > " ;; PS1="${HILIT}[\A - \$LOAD]$NC\n[\h \#] \w > " ;;
* ) * )
PS1="[\$TIME - \$LOAD]\n[\h \#] \w > " ;; PS1="[\A - \$LOAD]\n[\h \#] \w > " ;;
esac esac
} }
@ -144,6 +192,7 @@ alias rm='rm -i'
alias cp='cp -i' alias cp='cp -i'
alias mv='mv -i' alias mv='mv -i'
# -> Prevents accidentally clobbering files. # -> Prevents accidentally clobbering files.
alias mkdir='mkdir -p'
alias h='history' alias h='history'
alias j='jobs -l' alias j='jobs -l'
@ -151,23 +200,23 @@ alias r='rlogin'
alias which='type -all' alias which='type -all'
alias ..='cd ..' alias ..='cd ..'
alias path='echo -e ${PATH//:/\\n}' alias path='echo -e ${PATH//:/\\n}'
alias print='/usr/bin/lp -o nobanner -d $LPDEST' # Assumes LPDEST is defined alias print='/usr/bin/lp -o nobanner -d $LPDEST' # Assumes LPDEST is defined
alias pjet='enscript -h -G -fCourier9 -d $LPDEST' # Pretty-print using enscript alias pjet='enscript -h -G -fCourier9 -d $LPDEST' # Pretty-print using enscript
alias background='xv -root -quit -max -rmode 5' # put a picture in the background alias background='xv -root -quit -max -rmode 5' # Put a picture in the background
alias vi='vim' alias du='du -kh'
alias du='du -h' alias df='df -kTh'
alias df='df -kh'
# The 'ls' family (this assumes you use the GNU ls) # The 'ls' family (this assumes you use the GNU ls)
alias la='ls -Al' # show hidden files
alias ls='ls -hF --color' # add colors for filetype recognition alias ls='ls -hF --color' # add colors for filetype recognition
alias lx='ls -lXB' # sort by extension alias lx='ls -lXB' # sort by extension
alias lk='ls -lSr' # sort by size alias lk='ls -lSr' # sort by size
alias la='ls -Al' # show hidden files alias lc='ls -lcr' # sort by change time
alias lr='ls -lR' # recursice ls alias lu='ls -lur' # sort by access time
alias lt='ls -ltr' # sort by date alias lr='ls -lR' # recursive ls
alias lm='ls -al |more' # pipe through 'more' alias lt='ls -ltr' # sort by date
alias tree='tree -Cs' # nice alternative to 'ls' alias lm='ls -al |more' # pipe through 'more'
alias tree='tree -Csu' # nice alternative to 'ls'
# tailoring 'less' # tailoring 'less'
alias more='less' alias more='less'
@ -190,10 +239,11 @@ alias kk='ll'
function xtitle () function xtitle ()
{ {
case $TERM in case "$TERM" in
*term | rxvt) *term | rxvt)
echo -n -e "\033]0;$*\007" ;; echo -n -e "\033]0;$*\007" ;;
*) ;; *)
;;
esac esac
} }
@ -202,21 +252,22 @@ alias top='xtitle Processes on $HOST && top'
alias make='xtitle Making $(basename $PWD) ; make' alias make='xtitle Making $(basename $PWD) ; make'
alias ncftp="xtitle ncFTP ; ncftp" alias ncftp="xtitle ncFTP ; ncftp"
# .. and functions # .. and functions
function man () function man ()
{ {
xtitle The $(basename $1|tr -d .[:digit:]) manual for i ; do
man -a "$*" xtitle The $(basename $1|tr -d .[:digit:]) manual
command man -F -a "$i"
done
} }
function ll(){ ls -l "$@"| egrep "^d" ; ls -lXB "$@" 2>&-| egrep -v "^d|total "; } function ll(){ ls -l "$@"| egrep "^d" ; ls -lXB "$@" 2>&-| egrep -v "^d|total "; }
function xemacs() { { command xemacs -private $* 2>&- & } && disown ;}
function te() # wrapper around xemacs/gnuserv function te() # wrapper around xemacs/gnuserv
{ {
if [ "$(gnuclient -batch -eval t 2>&-)" == "t" ]; then if [ "$(gnuclient -batch -eval t 2>&-)" == "t" ]; then
gnuclient -q "$@"; gnuclient -q "$@";
else else
( xemacs "$@" & ); ( xemacs "$@" &);
fi fi
} }
@ -224,18 +275,33 @@ function te() # wrapper around xemacs/gnuserv
# File & strings related functions: # File & strings related functions:
#----------------------------------- #-----------------------------------
function ff() { find . -name '*'$1'*' ; } # find a file # Find a file with a pattern in name:
function fe() { find . -name '*'$1'*' -exec $2 {} \; ; } # find a file and run $2 on it function ff() { find . -type f -iname '*'$*'*' -ls ; }
function fstr() # find a string in a set of files # Find a file with pattern $1 in name and Execute $2 on it:
function fe() { find . -type f -iname '*'$1'*' -exec "${2:-file}" {} \; ; }
# find pattern in a set of filesand highlight them:
function fstr()
{ {
if [ "$#" -gt 2 ]; then OPTIND=1
echo "Usage: fstr \"pattern\" [files] " local case=""
local usage="fstr: find string in files.
Usage: fstr [-i] \"pattern\" [\"filename pattern\"] "
while getopts :it opt
do
case "$opt" in
i) case="-i " ;;
*) echo "$usage"; return;;
esac
done
shift $(( $OPTIND - 1 ))
if [ "$#" -lt 1 ]; then
echo "$usage"
return; return;
fi fi
SMSO=$(tput smso) local SMSO=$(tput smso)
RMSO=$(tput rmso) local RMSO=$(tput rmso)
find . -type f -name "${2:-*}" -print | xargs grep -sin "$1" | \ find . -type f -name "${2:-*}" -print0 | xargs -0 grep -sn ${case} "$1" 2>&- | \
sed "s/$1/$SMSO$1$RMSO/gI" sed "s/$1/${SMSO}\0${RMSO}/gI" | more
} }
function cuttail() # cut last n lines in file, 10 by default function cuttail() # cut last n lines in file, 10 by default
@ -266,11 +332,12 @@ function lowercase() # move filenames to lowercase
function swap() # swap 2 filenames around function swap() # swap 2 filenames around
{ {
local TMPFILE=tmp.$$ local TMPFILE=tmp.$$
mv $1 $TMPFILE mv "$1" $TMPFILE
mv $2 $1 mv "$2" "$1"
mv $TMPFILE $2 mv $TMPFILE "$2"
} }
#----------------------------------- #-----------------------------------
# Process/system related functions: # Process/system related functions:
#----------------------------------- #-----------------------------------
@ -283,16 +350,16 @@ function pp() { my_ps f | awk '!/awk/ && $0~var' var=${1:-".*"} ; }
function killps() # kill by process name function killps() # kill by process name
{ {
local pid pname sig="-TERM" # default signal local pid pname sig="-TERM" # default signal
if [ "$#" -lt 1 ] || [ "$#" -gt 2 ]; then if [ "$#" -lt 1 ] || [ "$#" -gt 2 ]; then
echo "Usage: killps [-SIGNAL] pattern" echo "Usage: killps [-SIGNAL] pattern"
return; return;
fi fi
if [ $# = 2 ]; then sig=$1 ; fi if [ $# = 2 ]; then sig=$1 ; fi
for pid in $(my_ps| awk '!/awk/ && $0~pat { print $1 }' pat=${!#} ) ; do for pid in $(my_ps| awk '!/awk/ && $0~pat { print $1 }' pat=${!#} ) ; do
pname=$(my_ps | awk '$1~var { print $5 }' var=$pid ) pname=$(my_ps | awk '$1~var { print $5 }' var=$pid )
if ask "Kill process $pid <$pname> with signal $sig?" if ask "Kill process $pid <$pname> with signal $sig?"
then kill $sig $pid then kill $sig $pid
fi fi
done done
} }
@ -316,7 +383,6 @@ function ii() # get current host related info
echo echo
} }
# Misc utilities: # Misc utilities:
function repeat() # repeat n times command function repeat() # repeat n times command
@ -328,7 +394,6 @@ function repeat() # repeat n times command
done done
} }
function ask() function ask()
{ {
echo -n "$@" '[y/n] ' ; read ans echo -n "$@" '[y/n] ' ; read ans
@ -341,8 +406,9 @@ function ask()
#========================================================================= #=========================================================================
# #
# PROGRAMMABLE COMPLETION - ONLY SINCE BASH-2.04 # PROGRAMMABLE COMPLETION - ONLY SINCE BASH-2.04
# (Most are taken from the bash 2.05 documentation) # Most are taken from the bash 2.05 documentation and from Ian McDonalds
# You will in fact need bash-2.05 for some features # 'Bash completion' package (http://www.caliban.org/bash/index.shtml#completion)
# You will in fact need bash-2.05a for some features
# #
#========================================================================= #=========================================================================
@ -352,11 +418,9 @@ if [ "${BASH_VERSION%.*}" \< "2.05" ]; then
fi fi
shopt -s extglob # necessary shopt -s extglob # necessary
set +o nounset # otherwise some completions will fail set +o nounset # otherwise some completions will fail
complete -A hostname rsh rcp telnet rlogin r ftp ping disk complete -A hostname rsh rcp telnet rlogin r ftp ping disk
complete -A command nohup exec eval trace gdb
complete -A command command type which
complete -A export printenv complete -A export printenv
complete -A variable export local readonly unset complete -A variable export local readonly unset
complete -A enabled builtin complete -A enabled builtin
@ -372,40 +436,57 @@ complete -A job -P '%' fg jobs disown
complete -A directory mkdir rmdir complete -A directory mkdir rmdir
complete -A directory -o default cd complete -A directory -o default cd
complete -f -d -X '*.gz' gzip # Compression
complete -f -d -X '*.bz2' bzip2 complete -f -o default -X '*.+(zip|ZIP)' zip
complete -f -o default -X '!*.gz' gunzip complete -f -o default -X '!*.+(zip|ZIP)' unzip
complete -f -o default -X '!*.bz2' bunzip2 complete -f -o default -X '*.+(z|Z)' compress
complete -f -o default -X '!*.pl' perl perl5 complete -f -o default -X '!*.+(z|Z)' uncompress
complete -f -o default -X '*.+(gz|GZ)' gzip
complete -f -o default -X '!*.+(gz|GZ)' gunzip
complete -f -o default -X '*.+(bz2|BZ2)' bzip2
complete -f -o default -X '!*.+(bz2|BZ2)' bunzip2
# Postscript,pdf,dvi.....
complete -f -o default -X '!*.ps' gs ghostview ps2pdf ps2ascii complete -f -o default -X '!*.ps' gs ghostview ps2pdf ps2ascii
complete -f -o default -X '!*.dvi' dvips dvipdf xdvi dviselect dvitype complete -f -o default -X '!*.dvi' dvips dvipdf xdvi dviselect dvitype
complete -f -o default -X '!*.pdf' acroread pdf2ps complete -f -o default -X '!*.pdf' acroread pdf2ps
complete -f -o default -X '!*.+(pdf|ps)' gv complete -f -o default -X '!*.+(pdf|ps)' gv
complete -f -o default -X '!*.texi*' makeinfo texi2dvi texi2html texi2pdf complete -f -o default -X '!*.texi*' makeinfo texi2dvi texi2html texi2pdf
complete -f -o default -X '!*.tex' tex latex slitex complete -f -o default -X '!*.tex' tex latex slitex
complete -f -o default -X '!*.lyx' lyx complete -f -o default -X '!*.lyx' lyx
complete -f -o default -X '!*.+(jpg|gif|xpm|png|bmp)' xv gimp complete -f -o default -X '!*.+(htm*|HTM*)' lynx html2ps
complete -f -o default -X '!*.mp3' mpg123 # Multimedia
complete -f -o default -X '!*.ogg' ogg123 complete -f -o default -X '!*.+(jp*g|gif|xpm|png|bmp)' xv gimp
complete -f -o default -X '!*.+(mp3|MP3)' mpg123 mpg321
complete -f -o default -X '!*.+(ogg|OGG)' ogg123
complete -f -o default -X '!*.pl' perl perl5
# This is a 'universal' completion function - it works when commands have # This is a 'universal' completion function - it works when commands have
# a so-called 'long options' mode , ie: 'ls --all' instead of 'ls -a' # a so-called 'long options' mode , ie: 'ls --all' instead of 'ls -a'
_universal_func ()
_get_longopts ()
{
$1 --help | sed -e '/--/!d' -e 's/.*--\([^[:space:].,]*\).*/--\1/'| \
grep ^"$2" |sort -u ;
}
_longopts_func ()
{ {
case "$2" in case "${2:-*}" in
-*) ;; -*) ;;
*) return ;; *) return ;;
esac esac
case "$1" in case "$1" in
\~*) eval cmd=$1 ;; \~*) eval cmd="$1" ;;
*) cmd="$1" ;; *) cmd="$1" ;;
esac esac
COMPREPLY=( $("$cmd" --help | sed -e '/--/!d' -e 's/.*--\([^ ]*\).*/--\1/'| \ COMPREPLY=( $(_get_longopts ${1} ${2} ) )
grep ^"$2" |sort -u) )
} }
complete -o default -F _universal_func ldd wget bash id info complete -o default -F _longopts_func configure bash
complete -o default -F _longopts_func wget id info a2ps ls recode
_make_targets () _make_targets ()
@ -459,22 +540,6 @@ _make_targets ()
complete -F _make_targets -X '+($*|*.[cho])' make gmake pmake complete -F _make_targets -X '+($*|*.[cho])' make gmake pmake
_configure_func ()
{
case "$2" in
-*) ;;
*) return ;;
esac
case "$1" in
\~*) eval cmd=$1 ;;
*) cmd="$1" ;;
esac
COMPREPLY=( $("$cmd" --help | awk '{if ($1 ~ /--.*/) print $1}' | grep ^"$2" | sort -u) )
}
complete -F _configure_func configure
# cvs(1) completion # cvs(1) completion
_cvs () _cvs ()
@ -485,17 +550,16 @@ _cvs ()
prev=${COMP_WORDS[COMP_CWORD-1]} prev=${COMP_WORDS[COMP_CWORD-1]}
if [ $COMP_CWORD -eq 1 ] || [ "${prev:0:1}" = "-" ]; then if [ $COMP_CWORD -eq 1 ] || [ "${prev:0:1}" = "-" ]; then
COMPREPLY=( $( compgen -W 'add admin checkout commit diff \ COMPREPLY=( $( compgen -W 'add admin checkout commit diff \
export history import log rdiff release remove rtag status \ export history import log rdiff release remove rtag status \
tag update' $cur )) tag update' $cur ))
else else
COMPREPLY=( $( compgen -f $cur )) COMPREPLY=( $( compgen -f $cur ))
fi fi
return 0 return 0
} }
complete -F _cvs cvs complete -F _cvs cvs
_killall () _killall ()
{ {
local cur prev local cur prev
@ -514,6 +578,60 @@ _killall ()
complete -F _killall killall killps complete -F _killall killall killps
# A meta-command completion function for commands like sudo(8), which need to
# first complete on a command, then complete according to that command's own
# completion definition - currently not quite foolproof (e.g. mount and umount
# don't work properly), but still quite useful - By Ian McDonald, modified by me.
_my_command()
{
local cur func cline cspec
COMPREPLY=()
cur=${COMP_WORDS[COMP_CWORD]}
if [ $COMP_CWORD = 1 ]; then
COMPREPLY=( $( compgen -c $cur ) )
elif complete -p ${COMP_WORDS[1]} &>/dev/null; then
cspec=$( complete -p ${COMP_WORDS[1]} )
if [ "${cspec%%-F *}" != "${cspec}" ]; then
# complete -F &lt;function&gt;
#
# COMP_CWORD and COMP_WORDS() are not read-only,
# so we can set them before handing off to regular
# completion routine
# set current token number to 1 less than now
COMP_CWORD=$(( $COMP_CWORD - 1 ))
# get function name
func=${cspec#*-F }
func=${func%% *}
# get current command line minus initial command
cline="${COMP_LINE#$1 }"
# split current command line tokens into array
COMP_WORDS=( $cline )
$func $cline
elif [ "${cspec#*-[abcdefgjkvu]}" != "" ]; then
# complete -[abcdefgjkvu]
#func=$( echo $cspec | sed -e 's/^.*\(-[abcdefgjkvu]\).*$/\1/' )
func=$( echo $cspec | sed -e 's/^complete//' -e 's/[^ ]*$//' )
COMPREPLY=( $( eval compgen $func $cur ) )
elif [ "${cspec#*-A}" != "$cspec" ]; then
# complete -A &lt;type&gt;
func=${cspec#*-A }
func=${func%% *}
COMPREPLY=( $( compgen -A $func $cur ) )
fi
else
COMPREPLY=( $( compgen -f $cur ) )
fi
}
complete -o default -F _my_command nohup exec eval trace truss strace sotruss gdb
complete -o default -F _my_command command type which man nice
# Local Variables: # Local Variables:
# mode:shell-script # mode:shell-script
# sh-shell:bash # sh-shell:bash

View File

@ -81,7 +81,7 @@ echo "File \"$file\" blotted out and deleted."; echo
# For an in-depth analysis on the topic of file deletion and security, # For an in-depth analysis on the topic of file deletion and security,
#+ see Peter Gutmann's paper, #+ see Peter Gutmann's paper,
#+ "Secure Deletion of Data From Magnetic and Solid-State Memory". #+ "Secure Deletion of Data From Magnetic and Solid-State Memory".
# http://www.cs.auckland.ac.nz/~pgut001/secure_del.html # http://www.cs.auckland.ac.nz/~pgut001/pubs/secure_del.html
exit 0 exit 0

View File

@ -24,10 +24,16 @@ do
filename=${file%.*c} # Strip ".mac" suffix off filename filename=${file%.*c} # Strip ".mac" suffix off filename
#+ ('.*c' matches everything #+ ('.*c' matches everything
#+ between '.' and 'c', inclusive). #+ between '.' and 'c', inclusive).
$OPERATION $file > $filename.$SUFFIX $OPERATION $file > "$filename.$SUFFIX"
# Redirect conversion to new filename. # Redirect conversion to new filename.
rm -f $file # Delete original files after converting. rm -f $file # Delete original files after converting.
echo "$filename.$SUFFIX" # Log what is happening to stdout. echo "$filename.$SUFFIX" # Log what is happening to stdout.
done done
exit 0 exit 0
# Exercise:
# --------
# As it stands, this script converts *all* the files in the current
#+ working directory.
# Modify it to work *only* on files with a ".mac" suffix.

View File

@ -1,6 +1,10 @@
#!/bin/bash #!/bin/bash
# empty-array.sh # empty-array.sh
# Thanks to Stephane Chazelas for the original example,
#+ and to Michael Zick for extending it.
# An empty array is not the same as an array with empty elements. # An empty array is not the same as an array with empty elements.
array0=( first second third ) array0=( first second third )
@ -8,7 +12,9 @@ array1=( '' ) # "array1" has one empty element.
array2=( ) # No elements... "array2" is empty. array2=( ) # No elements... "array2" is empty.
echo echo
ListArray()
{
echo
echo "Elements in array0: ${array0[@]}" echo "Elements in array0: ${array0[@]}"
echo "Elements in array1: ${array1[@]}" echo "Elements in array1: ${array1[@]}"
echo "Elements in array2: ${array2[@]}" echo "Elements in array2: ${array2[@]}"
@ -20,7 +26,101 @@ echo
echo "Number of elements in array0 = ${#array0[*]}" # 3 echo "Number of elements in array0 = ${#array0[*]}" # 3
echo "Number of elements in array1 = ${#array1[*]}" # 1 (surprise!) echo "Number of elements in array1 = ${#array1[*]}" # 1 (surprise!)
echo "Number of elements in array2 = ${#array2[*]}" # 0 echo "Number of elements in array2 = ${#array2[*]}" # 0
}
# ===================================================================
ListArray
# Try extending those arrays
# Adding an element to an array.
array0=( "${array0[@]}" "new1" )
array1=( "${array1[@]}" "new1" )
array2=( "${array2[@]}" "new1" )
ListArray
# or
array0[${#array0[*]}]="new2"
array1[${#array1[*]}]="new2"
array2[${#array2[*]}]="new2"
ListArray
# When extended as above; arrays are 'stacks'
# The above is the 'push'
# The stack 'height' is:
height=${#array2[@]}
echo echo
echo "Stack height for array2 = $height"
exit 0 # Thanks, S.C. # The 'pop' is:
unset array2[${#array2[@]}-1] # Arrays are zero based
height=${#array2[@]}
echo
echo "POP"
echo "New stack height for array2 = $height"
ListArray
# List only 2nd and 3rd elements of array0
from=1 # Zero based numbering
to=2 #
declare -a array3=( ${array0[@]:1:2} )
echo
echo "Elements in array3: ${array3[@]}"
# Works like a string (array of characters)
# Try some other "string" forms
# Replacement
declare -a array4=( ${array0[@]/second/2nd} )
echo
echo "Elements in array4: ${array4[@]}"
# Replace all matching wildcarded string
declare -a array5=( ${array0[@]//new?/old} )
echo
echo "Elements in array5: ${array5[@]}"
# Just when you are getting the feel for this...
declare -a array6=( ${array0[@]#*new} )
echo # This one might surprise you
echo "Elements in array6: ${array6[@]}"
declare -a array7=( ${array0[@]#new1} )
echo # After array6 this should not be a surprise
echo "Elements in array7: ${array7[@]}"
# Which looks a lot like...
declare -a array8=( ${array0[@]/new1/} )
echo
echo "Elements in array8: ${array8[@]}"
# So what can one say about this?
# The string operations are performed on
#+ each of the elements in var[@] in succession.
# Therefore : BASH supports string vector operations
# If the result is a zero length string, that
#+ element disappears in the resulting assignment.
# Question, are those strings hard or soft quotes?
zap='new*'
declare -a array9=( ${array0[@]/$zap/} )
echo
echo "Elements in array9: ${array9[@]}"
# Just when you thought you where still in Kansas...
declare -a array10=( ${array0[@]#$zap} )
echo
echo "Elements in array10: ${array10[@]}"
# Compare array7 with array10
# Compare array8 with array9
# Answer, must be soft quotes.
exit 0

View File

@ -17,3 +17,9 @@ echo >>logfile
echo >>logfile echo >>logfile
exit 0 exit 0
# Exercise:
# --------
# Modify this script to track changes in /var/log/messages at intervals
#+ of 20 minutes.
# Hint: Use the "watch" command.

View File

@ -7,7 +7,7 @@ DOC_REQUEST=70
if [ "$1" = "-h" -o "$1" = "--help" ] # Request help. if [ "$1" = "-h" -o "$1" = "--help" ] # Request help.
then then
echo; echo "Usage: $0 [directory-name]"; echo echo; echo "Usage: $0 [directory-name]"; echo
cat "$0" | sed --silent -e '/DOCUMENTATIONXX$/,/^DOCUMENTATION/p' | sed --silent -e '/DOCUMENTATIONXX$/,/^DOCUMENTATION/p' "$0" |
sed -e '/DOCUMENTATIONXX/d'; exit $DOC_REQUEST; fi sed -e '/DOCUMENTATIONXX/d'; exit $DOC_REQUEST; fi
: << DOCUMENTATIONXX : << DOCUMENTATIONXX

View File

@ -1,6 +1,6 @@
#!/bin/sh #!/bin/sh
# @(#) tree 1.1 30/11/95 by Jordi Sanfeliu # @(#) tree 1.1 30/11/95 by Jordi Sanfeliu
# email: mikaku@arrakis.es # email: mikaku@fiwix.org
# #
# Initial version: 1.0 30/11/95 # Initial version: 1.0 30/11/95
# Next version : 1.1 24/02/97 Now, with symbolic links # Next version : 1.1 24/02/97 Now, with symbolic links