mirror of https://github.com/tLDP/LDP
updated
This commit is contained in:
parent
54b9f39293
commit
dc5f74fc57
|
@ -3,18 +3,80 @@
|
|||
Release History
|
||||
|
||||
The latest version of this file is available on-line at
|
||||
http://personal.riverusers.com/~thegrendel/Change.log
|
||||
http://http://bash.neuralshortcircuit.com/Change.log
|
||||
|
||||
|
||||
==================================================================
|
||||
Current version = 5.5
|
||||
Dated 11/23/08
|
||||
http://personal.riverusers.com/~thegrendel/abs-guide-5.5.tar.bz2
|
||||
http://personal.riverusers.com/~thegrendel/abs-guide.pdf
|
||||
Current version = 5.6
|
||||
Dated 01/26/09
|
||||
|
||||
http://bash.neuralshortcircuit.com/abs-guide-latest.tar.bz2
|
||||
http://bash.neuralshortcircuit.com/abs-guide.pdf
|
||||
--------------------------------------------------------------------
|
||||
News: Mostly a bugfix release. A fair amount of new material added.
|
||||
News: Added Knight's Tour script (ktour.sh),
|
||||
Magic Square script (msquare.sh).
|
||||
--------------------------------------------------------------------
|
||||
Remarks: Gradually adding in-line definitions for technical terms,
|
||||
usually as sidebars, less often as footnotes.
|
||||
====================================================================
|
||||
|
||||
Version 5.6, Worcesterberry release
|
||||
01/26/09
|
||||
|
||||
1) In "Special Characters" chapter:
|
||||
At "#" (comments) entry, added example of comment embedded within a pipe.
|
||||
At "semicolon" entry, slightly revised comments.
|
||||
Corrected a typo in "filter" footnote ("rougly").
|
||||
At "$IFS" entry, added sidebar defining the term "field."
|
||||
|
||||
2) In "Variables Revisited" chapter:
|
||||
In "Manipulating Strings" section:
|
||||
* Expanded first inline
|
||||
"Substring Replacement example, thanks to the suggestion from
|
||||
Zhiyi Liu. Also added explanatory footnote.
|
||||
* Fixed minor typo in "rand-string.sh" example script.
|
||||
(Thank you, Ethan Larson, for bringing it to my attention.)
|
||||
|
||||
3) In "Internal Commands and Builtins" chapter:
|
||||
At "let" reference, inserted footnote that the command cannot be used
|
||||
for setting string variables.
|
||||
|
||||
4) In "Regular Expressions" chapter:
|
||||
Added example snippet of use of POSIX character classes
|
||||
(excerpted from ktour.sh example).
|
||||
|
||||
5) In "Gotchas" chapter:
|
||||
Added entry about misuse of "let" command to set string variables.
|
||||
|
||||
6) In "Contributed Scripts" appendix:
|
||||
Added "ktour.sh" -- Knight's Tour -- example script.
|
||||
Added "msquare.sh" -- Magic Square -- example script.
|
||||
|
||||
7) In "Bibliography" section:
|
||||
Added http://bashcookbook.com entry.
|
||||
Word usage cleanups in a couple of entries.
|
||||
|
||||
8) Moved the download and mirror site URLs from the title page
|
||||
to the "Download and Mirror Sites" appendix (where they rightfully
|
||||
belong!).
|
||||
Removed http://personal.riverusers/~thegrendel/ URL.
|
||||
|
||||
In Download and Mirror Sites" appendix:
|
||||
Gave Ronny Bangsund credit for graciously donating server space for
|
||||
a mirror site.
|
||||
Removed stale www.morethan.org URL.
|
||||
|
||||
Updated document author's e-mal.
|
||||
|
||||
9) Updated sample "bashrc" file (Appendix K).
|
||||
|
||||
10) Cleanups/fixups to main text, appendices, and script examples where
|
||||
appropriate.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Version 5.5, Farkleberry release
|
||||
11/28/08
|
||||
|
||||
|
@ -28,7 +90,7 @@ Version 5.5, Farkleberry release
|
|||
In "Quoting Variables" subsection, simplified introductory
|
||||
paragraph to eliminate confusion.
|
||||
|
||||
4 ) In "Special Characters" chapter:
|
||||
4) In "Special Characters" chapter:
|
||||
At "comma operator" entry, added discussion and usage example
|
||||
for string concatenation.
|
||||
(Thank you, Rory Winston!)
|
||||
|
|
|
@ -1378,6 +1378,9 @@
|
|||
returns <firstterm>unsuccessful</firstterm> (1) <link
|
||||
linkend="exitstatusref">exit status</link></para>
|
||||
|
||||
<para><link linkend="fieldref">Field</link>, a group of characters
|
||||
that comprises an item of data</para>
|
||||
|
||||
<para><link linkend="filearchiv">Files / Archiving</link></para>
|
||||
|
||||
<para><link linkend="fdref">File descriptors</link></para>
|
||||
|
@ -1495,8 +1498,12 @@
|
|||
linkend="cards">Dealing a deck of cards</link></para></listitem>
|
||||
<listitem><para><link
|
||||
linkend="horserace">Horse race</link></para></listitem>
|
||||
<listitem><para><link
|
||||
linkend="ktour">Knight's Tour</link></para></listitem>
|
||||
<listitem><para><link linkend="lifeslow"><quote>Life</quote>
|
||||
game</link></para></listitem>
|
||||
<listitem><para><link
|
||||
linkend="msquare">Magic Squares</link></para></listitem>
|
||||
<listitem><para><link linkend="musicscr">Music-playing
|
||||
script</link></para></listitem>
|
||||
<listitem><para><link linkend="nim">Nim</link></para></listitem>
|
||||
|
@ -2071,6 +2078,9 @@
|
|||
<listitem><para><link linkend="catabuse">Avoiding
|
||||
unnecessary commands</link> in a
|
||||
<firstterm>pipe</firstterm></para></listitem>
|
||||
<listitem><para><link
|
||||
linkend="comminpipe"><firstterm>Comments</firstterm> embedded
|
||||
within</link></para></listitem>
|
||||
<listitem><para><link linkend="pipefailref">Pipefail</link>,
|
||||
<firstterm>set -o pipefail</firstterm>
|
||||
option to indicate <link linkend="exitstatusref">exit status</link>
|
||||
|
@ -2126,6 +2136,9 @@
|
|||
within <firstterm>test</firstterm> brackets</para></listitem>
|
||||
<listitem><para><link linkend="gnuref"><firstterm>GNU</firstterm>
|
||||
command set</link>, in cross-platform scripts</para></listitem>
|
||||
<listitem><para><firstterm>let</firstterm> misuse:
|
||||
<link linkend="letbad">attempting to set string variables</link>
|
||||
</para></listitem>
|
||||
<listitem><para><link linkend="rvtcaution2">Multiple echo
|
||||
statements</link> in a <link linkend="rvt">function whose
|
||||
output is captured</link></para></listitem>
|
||||
|
|
|
@ -54,7 +54,7 @@ cdll (lines 51-53, 59, 63-69, 82-83, 85, 463, 521, 567-568, 570,
|
|||
580-586, 637, 656-658)
|
||||
directory-info.sh (lines 36, 166, 273 and 353)
|
||||
is-spammer.sh (comments on lines 4, 35, and 51)
|
||||
bashrc (comments on lines 596 and 618)
|
||||
bashrc (comment on line 4)
|
||||
commentblock.sh (lines 4 and 23)
|
||||
self-document.sh (line 14)
|
||||
self-document2.sh (line 8)
|
||||
|
@ -103,8 +103,8 @@ qky.sh
|
|||
line 63
|
||||
line 87
|
||||
line 113
|
||||
(The unaltered, executable script can be downloaded. See:
|
||||
http://personal.riverusers.com/~thegrendel/qky.README.html)
|
||||
(The unaltered, executable script can be downloaded.
|
||||
See: http://bash.neuralshortcircuit.com/qky.README.html)
|
||||
|
||||
maned.sh
|
||||
line 6 (comment)
|
||||
|
|
|
@ -358,6 +358,8 @@
|
|||
<!ENTITY petals SYSTEM "petals.sh">
|
||||
<!ENTITY qky SYSTEM "qky.sh">
|
||||
<!ENTITY maned SYSTEM "maned.sh">
|
||||
<!ENTITY ktour SYSTEM "ktour.sh">
|
||||
<!ENTITY msquare SYSTEM "msquare.sh">
|
||||
<!ENTITY nim SYSTEM "nim.sh">
|
||||
<!ENTITY stddev SYSTEM "sd.sh">
|
||||
<!ENTITY gen0data SYSTEM "gen0">
|
||||
|
@ -377,26 +379,19 @@
|
|||
<surname>Cooper</surname>
|
||||
<affiliation>
|
||||
<orgname></orgname>
|
||||
<address><email>thegrendel@theriver.com</email></address>
|
||||
<address><email>thegrendel.abs@gmail.com</email></address>
|
||||
</affiliation>
|
||||
</author>
|
||||
|
||||
|
||||
<releaseinfo>5.5</releaseinfo>
|
||||
<pubdate>23 November 2008</pubdate>
|
||||
<releaseinfo>5.6</releaseinfo>
|
||||
<pubdate>26 January 2009</pubdate>
|
||||
<isbn>978-1-4357-5219-1</isbn>
|
||||
|
||||
|
||||
|
||||
<revhistory>
|
||||
|
||||
<revision>
|
||||
<revnumber>5.3</revnumber>
|
||||
<date>05 May 2008</date>
|
||||
<authorinitials>mc</authorinitials>
|
||||
<revremark>'GOLDENBERRY' release: Minor Update.</revremark>
|
||||
</revision>
|
||||
|
||||
<revision>
|
||||
<revnumber>5.4</revnumber>
|
||||
<date>21 July 2008</date>
|
||||
|
@ -411,6 +406,13 @@
|
|||
<revremark>'FARKLEBERRY' release: Minor Update.</revremark>
|
||||
</revision>
|
||||
|
||||
<revision>
|
||||
<revnumber>5.6</revnumber>
|
||||
<date>26 Jan 2009</date>
|
||||
<authorinitials>mc</authorinitials>
|
||||
<revremark>'WORCESTERBERRY' release: Minor Update.</revremark>
|
||||
</revision>
|
||||
|
||||
</revhistory>
|
||||
|
||||
|
||||
|
@ -430,22 +432,6 @@
|
|||
<para>This book is suitable for classroom use as a general
|
||||
introduction to programming concepts.</para>
|
||||
|
||||
|
||||
<para><anchor id="where_tarball"></para>
|
||||
|
||||
<para><ulink
|
||||
url="http://personal.riverusers.com/~thegrendel/abs-guide-5.5.tar.bz2">
|
||||
The latest update of this document</ulink>, as an archived, <link
|
||||
linkend="bzipref">bzip2-ed</link> <quote>tarball</quote>
|
||||
including both the SGML source and rendered HTML, may
|
||||
be downloaded from the author's home site. A <ulink
|
||||
url="http://www.tldp.org/LDP/abs/abs-guide.pdf">pdf
|
||||
version</ulink> is also available (<ulink
|
||||
url="http://personal.riverusers.com/~thegrendel/abs-guide.pdf"> pdf mirror
|
||||
site</ulink>). See the <ulink
|
||||
url="http://personal.riverusers.com/~thegrendel/Change.log">change
|
||||
log</ulink> for a revision history.</para>
|
||||
|
||||
</abstract>
|
||||
</bookinfo>
|
||||
|
||||
|
@ -660,16 +646,17 @@
|
|||
|
||||
give them <firstterm>execute</firstterm> permission
|
||||
(<userinput>chmod u+rx scriptname</userinput>),
|
||||
then run them to see what happens. Should the source
|
||||
archive not be available, then cut-and-paste from the <ulink
|
||||
then run them to see what happens. Should the <ulink
|
||||
url="http://bash.neuralshortcircuit.com/abs-guide-latest.tar.bz2">source
|
||||
archive</ulink> not be available, then cut-and-paste from the <ulink
|
||||
url="http://www.tldp.org/LDP/abs/abs-guide.html.tar.gz">HTML</ulink> or
|
||||
<ulink url="http://www.tldp.org/LDP/abs/abs-guide.pdf">pdf</ulink>
|
||||
<ulink url="http://bash.neuralshortcircuit.com/abs-guide.pdf">pdf</ulink>
|
||||
rendered versions. Be aware that some of the scripts presented here
|
||||
introduce features before they are explained, and this may require
|
||||
the reader to temporarily skip ahead for enlightenment.</para>
|
||||
|
||||
<para>Unless otherwise noted, <ulink
|
||||
url="mailto:thegrendel@theriver.com">the author</ulink> of this
|
||||
url="mailto:thegrendel.abs@gmail.com">the author</ulink> of this
|
||||
book wrote the example scripts that follow.</para>
|
||||
|
||||
<epigraph>
|
||||
|
@ -1056,12 +1043,23 @@ fi</programlisting>
|
|||
<para><programlisting>echo "A comment will follow." # Comment here.
|
||||
# ^ Note whitespace before #</programlisting></para>
|
||||
|
||||
<para><anchor id="wsbcomm"></para>
|
||||
<para>Comments may also follow <link
|
||||
<para><anchor id="wsbcomm"> Comments may also follow <link
|
||||
linkend="whitespaceref">whitespace</link> at the beginning
|
||||
of a line.</para>
|
||||
<para>
|
||||
<programlisting># A tab precedes this comment.</programlisting>
|
||||
</para>
|
||||
|
||||
<para><anchor id="comminpipe">Comments may even be embedded
|
||||
within a <link linkend="piperef">pipe</link>.</para>
|
||||
<para>
|
||||
<programlisting>initial=( `cat "$startfile" | sed -e '/#/d' | tr -d '\n' |\
|
||||
# Delete lines containing '#' comment character.
|
||||
sed -e 's/\./\. /g' -e 's/_/_ /g'` )
|
||||
# Excerpted from life.sh script</programlisting>
|
||||
</para>
|
||||
|
||||
|
||||
<para><programlisting> # A tab precedes this comment.</programlisting></para>
|
||||
|
||||
<caution><para>A command may not follow a comment on the
|
||||
same line. There is no method of terminating the comment,
|
||||
|
@ -1118,10 +1116,10 @@ echo $(( 2#101011 )) # Base conversion, not a comment.
|
|||
<programlisting>echo hello; echo there
|
||||
|
||||
|
||||
if [ -x "$filename" ]; then # Note that "if" and "then" need whitespace
|
||||
#+ separation. Why?
|
||||
if [ -x "$filename" ]; then # Note the space after the semicolon.
|
||||
#+ ^^
|
||||
echo "File $filename exists."; cp $filename $filename.bak
|
||||
else
|
||||
else # ^^
|
||||
echo "File $filename not found."; touch $filename
|
||||
fi; echo "File test complete."</programlisting>
|
||||
</para>
|
||||
|
@ -1522,7 +1520,8 @@ fi</programlisting>
|
|||
<programlisting>: This is a comment that generates an error, ( if [ $x -eq 3] ).</programlisting>
|
||||
</para>
|
||||
|
||||
<para>The <quote><token>:</token></quote> also serves as a field
|
||||
<para>The <quote><token>:</token></quote> also serves as a <link
|
||||
linkend="fieldref">field</link>
|
||||
separator, in <link
|
||||
linkend="datafilesref1"><filename>/etc/passwd</filename></link>,
|
||||
and in the <link linkend="pathref">$PATH</link> variable.
|
||||
|
@ -1890,10 +1889,10 @@ echo $var2 # 23skidoo</programlisting>
|
|||
</para>
|
||||
<para><anchor id="processref"></para>
|
||||
<para>
|
||||
Definition: A <firstterm>process</firstterm> is
|
||||
an executing program, sometimes referred to as a
|
||||
<firstterm>job</firstterm>.
|
||||
</para>
|
||||
<userinput>Definition:</userinput> A
|
||||
<firstterm>process</firstterm> is a currently
|
||||
executing program, sometimes referred to as a
|
||||
<firstterm>job</firstterm>. </para>
|
||||
</footnote>
|
||||
of the script in which it appears.</para>
|
||||
</formalpara>
|
||||
|
@ -2473,7 +2472,7 @@ cat *.lst | sort | uniq
|
|||
<firstterm>philtre</firstterm> denoted a potion alleged
|
||||
to have magical transformative powers, so does a UNIX
|
||||
<firstterm>filter</firstterm> transform its target in
|
||||
(rougly) analogous fashion. (The coder who comes up with a
|
||||
(roughly) analogous fashion. (The coder who comes up with a
|
||||
<quote>love philtre</quote> that runs on a Linux machine
|
||||
will likely win accolades and honors.)</para></footnote>
|
||||
</para>
|
||||
|
@ -3376,7 +3375,9 @@ echo <Ctl-V><Ctl-J></programlisting></para>
|
|||
<varlistentry>
|
||||
<term><anchor id="whitespaceref">Whitespace</term>
|
||||
<listitem>
|
||||
<formalpara><title>functions as a separator, separating commands or variables.</title>
|
||||
<formalpara>
|
||||
<title>functions as a separator between commands and/or
|
||||
variables.</title>
|
||||
<para>Whitespace consists of either
|
||||
<firstterm>spaces</firstterm>,
|
||||
<firstterm>tabs</firstterm>, <firstterm>blank
|
||||
|
@ -3398,8 +3399,19 @@ echo <Ctl-V><Ctl-J></programlisting></para>
|
|||
sections.</para>
|
||||
|
||||
<para><link linkend="ifsref">$IFS</link>, the special variable
|
||||
separating fields of input to certain commands, defaults
|
||||
to whitespace.</para>
|
||||
separating <firstterm>fields</firstterm> of input to certain
|
||||
commands. It defaults to whitespace.</para>
|
||||
|
||||
<sidebar><para>
|
||||
<anchor id="fieldref"><userinput>Definition:</userinput>
|
||||
A <firstterm>field</firstterm> is a discrete chunk of data
|
||||
expressed as a string of consecutive characters.
|
||||
Separating each field from adjacent fields is either
|
||||
<firstterm>whitespace</firstterm> or some other designated
|
||||
character (often determined by the <token>$IFS</token>).
|
||||
In some contexts, a field may be called a
|
||||
<firstterm>record</firstterm>.
|
||||
</para></sidebar>
|
||||
|
||||
<para><anchor id="quotingws"></para>
|
||||
<para>To preserve <firstterm>whitespace</firstterm>
|
||||
|
@ -3751,9 +3763,10 @@ arch=$(uname -m)</programlisting></para>
|
|||
<emphasis><link linkend="forkref">Child processes</link>
|
||||
cannot export variables back to the parent processes that
|
||||
spawned them.</emphasis></para>
|
||||
<para><anchor id="childref2">Definition: A <firstterm>child
|
||||
process</firstterm> is a subprocess launched by another
|
||||
process, its <link linkend="parentref">parent</link>.</para>
|
||||
<para><anchor id="childref2"><userinput>Definition:</userinput>
|
||||
A <firstterm>child process</firstterm> is a
|
||||
subprocess launched by another process, its <link
|
||||
linkend="parentref">parent</link>.</para>
|
||||
</note>
|
||||
|
||||
|
||||
|
@ -4876,7 +4889,7 @@ fi
|
|||
# The very useful "if-grep" construct:
|
||||
# -----------------------------------
|
||||
if grep -q Bash file
|
||||
then echo "File contains at least one occurrence of Bash."
|
||||
then echo "File contains at least one occurrence of Bash."
|
||||
fi
|
||||
|
||||
word=Linux
|
||||
|
@ -4891,8 +4904,8 @@ fi
|
|||
|
||||
|
||||
if COMMAND_WHOSE_EXIT_STATUS_IS_0_UNLESS_ERROR_OCCURRED
|
||||
then echo "Command succeeded."
|
||||
else echo "Command failed."
|
||||
then echo "Command succeeded."
|
||||
else echo "Command failed."
|
||||
fi</programlisting>
|
||||
</para>
|
||||
</listitem>
|
||||
|
@ -6894,8 +6907,9 @@ echo "FUNCNAME = $FUNCNAME" # FUNCNAME =
|
|||
</indexterm>
|
||||
<listitem><para>internal field separator</para>
|
||||
|
||||
<para>This variable determines how Bash recognizes fields, or word
|
||||
boundaries, when it interprets character strings.</para>
|
||||
<para>This variable determines how Bash recognizes <link
|
||||
linkend="fieldref">fields</link>, or word boundaries,
|
||||
when it interprets character strings.</para>
|
||||
|
||||
<para><anchor id="ifsws"></para>
|
||||
<para>$IFS defaults to <link
|
||||
|
@ -6982,13 +6996,13 @@ echo "FUNCNAME = $FUNCNAME" # FUNCNAME =
|
|||
</indexterm>
|
||||
<listitem>
|
||||
|
||||
<para>Often set in the <filename>.bashrc</filename> or
|
||||
<filename>/etc/profile</filename> files, this
|
||||
<para>Often set in the <link
|
||||
linkend="sample-bashrc"<filename>.bashrc</filename></link>
|
||||
or <filename>/etc/profile</filename> files, this
|
||||
variable controls collation order in filename
|
||||
expansion and pattern matching. If mishandled,
|
||||
<varname>LC_COLLATE</varname> can cause unexpected results
|
||||
in <link linkend="globbingref">filename
|
||||
globbing</link>.</para>
|
||||
<varname>LC_COLLATE</varname> can cause unexpected results in
|
||||
<link linkend="globbingref">filename globbing</link>.</para>
|
||||
|
||||
<note><para>As of version 2.05 of Bash,
|
||||
filename globbing no longer distinguishes between lowercase
|
||||
|
@ -7138,8 +7152,9 @@ echo "Last command argument processed = $last_cmd_arg"
|
|||
of directories, separated by colons. Normally,
|
||||
the system stores the <varname>$PATH</varname>
|
||||
definition in <filename>/etc/profile</filename>
|
||||
and/or <filename>~/.bashrc</filename> (see <xref
|
||||
linkend="files">).</para>
|
||||
and/or <link
|
||||
linkend="sample-bashrc"><filename>~/.bashrc</filename></link>
|
||||
(see <xref linkend="files">).</para>
|
||||
|
||||
<para><screen><prompt>bash$ </prompt><command>echo $PATH</command>
|
||||
<computeroutput>/bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin:/sbin:/usr/sbin</computeroutput></screen>
|
||||
|
@ -8540,9 +8555,17 @@ echo ${stringZ%%b*c} # a
|
|||
</indexterm>
|
||||
|
||||
<listitem>
|
||||
<para>Replace first match of
|
||||
<para>
|
||||
Replace first <firstterm>match</firstterm> of
|
||||
<replaceable>$substring</replaceable> with
|
||||
<replaceable>$replacement</replaceable>.</para>
|
||||
<replaceable>$replacement</replaceable>.
|
||||
<footnote><para>Note that
|
||||
<replaceable>$substring</replaceable> and
|
||||
<replaceable>$replacement</replaceable> may refer to
|
||||
either <firstterm>literal strings</firstterm> or
|
||||
<firstterm>variables</firstterm>, depending on
|
||||
context. See the first usage example.</para></footnote>
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
@ -8569,6 +8592,21 @@ echo ${stringZ/abc/xyz} # xyzABC123ABCabc
|
|||
echo ${stringZ//abc/xyz} # xyzABC123ABCxyz
|
||||
# Replaces all matches of 'abc' with # 'xyz'.
|
||||
|
||||
echo ---------------
|
||||
echo "$stringZ" # abcABC123ABCabc
|
||||
echo ---------------
|
||||
# The string itself is not altered!
|
||||
|
||||
# Can the match and replacement strings be parameterized?
|
||||
match=abc
|
||||
repl=000
|
||||
echo ${stringZ/$match/$repl} # 000ABC123ABCabc
|
||||
# ^ ^ ^^^
|
||||
echo ${stringZ//$match/$repl} # 000ABC123ABC000
|
||||
# Yes! ^ ^ ^^^ ^^^
|
||||
|
||||
echo
|
||||
|
||||
# What happens if no $replacement string is supplied?
|
||||
echo ${stringZ/abc} # ABC123ABCabc
|
||||
echo ${stringZ//abc} # ABC123ABC
|
||||
|
@ -12036,9 +12074,16 @@ while read f; do
|
|||
<secondary>let</secondary>
|
||||
</indexterm>
|
||||
<listitem>
|
||||
<para>The <command>let</command> command carries out arithmetic
|
||||
operations on variables. In many cases, it functions as a less
|
||||
complex version of <link linkend="exprref">expr</link>.</para>
|
||||
<para>The <command>let</command> command carries out
|
||||
<firstterm>arithmetic</firstterm> operations on variables.
|
||||
|
||||
<footnote><para>Note that <firstterm>let</firstterm>
|
||||
<link linkend="letbad">cannot be used
|
||||
for setting <firstterm>string</firstterm>
|
||||
variables.</link></para></footnote>
|
||||
|
||||
In many cases, it functions as a less complex version
|
||||
of <link linkend="exprref">expr</link>.</para>
|
||||
|
||||
<example id="ex46">
|
||||
<title>Letting <firstterm>let</firstterm> do arithmetic.</title>
|
||||
|
@ -12167,7 +12212,8 @@ eval eval echo $a # d
|
|||
linkend="posparamref">positional parameters</link> that
|
||||
a script sees as the result of a command (<userinput>set
|
||||
`command`</userinput>). The script can then parse the
|
||||
fields of the command output.</para>
|
||||
<link linkend="fieldref">fields</link> of the command
|
||||
output.</para>
|
||||
|
||||
<example id="ex34">
|
||||
<title>Using <firstterm>set</firstterm> with positional
|
||||
|
@ -14997,8 +15043,9 @@ OneYearAgo=$(date --date='1 year ago')</programlisting></para>
|
|||
<secondary>awk</secondary>
|
||||
</indexterm>
|
||||
<listitem>
|
||||
<para>A tool for extracting fields from files. It is similar to the
|
||||
<userinput>print $N</userinput> command set in <link
|
||||
<para>A tool for extracting <link
|
||||
linkend="fieldref">fields</link> from files. It is similar
|
||||
to the <userinput>print $N</userinput> command set in <link
|
||||
linkend="awkref">awk</link>, but more limited. It may be
|
||||
simpler to use <firstterm>cut</firstterm> in a script than
|
||||
<firstterm>awk</firstterm>. Particularly important are the
|
||||
|
@ -15100,10 +15147,11 @@ done
|
|||
|
||||
<para>The <command>join</command> command operates on
|
||||
exactly two files, but pastes together only those lines
|
||||
with a common tagged field (usually a numerical label),
|
||||
and writes the result to <filename>stdout</filename>.
|
||||
The files to be joined should be sorted according to the
|
||||
tagged field for the matchups to work properly.</para>
|
||||
with a common tagged <link linkend="fieldref">field</link>
|
||||
(usually a numerical label), and writes the result to
|
||||
<filename>stdout</filename>. The files to be joined should
|
||||
be sorted according to the tagged field for the matchups
|
||||
to work properly.</para>
|
||||
|
||||
<para><programlisting>File: 1.data
|
||||
|
||||
|
@ -15558,8 +15606,9 @@ Here is some text.</programlisting>
|
|||
<term><command><link linkend="awkref">awk</link></command></term>
|
||||
<listitem>
|
||||
<para>Programmable file extractor and formatter, good for
|
||||
manipulating and/or extracting fields (columns) in
|
||||
structured text files. Its syntax is similar to C.</para>
|
||||
manipulating and/or extracting <link
|
||||
linkend="fieldref">fields</link> (columns) in structured
|
||||
text files. Its syntax is similar to C.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
@ -22823,7 +22872,8 @@ mount -o loop /dev/loop0 /mnt # Mount it.
|
|||
to <filename>/aaa/bbb</filename> as the base directory,
|
||||
rather than <filename class="directory">/</filename> as is
|
||||
normally the case. An <command>alias XX 'chroot /aaa/bbb
|
||||
ls'</command> in a user's <filename>~/.bashrc</filename>
|
||||
ls'</command> in a user's <link
|
||||
linkend="sample-bashrc"><filename>~/.bashrc</filename></link>
|
||||
effectively restricts which portion of the filesystem
|
||||
she may run command <quote>XX</quote> on.</para>
|
||||
|
||||
|
@ -22859,9 +22909,11 @@ mount -o loop /dev/loop0 /mnt # Mount it.
|
|||
<para>This utility is part of the <command>procmail</command>
|
||||
package (<ulink url="http://www.procmail.org">www.procmail.org</ulink>).
|
||||
It creates a <firstterm>lock file</firstterm>, a
|
||||
<firstterm>semaphore</firstterm>
|
||||
<firstterm>semaphore</firstterm> that controls access to
|
||||
a file, device, or resource.</para>
|
||||
|
||||
<footnote><para><anchor id="semaphoreref">Definition:
|
||||
<sidebar><para><anchor id="semaphoreref">
|
||||
<userinput>Definition:</userinput>
|
||||
A <firstterm>semaphore</firstterm> is a flag or
|
||||
signal. (The usage originated in railroading, where a
|
||||
colored flag, lantern, or striped movable arm
|
||||
|
@ -22869,13 +22921,13 @@ mount -o loop /dev/loop0 /mnt # Mount it.
|
|||
particular track was in use and therefore unavailable
|
||||
for another train.) A UNIX process can check the
|
||||
appropriate semaphore to determine whether a particular
|
||||
resource is available/accessible.</para></footnote>
|
||||
resource is available/accessible.</para></sidebar>
|
||||
|
||||
file that controls access to a file, device, or resource.
|
||||
The lock file serves as a flag that this particular
|
||||
file, device, or resource is in use by a process (it is
|
||||
<quote>busy</quote>), and this permits only restricted
|
||||
access (or no access) to other processes.</para>
|
||||
<para>The lock file serves as a flag that this particular
|
||||
file, device, or resource is in use by a process (and
|
||||
is therefore <quote>busy</quote>). The presence of a
|
||||
lock file permits only restricted access (or no access)
|
||||
to other processes.</para>
|
||||
|
||||
<para><programlisting>lockfile /home/bozo/lockfiles/$0.lock
|
||||
# Creates a write-protected lockfile prefixed with the name of the script.
|
||||
|
@ -22887,7 +22939,7 @@ lockfile /home/bozo/lockfiles/${0##*/}.lock
|
|||
system mail folders from simultaneously being changed
|
||||
by multiple users, indicating that a modem port
|
||||
is being accessed, and showing that an instance of
|
||||
<application>Netscape</application> is using its cache.
|
||||
<application>Firefox</application> is using its cache.
|
||||
Scripts may check for the existence of a lock file created
|
||||
by a certain process to check if that process is running.
|
||||
Note that if a script attempts to create a lock file that
|
||||
|
@ -24213,10 +24265,10 @@ echo a111b | gawk '/a1+b/'
|
|||
<userinput>0-9A-Fa-f</userinput>.</para>
|
||||
|
||||
<important>
|
||||
|
||||
<para>POSIX character classes generally require quoting
|
||||
or <link linkend="dblbrackets">double brackets</link>
|
||||
([[ ]]).</para>
|
||||
</important>
|
||||
|
||||
<para>
|
||||
<screen><prompt>bash$ </prompt><userinput>grep [[:digit:]] test.file</userinput>
|
||||
|
@ -24224,6 +24276,14 @@ echo a111b | gawk '/a1+b/'
|
|||
</screen>
|
||||
</para>
|
||||
|
||||
<para><programlisting># ...
|
||||
if [[ $arow =~ [[:digit:]] ]] # Numerical input?
|
||||
then # POSIX char class
|
||||
if [[ $acol =~ [[:alpha:]] ]] # Number followed by a letter? Illegal!
|
||||
# ...
|
||||
# From ktour.sh example script.</programlisting>
|
||||
</para>
|
||||
|
||||
<para>These character classes may even be used with <link
|
||||
linkend="globbingref">globbing</link>, to a limited
|
||||
extent.</para>
|
||||
|
@ -24234,10 +24294,9 @@ echo a111b | gawk '/a1+b/'
|
|||
</screen>
|
||||
</para>
|
||||
|
||||
<para>To see POSIX character classes used in scripts, refer to
|
||||
<para>POSIX character classes are used in
|
||||
<xref linkend="ex49"> and <xref linkend="lowercase">.</para>
|
||||
|
||||
</important>
|
||||
|
||||
</listitem>
|
||||
|
||||
|
@ -24297,7 +24356,8 @@ echo a111b | gawk '/a1+b/'
|
|||
<anchor id="wdotfilewc">There are important limitations on wild
|
||||
card characters in globbing, however. Strings containing
|
||||
<replaceable>*</replaceable> will not match filenames that
|
||||
start with a dot, as, for example, <filename>.bashrc</filename>.
|
||||
start with a dot, as, for example, <link
|
||||
linkend="sample-bashrc"><filename>.bashrc</filename></link>.
|
||||
|
||||
<footnote>
|
||||
<para>
|
||||
|
@ -25230,7 +25290,8 @@ echo "$nr files totaling $totalSize bytes"</programlisting>
|
|||
<firstterm>subshell</firstterm>.</para>
|
||||
|
||||
<sidebar>
|
||||
<para>Definition: A <firstterm>subshell</firstterm> is a
|
||||
<para><userinput>Definition:</userinput>
|
||||
A <firstterm>subshell</firstterm> is a
|
||||
<link linkend="childref2">child process</link> launched by a
|
||||
shell (or <firstterm>shell script</firstterm>).</para>
|
||||
</sidebar>
|
||||
|
@ -25334,7 +25395,7 @@ but is shown here for illustrative purposes.</programlisting>
|
|||
|
||||
<sidebar>
|
||||
<para><anchor id="scoperef"></para>
|
||||
<para><emphasis>Definition:</emphasis> The
|
||||
<para><userinput>Definition:</userinput> The
|
||||
<firstterm>scope</firstterm> of a variable is the
|
||||
context in which it has meaning, in which it has a
|
||||
<firstterm>value</firstterm> that can be referenced. For
|
||||
|
@ -26285,6 +26346,11 @@ Function () # This doesn't work.
|
|||
# Thanks, S.C.</programlisting>
|
||||
</para>
|
||||
|
||||
<note><para>Emmanuel Rouat's <link
|
||||
linkend="sample-bashrc">sample <filename>bashrc</filename>
|
||||
file</link> contains some instructive examples of
|
||||
functions.</para></note>
|
||||
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
@ -26483,7 +26549,7 @@ exit 0 # This script will not exit normally.
|
|||
more than a keyboard shortcut, an abbreviation, a means of
|
||||
avoiding typing a long command sequence. If, for example,
|
||||
we include <command>alias lm="ls -l | more"</command> in
|
||||
the <link linkend="filesref1"><filename>~/.bashrc</filename>
|
||||
the <link linkend="sample-bashrc"><filename>~/.bashrc</filename>
|
||||
file</link>, then each <userinput>lm</userinput>
|
||||
<footnote><para> ... as the first word of a command string.
|
||||
Obviously, an alias is only meaningful at the
|
||||
|
@ -28358,6 +28424,14 @@ fi # Aborts with an error message.
|
|||
</example>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><anchor id="letbad"></para>
|
||||
<para>Attempting to use <link linkend="letref">let</link>
|
||||
to set string variables.</para>
|
||||
<para><programlisting>let "a = hello, you"
|
||||
echo "$a" # 0</programlisting></para>
|
||||
</listitem>
|
||||
|
||||
|
||||
<listitem>
|
||||
<para><anchor id="failquote"></para>
|
||||
|
@ -28433,10 +28507,11 @@ fi
|
|||
|
||||
|
||||
<listitem>
|
||||
<para>Using Bash-specific functionality in a Bourne shell script
|
||||
<para>Using Bash-specific functionality in a <link
|
||||
linkend="bashdef">Bourne shell</link> script
|
||||
(<userinput>#!/bin/sh</userinput>) on a non-Linux machine
|
||||
<link linkend="binsh">may cause unexpected behavior</link>. A
|
||||
Linux system usually aliases <command>sh</command> to
|
||||
<link linkend="binsh">may cause unexpected behavior</link>.
|
||||
A Linux system usually aliases <command>sh</command> to
|
||||
<command>bash</command>, but this does not necessarily hold true
|
||||
for a generic UNIX machine.</para> </listitem>
|
||||
|
||||
|
@ -30444,8 +30519,8 @@ echo "User entered: "$answer""</programlisting>
|
|||
utilities has accelerated the trend.</para>
|
||||
|
||||
<para><anchor id="bashcompat"></para>
|
||||
<para>Bash has certain features that the traditional Bourne shell
|
||||
lacks. Among these are:
|
||||
<para>Bash has certain features that the traditional <link
|
||||
linkend="bashdef">Bourne shell</link> lacks. Among these are:
|
||||
|
||||
<itemizedlist>
|
||||
|
||||
|
@ -30888,7 +30963,8 @@ echo $a # 6</programlisting>
|
|||
<title>About the Author</title>
|
||||
<subtitle>Who is this guy anyhow?</subtitle>
|
||||
|
||||
<para>The author claims no credentials or special qualifications,
|
||||
<para><anchor id="nocreds">The author claims no credentials or
|
||||
special qualifications,
|
||||
<footnote><para>In fact, he is a school dropout
|
||||
and has no formal credentials or qualifications
|
||||
whatsoever.</para></footnote>
|
||||
|
@ -30896,7 +30972,7 @@ echo $a # 6</programlisting>
|
|||
<footnote><para>Those who can, do. Those who can't . . . get an
|
||||
MCSE.</para></footnote>
|
||||
This book is somewhat of a departure from his other major work,
|
||||
<ulink url="http://personal.riverusers.com/~thegrendel/hmw60.zip">
|
||||
<ulink url="http://bash.neuralshortcircuit.com/hmw60.zip">
|
||||
HOW-2 Meet Women: The Shy Man's Guide to
|
||||
Relationships</ulink>. He has also written the <ulink
|
||||
url="http://tldp.org/HOWTO/Software-Building-HOWTO.html">Software-Building
|
||||
|
@ -30914,7 +30990,7 @@ echo $a # 6</programlisting>
|
|||
Scrabble® adjudicator, the <ulink
|
||||
url="http://ibiblio.org/pub/Linux/libs/yawl-0.3.2.tar.gz">yawl</ulink>
|
||||
word gaming list package, and the <ulink
|
||||
url="http://personal.riverusers.com/~thegrendel/qky.README.html">Quacky</ulink>
|
||||
url="http://bash.neuralshortcircuit.com/qky.README.html">Quacky</ulink>
|
||||
anagramming gaming package. He got off to a rather shaky start in the
|
||||
computer game -- programming FORTRAN IV on a CDC 3800 --
|
||||
and is not the least bit nostalgic for those days.</para>
|
||||
|
@ -30934,7 +31010,7 @@ echo $a # 6</programlisting>
|
|||
<sect1 id="wherehelp">
|
||||
<title>Where to Go For Help</title>
|
||||
|
||||
<para><ulink url="mailto:thegrendel@theriver.com">The author</ulink>
|
||||
<para><ulink url="mailto:thegrendel.abs@gmail.com">The author</ulink>
|
||||
will sometimes, if not too busy (and in a good mood),
|
||||
answer general scripting questions.
|
||||
<footnote><para>E-mails from certain spam-infested TLDs
|
||||
|
@ -31130,6 +31206,7 @@ echo $a # 6</programlisting>
|
|||
<para>Andreas Abraham sent in a long list of typographical
|
||||
errors and other corrections. Special thanks!</para>
|
||||
|
||||
|
||||
<para>Others contributing scripts, making helpful suggestions, and
|
||||
pointing out errors were Gabor Kiss, Leopold Toetsch,
|
||||
Peter Tillier, Marcus Berglof, Tony Richardson, Nick Drage
|
||||
|
@ -31279,7 +31356,7 @@ echo $a # 6</programlisting>
|
|||
familiarity with <link linkend="sedref"><firstterm>sed</firstterm>
|
||||
and <firstterm>awk</firstterm></link>. This is the standard
|
||||
tutorial. It includes an excellent introduction to
|
||||
<quote>regular expressions.</quote> Recommended.</para>
|
||||
<firstterm>Regular Expressions</firstterm>. Recommended.</para>
|
||||
<para>*</para>
|
||||
</abstract>
|
||||
</biblioentry>
|
||||
|
@ -31315,9 +31392,10 @@ echo $a # 6</programlisting>
|
|||
<year>2002</year>
|
||||
</copyright>
|
||||
<isbn>0-596-00343-9</isbn>
|
||||
<abstract><para>This excellent sys admin manual has a decent introduction to shell
|
||||
scripting for sys administrators and does a thorough job of explaining the
|
||||
startup and initialization scripts.</para>
|
||||
<abstract><para>This excellent manual provides a decent introduction
|
||||
to shell scripting from a sys admin point of view. It includes
|
||||
comprehensive explanations of the startup and initialization
|
||||
scripts in a UNIX system.</para>
|
||||
<para>*</para>
|
||||
<para><anchor id="kochanref"></para>
|
||||
</abstract>
|
||||
|
@ -31779,6 +31857,14 @@ echo $a # 6</programlisting>
|
|||
</abstract>
|
||||
</biblioentry>
|
||||
|
||||
<biblioentry>
|
||||
<abstract>
|
||||
<para><ulink url="http://bashcookbook.com/bashinfo/">Examples</ulink>
|
||||
from the <citetitle pubwork="book">The Bash Scripting
|
||||
Cookbook</citetitle>, by Albing, Vossen, and Newham.</para>
|
||||
</abstract>
|
||||
</biblioentry>
|
||||
|
||||
<biblioentry>
|
||||
<abstract>
|
||||
<para>Example shell scripts at <ulink
|
||||
|
@ -32417,6 +32503,17 @@ echo $a # 6</programlisting>
|
|||
<programlisting>&homework;</programlisting>
|
||||
</example>
|
||||
|
||||
<para<anchor id="ktour0"></para>
|
||||
<example id="ktour">
|
||||
<title>The Knight's Tour</title>
|
||||
<programlisting>&ktour;</programlisting>
|
||||
</example>
|
||||
|
||||
<example id="msquare">
|
||||
<title>Magic Squares</title>
|
||||
<programlisting>&msquare;</programlisting>
|
||||
</example>
|
||||
|
||||
<example id="usegetopt">
|
||||
<title>An alternate version of the
|
||||
<link linkend="getoptsimple">getopt-simple.sh</link> script</title>
|
||||
|
@ -33454,7 +33551,8 @@ pattern=BEGIN
|
|||
a few of these here - the ones most useful in shell scripts.</para>
|
||||
|
||||
<para>Awk breaks each line of input passed to it into
|
||||
<firstterm>fields</firstterm>. By default, a field
|
||||
<anchor id="fieldref2">
|
||||
<link linkend="fieldref">fields</link>. By default, a field
|
||||
is a string of consecutive characters delimited by <link
|
||||
linkend="whitespaceref">whitespace</link>, though there are options
|
||||
for changing this. Awk parses and operates on each separate
|
||||
|
@ -35082,16 +35180,20 @@ var=$(history); echo "$var" # $var is empty.
|
|||
<para>
|
||||
<literallayout>
|
||||
On a dingy side street in a run-down section of Hoboken, New Jersey,
|
||||
there sits a nondescript squat two-story brick building
|
||||
with a inscription incised on a marble plate in its wall:
|
||||
there sits a nondescript squat two-story brick building with an inscription
|
||||
incised on a marble plate in its wall:
|
||||
|
||||
<computeroutput>Bash Scripting Hall of Fame</computeroutput>.
|
||||
|
||||
Inside, among various dusty uninteresting exhibits is a corroding,
|
||||
cobweb-festooned brass plaque inscribed with a short, very short
|
||||
list of those few persons who have successfully mastered the material
|
||||
in the <firstterm>Advanced Bash Scripting Guide</firstterm>,
|
||||
as evidenced by their performance on the following Exercise sections. . . .
|
||||
in the <firstterm>Advanced Bash Scripting Guide</firstterm>, as evidenced by their performance
|
||||
on the following Exercise sections.
|
||||
|
||||
(Alas, the author of the <firstterm>ABS Guide</firstterm> is not represented among the exhibits.
|
||||
This is possibly due to malicious rumors about <link linkend="nocreds">lack of credentials</link> and
|
||||
<link linkend="ktour0">deficient scripting skills</link>.)
|
||||
</literallayout>
|
||||
</para>
|
||||
|
||||
|
@ -35647,8 +35749,8 @@ do export SUM=$(($SUM + $(wc -l $f | awk '{ print $1 }'))); done; echo $SUM</pro
|
|||
with <firstterm>comma-separated values</firstterm>
|
||||
(CSVs). Other applications often need to parse these
|
||||
files.</para>
|
||||
<para>Given a data file with comma-separated fields,
|
||||
of the form:
|
||||
<para>Given a data file with comma-separated <link
|
||||
linkend="fieldref">fields</link>, of the form:
|
||||
<programlisting>Jones,Bill,235 S. Williams St.,Denver,CO,80221,(303) 244-7989
|
||||
Smith,Tom,404 Polk Ave.,Los Angeles,CA,90003,(213) 879-5612
|
||||
...</programlisting>
|
||||
|
@ -35990,13 +36092,13 @@ s c r i p t</programlisting></para>
|
|||
<listitem>
|
||||
<para>Do a hex(adecimal) dump on a binary file
|
||||
specified as an argument. The output should be in neat
|
||||
tabular fields, with the first field showing the address,
|
||||
each of the next 8 fields a 4-byte hex number, and the final
|
||||
field the ASCII equivalent of the previous 8 fields.</para>
|
||||
<para>The obvious followup to this is to extend the hex dump
|
||||
script into a disassembler. Using a lookup table, or some other
|
||||
clever gimmick, convert the hex values into 80x86 op
|
||||
codes.</para>
|
||||
tabular <link linkend="fieldref">fields</link>, with the
|
||||
first field showing the address, each of the next 8 fields a
|
||||
4-byte hex number, and the final field the ASCII equivalent
|
||||
of the previous 8 fields.</para> <para>The obvious
|
||||
followup to this is to extend the hex dump script into a
|
||||
disassembler. Using a lookup table, or some other clever
|
||||
gimmick, convert the hex values into 80x86 op codes.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
@ -36600,6 +36702,11 @@ thegrendel@theriver.com</programlisting></para>
|
|||
<entry>23 Nov 2008</entry>
|
||||
<entry>FARKLEBERRY release: Minor update.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><option>5.6</option></entry>
|
||||
<entry>26 Jan 2009</entry>
|
||||
<entry>WORCESTERBERRY release: Minor update.</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
@ -36608,34 +36715,43 @@ thegrendel@theriver.com</programlisting></para>
|
|||
</appendix> <!-- End Revision History appendix -->
|
||||
|
||||
<appendix id="mirrorsites">
|
||||
<title>Mirror Sites</title>
|
||||
<title>Download and Mirror Sites</title>
|
||||
|
||||
<para><ulink
|
||||
url="http://thegrendel.150m.com/abs-guide-5.5.tar.bz2">
|
||||
The latest update of this document</ulink>, as an archived
|
||||
<quote>tarball</quote>
|
||||
including both the SGML source and rendered HTML, may
|
||||
be downloaded from the <ulink
|
||||
url="http://personal.riverusers.com/~thegrendel/abs-guide-5.5.tar.bz2">author's
|
||||
home site</ulink>.</para>
|
||||
<para><anchor id="where_tarball"></para>
|
||||
|
||||
<para>The main mirror site for this document is the <ulink
|
||||
<para>The latest update of this document, as an archived,
|
||||
<link linkend="bzipref">bzip2-ed</link>
|
||||
<quote>tarball</quote> including both the SGML source
|
||||
and rendered HTML, may be downloaded from the <ulink
|
||||
url="http://bash.neuralshortcircuit.com/abs-guidelatest.tar.bz2">author's
|
||||
home site</ulink>).
|
||||
|
||||
A <ulink
|
||||
url="http://bash.neuralshortcircuit.com/abs-guide.pdf">
|
||||
pdf version</ulink> is also available.
|
||||
|
||||
The <ulink
|
||||
url="http://bash.neuralshortcircuit.com/Change.log">change
|
||||
log</ulink> gives a detailed revision history.
|
||||
The <emphasis>ABS Guide</emphasis> even has <ulink
|
||||
url="http://freshmeat.net/projects/advancedbashscriptingguide/">
|
||||
its own <filename>freshmeat.net</filename> page</ulink> to keep
|
||||
track of major updates, user comments, and popularity ratings
|
||||
for the project.</para>
|
||||
|
||||
<para>The main hosting site for this document is the <ulink
|
||||
url="http://www.tldp.org/LDP/abs/">Linux Documentation Project</ulink>,
|
||||
which maintains many other Guides and HOWTOs as well.</para>
|
||||
|
||||
|
||||
<para>Yet another mirror site for this document is
|
||||
<ulink url="http://www.morethan.org">morethan.org</ulink>.</para>
|
||||
|
||||
<para>You can download the <emphasis>pdf</emphasis> version
|
||||
<ulink
|
||||
url="http://personal.riverusers.com/~thegrendel/abs-guide.pdf">
|
||||
here</ulink>.</para>
|
||||
<para>Many thanks to Ronny Bangsund for donating <ulink
|
||||
url="http://bash.neuralshortcircuit.com/">server space</ulink> to host
|
||||
this project.</para>
|
||||
|
||||
|
||||
</appendix> <!-- Mirror Sites appendix -->
|
||||
|
||||
|
||||
|
||||
<appendix id="todolist">
|
||||
<title>To Do List</title>
|
||||
|
||||
|
@ -36643,7 +36759,8 @@ thegrendel@theriver.com</programlisting></para>
|
|||
<listitem>
|
||||
<para>A comprehensive survey of <link
|
||||
linkend="bashcompat">incompatibilities</link> between
|
||||
Bash and the classic Bourne shell.</para>
|
||||
Bash and the classic <link linkend="bashdef">Bourne
|
||||
shell</link>.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
|
@ -36778,7 +36895,7 @@ distributors, or any of its associated software or documentation.</programlistin
|
|||
|
||||
<para>The commercial print and other rights to this book are
|
||||
available. Please contact <ulink
|
||||
url="mailto:thegrendel@theriver.com">the author</ulink> if
|
||||
url="mailto:thegrendel.abs@gmail.com">the author</ulink> if
|
||||
interested.</para>
|
||||
|
||||
<para>The author produced this book in a manner consistent with the
|
||||
|
|
|
@ -16,7 +16,7 @@ grep -v 'ed$' # no past tense verbs
|
|||
# Uses "anagram" utility
|
||||
#+ that is part of the author's "yawl" word list package.
|
||||
# http://ibiblio.org/pub/Linux/libs/yawl-0.3.2.tar.gz
|
||||
# http://personal.riverusers.com/~thegrendel/yawl-0.3.2.tar.gz
|
||||
# http://bash.neuralshortcircuit.com/yawl-0.3.2.tar.gz
|
||||
|
||||
exit 0 # End of code.
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
# Uses "anagram" utility
|
||||
#+ that is part of the author's "yawl" word list package.
|
||||
# http://ibiblio.org/pub/Linux/libs/yawl-0.3.2.tar.gz
|
||||
# http://personal.riverusers.com/~thegrendel/yawl-0.3.2.tar.gz
|
||||
# http://bash.neuralshortcircuit.com/yawl-0.3.2.tar.gz
|
||||
|
||||
E_NOARGS=66
|
||||
E_BADARG=67
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
# ==> Used in ABS Guide with the script author's permission.
|
||||
# ==> Comments added by ABS Guide author.
|
||||
|
||||
NOARGS=65
|
||||
NOARGS=85
|
||||
PN=`basename "$0"` # Program name
|
||||
VER=`echo '$Revision$' | cut -d' ' -f2` # ==> VER=1.2
|
||||
|
||||
|
@ -31,10 +31,10 @@ A number may be
|
|||
hexadecimal (base 16) starting with 0x (i.e. 0xc)
|
||||
decimal otherwise (i.e. 12)" >&2
|
||||
exit $NOARGS
|
||||
} # ==> Function to print usage message.
|
||||
} # ==> Prints usage message.
|
||||
|
||||
Msg () {
|
||||
for i # ==> in [list] missing.
|
||||
for i # ==> in [list] missing. Why?
|
||||
do echo "$PN: $i" >&2
|
||||
done
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ PrintBases () {
|
|||
continue;;
|
||||
esac
|
||||
|
||||
# Remove prefix, convert hex digits to uppercase (bc needs this)
|
||||
# Remove prefix, convert hex digits to uppercase (bc needs this).
|
||||
number=`echo "$i" | sed -e 's:^0[bBxX]::' | tr '[a-f]' '[A-F]'`
|
||||
# ==> Uses ":" as sed separator, rather than "/".
|
||||
|
||||
|
@ -89,15 +89,15 @@ do
|
|||
--) shift; break;;
|
||||
-h) Usage;; # ==> Help message.
|
||||
-*) Usage;;
|
||||
*) break;; # first number
|
||||
esac # ==> More error checking for illegal input might be useful.
|
||||
*) break;; # First number
|
||||
esac # ==> Error checking for illegal input might be appropriate.
|
||||
shift
|
||||
done
|
||||
|
||||
if [ $# -gt 0 ]
|
||||
then
|
||||
PrintBases "$@"
|
||||
else # read from stdin
|
||||
else # Read from stdin.
|
||||
while read line
|
||||
do
|
||||
PrintBases $line
|
||||
|
@ -105,4 +105,4 @@ else # read from stdin
|
|||
fi
|
||||
|
||||
|
||||
exit 0
|
||||
exit
|
||||
|
|
|
@ -1,41 +1,47 @@
|
|||
#===============================================================
|
||||
#=============================================================
|
||||
#
|
||||
# PERSONAL $HOME/.bashrc FILE for bash-2.05a (or later)
|
||||
#
|
||||
# Last modified: Tue Apr 15 20:32:34 CEST 2003
|
||||
# PERSONAL $HOME/.bashrc FILE for bash-3.0 (or later)
|
||||
# By Emmanuel Rouat <no-email>
|
||||
#
|
||||
# Last modified: Sun Nov 30 16:27:45 CET 2008
|
||||
# This file is read (normally) by interactive shells only.
|
||||
# Here is the place to define your aliases, functions and
|
||||
# other interactive features like your prompt.
|
||||
#
|
||||
# This file was designed (originally) for Solaris but based
|
||||
# on Redhat's default .bashrc file
|
||||
# --> 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
|
||||
# just an example. Tailor it to your needs
|
||||
# The majority of the code here assumes you are on a GNU
|
||||
# system (most likely a Linux box) and is based on code found
|
||||
# on Usenet or internet. See for instance:
|
||||
#
|
||||
# http://tldp.org/LDP/abs/html/index.html
|
||||
# http://www.caliban.org/bash/
|
||||
# http://www.shelldorado.com/scripts/categories.html
|
||||
# http://www.dotfiles.org/
|
||||
#
|
||||
# This bashrc file is a bit overcrowded -- remember it is just
|
||||
# just an example. Tailor it to your needs.
|
||||
#
|
||||
#
|
||||
#===============================================================
|
||||
#=============================================================
|
||||
|
||||
# --> Comments added by HOWTO author.
|
||||
# --> And then edited again by ER :-)
|
||||
|
||||
#-----------------------------------
|
||||
|
||||
#-------------------------------------------------------------
|
||||
# Source global definitions (if any)
|
||||
#-----------------------------------
|
||||
#-------------------------------------------------------------
|
||||
|
||||
|
||||
if [ -f /etc/bashrc ]; then
|
||||
. /etc/bashrc # --> Read /etc/bashrc, if present.
|
||||
fi
|
||||
|
||||
#-------------------------------------------------------------
|
||||
# Automatic setting of $DISPLAY (if not set already)
|
||||
# This works for linux - your mileage may vary....
|
||||
# Automatic setting of $DISPLAY (if not set already).
|
||||
# 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
|
||||
# different answers to 'who am i' (rxvt in particular can be
|
||||
# troublesome).
|
||||
# I have not found a 'universal' method yet.
|
||||
#-------------------------------------------------------------
|
||||
|
||||
function get_xserver ()
|
||||
|
@ -51,60 +57,60 @@ function get_xserver ()
|
|||
XSERVER=${XSERVER%%:*}
|
||||
;;
|
||||
aterm | rxvt)
|
||||
# find some code that works here.....
|
||||
# Find some code that works here. ...
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
if [ -z ${DISPLAY:=""} ]; then
|
||||
get_xserver
|
||||
if [[ -z ${XSERVER} || ${XSERVER} == $(hostname) ||
|
||||
if [[ -z ${XSERVER} || ${XSERVER} == $(hostname) || \
|
||||
${XSERVER} == "unix" ]]; then
|
||||
DISPLAY=":0.0" # Display on local host
|
||||
DISPLAY=":0.0" # Display on local host.
|
||||
else
|
||||
DISPLAY=${XSERVER}:0.0 # Display on remote host
|
||||
DISPLAY=${XSERVER}:0.0 # Display on remote host.
|
||||
fi
|
||||
fi
|
||||
|
||||
export DISPLAY
|
||||
|
||||
#---------------
|
||||
#-------------------------------------------------------------
|
||||
# Some settings
|
||||
#---------------
|
||||
#-------------------------------------------------------------
|
||||
|
||||
ulimit -S -c 0 # Don't want any coredumps
|
||||
ulimit -S -c 0 # Don't want any coredumps.
|
||||
set -o notify
|
||||
set -o noclobber
|
||||
set -o ignoreeof
|
||||
set -o nounset
|
||||
#set -o xtrace # Useful for debuging
|
||||
#set -o xtrace # Useful for debuging.
|
||||
|
||||
# Enable options:
|
||||
shopt -s cdspell
|
||||
shopt -s cdable_vars
|
||||
shopt -s checkhash
|
||||
shopt -s checkwinsize
|
||||
shopt -s mailwarn
|
||||
shopt -s sourcepath
|
||||
shopt -s no_empty_cmd_completion # bash>=2.04 only
|
||||
shopt -s no_empty_cmd_completion
|
||||
shopt -s cmdhist
|
||||
shopt -s histappend histreedit histverify
|
||||
shopt -s extglob # Necessary for programmable completion
|
||||
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
|
||||
unset MAILCHECK # Don't want my shell to warn me of incoming mail.
|
||||
|
||||
|
||||
export TIMEFORMAT=$'\nreal %3R\tuser %3U\tsys %3S\tpcpu %P\n'
|
||||
export HISTTIMEFORMAT="%H:%M > "
|
||||
export HISTIGNORE="&:bg:fg:ll:h"
|
||||
export HOSTFILE=$HOME/.hosts # Put a list of remote hosts in ~/.hosts
|
||||
export HOSTFILE=$HOME/.hosts # Put list of remote hosts in ~/.hosts ...
|
||||
|
||||
|
||||
|
||||
#-----------------------
|
||||
#-------------------------------------------------------------
|
||||
# Greeting, motd etc...
|
||||
#-----------------------
|
||||
#-------------------------------------------------------------
|
||||
|
||||
# Define some colors first:
|
||||
red='\e[0;31m'
|
||||
|
@ -116,25 +122,28 @@ CYAN='\e[1;36m'
|
|||
NC='\e[0m' # No Color
|
||||
# --> Nice. Has the same effect as using "ansi.sys" in DOS.
|
||||
|
||||
# Looks best on a black background.....
|
||||
|
||||
# Looks best on a terminal with black background.....
|
||||
echo -e "${CYAN}This is BASH ${RED}${BASH_VERSION%.*}\
|
||||
${CYAN} - DISPLAY on ${RED}$DISPLAY${NC}\n"
|
||||
date
|
||||
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
|
||||
|
||||
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}"
|
||||
}
|
||||
trap _exit EXIT
|
||||
|
||||
#---------------
|
||||
# Shell Prompt
|
||||
#---------------
|
||||
|
||||
if [[ "${DISPLAY#$HOST}" != ":0.0" && "${DISPLAY}" != ":0" ]]; then
|
||||
#-------------------------------------------------------------
|
||||
# Shell Prompt
|
||||
#-------------------------------------------------------------
|
||||
|
||||
|
||||
if [[ "${DISPLAY%%:0*}" != "" ]]; then
|
||||
HILIT=${red} # remote machine: prompt will be partly red
|
||||
else
|
||||
HILIT=${cyan} # local machine: prompt will be partly cyan
|
||||
|
@ -156,36 +165,37 @@ function fastprompt()
|
|||
esac
|
||||
}
|
||||
|
||||
|
||||
_powerprompt()
|
||||
{
|
||||
LOAD=$(uptime|sed -e "s/.*: \([^,]*\).*/\1/" -e "s/ //g")
|
||||
}
|
||||
|
||||
function powerprompt()
|
||||
{
|
||||
_powerprompt()
|
||||
{
|
||||
LOAD=$(uptime|sed -e "s/.*: \([^,]*\).*/\1/" -e "s/ //g")
|
||||
}
|
||||
|
||||
PROMPT_COMMAND=_powerprompt
|
||||
case $TERM in
|
||||
*term | rxvt )
|
||||
PS1="${HILIT}[\A \$LOAD]$NC\n[\h \#] \W > \
|
||||
PS1="${HILIT}[\A - \$LOAD]$NC\n[\u@\h \#] \W > \
|
||||
\[\033]0;\${TERM} [\u@\h] \w\007\]" ;;
|
||||
linux )
|
||||
PS1="${HILIT}[\A - \$LOAD]$NC\n[\h \#] \w > " ;;
|
||||
PS1="${HILIT}[\A - \$LOAD]$NC\n[\u@\h \#] \W > " ;;
|
||||
* )
|
||||
PS1="[\A - \$LOAD]\n[\h \#] \w > " ;;
|
||||
PS1="[\A - \$LOAD]\n[\u@\h \#] \W > " ;;
|
||||
esac
|
||||
}
|
||||
|
||||
powerprompt # This is the default prompt -- might be slow.
|
||||
# If too slow, use fastprompt instead.
|
||||
# If too slow, use fastprompt instead. ...
|
||||
|
||||
#===============================================================
|
||||
#
|
||||
# ALIASES AND FUNCTIONS
|
||||
#
|
||||
# Arguably, some functions defined here are quite big
|
||||
# (ie 'lowercase') but my workstation has 512Meg of RAM, so ...
|
||||
# Arguably, some functions defined here are quite big.
|
||||
# If you want to make this file smaller, these functions can
|
||||
# be converted into scripts.
|
||||
# be converted into scripts and removed from here.
|
||||
#
|
||||
# Many functions were taken (almost) straight from the bash-2.04
|
||||
# examples.
|
||||
|
@ -204,52 +214,68 @@ alias mkdir='mkdir -p'
|
|||
|
||||
alias h='history'
|
||||
alias j='jobs -l'
|
||||
alias r='rlogin'
|
||||
alias which='type -all'
|
||||
alias which='type -a'
|
||||
alias ..='cd ..'
|
||||
alias path='echo -e ${PATH//:/\\n}'
|
||||
alias libpath='echo -e ${LD_LIBRARY_PATH//:/\\n}'
|
||||
alias print='/usr/bin/lp -o nobanner -d $LPDEST'
|
||||
# Assumes LPDEST is defined
|
||||
# Assumes LPDEST is defined (default printer)
|
||||
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 du='du -kh'
|
||||
|
||||
alias du='du -kh' # Makes a more readable output.
|
||||
alias df='df -kTh'
|
||||
|
||||
# The 'ls' family (this assumes you use the GNU ls)
|
||||
alias la='ls -Al' # show hidden files
|
||||
#-------------------------------------------------------------
|
||||
# The 'ls' family (this assumes you use a recent GNU ls)
|
||||
#-------------------------------------------------------------
|
||||
alias ll="ls -l --group-directories-first"
|
||||
alias ls='ls -hF --color' # add colors for filetype recognition
|
||||
alias la='ls -Al' # show hidden files
|
||||
alias lx='ls -lXB' # sort by extension
|
||||
alias lk='ls -lSr' # sort by size
|
||||
alias lc='ls -lcr' # sort by change time
|
||||
alias lu='ls -lur' # sort by access time
|
||||
alias lr='ls -lR' # recursive ls
|
||||
alias lt='ls -ltr' # sort by date
|
||||
alias lk='ls -lSr' # sort by size, biggest last
|
||||
alias lc='ls -ltcr' # sort by and show change time, most recent last
|
||||
alias lu='ls -ltur' # sort by and show access time, most recent last
|
||||
alias lt='ls -ltr' # sort by date, most recent last
|
||||
alias lm='ls -al |more' # pipe through 'more'
|
||||
alias tree='tree -Csu' # nice alternative to 'ls'
|
||||
alias lr='ls -lR' # recursive ls
|
||||
alias tree='tree -Csu' # nice alternative to 'recursive ls'
|
||||
|
||||
# If your version of 'ls' doesn't support --group-directories-first try this:
|
||||
# function ll(){ ls -l "$@"| egrep "^d" ; ls -lXB "$@" 2>&-| \
|
||||
# egrep -v "^d|total "; }
|
||||
|
||||
|
||||
#-------------------------------------------------------------
|
||||
# tailoring 'less'
|
||||
#-------------------------------------------------------------
|
||||
|
||||
alias more='less'
|
||||
export PAGER=less
|
||||
export LESSCHARSET='latin1'
|
||||
export LESSOPEN='|/usr/bin/lesspipe.sh %s 2>&-'
|
||||
# Use this if lesspipe.sh exists.
|
||||
# Use this if lesspipe.sh exists
|
||||
export LESS='-i -N -w -z-4 -g -e -M -X -F -R -P%t?f%f \
|
||||
:stdin .?pb%pb\%:?lbLine %lb:?bbByte %bb:-...'
|
||||
|
||||
# spelling typos - highly personnal :-)
|
||||
|
||||
#-------------------------------------------------------------
|
||||
# spelling typos - highly personnal and keyboard-dependent :-)
|
||||
#-------------------------------------------------------------
|
||||
|
||||
alias xs='cd'
|
||||
alias vf='cd'
|
||||
alias moer='more'
|
||||
alias moew='more'
|
||||
alias kk='ll'
|
||||
|
||||
#----------------
|
||||
# a few fun ones
|
||||
#----------------
|
||||
|
||||
function xtitle ()
|
||||
#-------------------------------------------------------------
|
||||
# A few fun ones
|
||||
#-------------------------------------------------------------
|
||||
|
||||
|
||||
function xtitle() # Adds some text in the terminal frame.
|
||||
{
|
||||
case "$TERM" in
|
||||
*term | rxvt)
|
||||
|
@ -259,13 +285,13 @@ function xtitle ()
|
|||
esac
|
||||
}
|
||||
|
||||
# aliases...
|
||||
# aliases that use xtitle
|
||||
alias top='xtitle Processes on $HOST && top'
|
||||
alias make='xtitle Making $(basename $PWD) ; make'
|
||||
alias ncftp="xtitle ncFTP ; ncftp"
|
||||
|
||||
# .. and functions
|
||||
function man ()
|
||||
function man()
|
||||
{
|
||||
for i ; do
|
||||
xtitle The $(basename $1|tr -d .[:digit:]) manual
|
||||
|
@ -273,10 +299,12 @@ function man ()
|
|||
done
|
||||
}
|
||||
|
||||
function ll()
|
||||
{ ls -l "$@"| egrep "^d" ; ls -lXB "$@" 2>&-| egrep -v "^d|total "; }
|
||||
|
||||
function te() # wrapper around xemacs/gnuserv
|
||||
#-------------------------------------------------------------
|
||||
# Make the following commands run in background automatically:
|
||||
#-------------------------------------------------------------
|
||||
|
||||
function te() # Wrapper around xemacs/gnuserv ...
|
||||
{
|
||||
if [ "$(gnuclient -batch -eval t 2>&-)" == "t" ]; then
|
||||
gnuclient -q "$@";
|
||||
|
@ -285,20 +313,25 @@ function te() # wrapper around xemacs/gnuserv
|
|||
fi
|
||||
}
|
||||
|
||||
#-----------------------------------
|
||||
# File & strings related functions:
|
||||
#-----------------------------------
|
||||
function soffice() { command soffice "$@" & }
|
||||
function firefox() { command firefox "$@" & }
|
||||
function xpdf() { command xpdf "$@" & }
|
||||
|
||||
|
||||
#-------------------------------------------------------------
|
||||
# File & string-related functions:
|
||||
#-------------------------------------------------------------
|
||||
|
||||
|
||||
# Find a file with a pattern in name:
|
||||
function ff()
|
||||
function ff() { find . -type f -iname '*'$*'*' -ls ; }
|
||||
|
||||
{ find . -type f -iname '*'$*'*' -ls ; }
|
||||
# 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:
|
||||
{ find . -type f -iname '*'${1:-}'*' -exec ${2:-file} {} \; ; }
|
||||
|
||||
# Find a pattern in a set of files and highlight them:
|
||||
# (needs a recent version of egrep)
|
||||
function fstr()
|
||||
{
|
||||
OPTIND=1
|
||||
|
@ -317,14 +350,12 @@ Usage: fstr [-i] \"pattern\" [\"filename pattern\"] "
|
|||
echo "$usage"
|
||||
return;
|
||||
fi
|
||||
local SMSO=$(tput smso)
|
||||
local RMSO=$(tput rmso)
|
||||
find . -type f -name "${2:-*}" -print0 |
|
||||
xargs -0 grep -sn ${case} "$1" 2>&- | \
|
||||
sed "s/$1/${SMSO}\0${RMSO}/gI" | more
|
||||
find . -type f -name "${2:-*}" -print0 | \
|
||||
xargs -0 egrep --color=always -sn ${case} "$1" 2>&- | more
|
||||
|
||||
}
|
||||
|
||||
function cuttail() # Cut last n lines in file, 10 by default.
|
||||
function cuttail() # cut last n lines in file, 10 by default
|
||||
{
|
||||
nlines=${2:-10}
|
||||
sed -n -e :a -e "1,${nlines}!{P;N;D;};N;ba" $1
|
||||
|
@ -349,30 +380,54 @@ function lowercase() # move filenames to lowercase
|
|||
done
|
||||
}
|
||||
|
||||
function swap() # swap 2 filenames around
|
||||
{
|
||||
|
||||
function swap() # Swap 2 filenames around, if they exist
|
||||
{ #(from Uzi's bashrc).
|
||||
local TMPFILE=tmp.$$
|
||||
|
||||
[ $# -ne 2 ] && echo "swap: 2 arguments needed" && return 1
|
||||
[ ! -e $1 ] && echo "swap: $1 does not exist" && return 1
|
||||
[ ! -e $2 ] && echo "swap: $2 does not exist" && return 1
|
||||
|
||||
mv "$1" $TMPFILE
|
||||
mv "$2" "$1"
|
||||
mv $TMPFILE "$2"
|
||||
}
|
||||
|
||||
|
||||
#-----------------------------------
|
||||
# Process/system related functions:
|
||||
#-----------------------------------
|
||||
|
||||
function my_ps()
|
||||
{ ps $@ -u $USER -o pid,%cpu,%mem,bsdtime,command ; }
|
||||
|
||||
function pp()
|
||||
{ my_ps f | awk '!/awk/ && $0~var' var=${1:-".*"} ; }
|
||||
|
||||
# This function is roughly the same as 'killall' on linux
|
||||
# but has no equivalent (that I know of) on Solaris
|
||||
function killps() # kill by process name
|
||||
function extract() # Handy Extract Program.
|
||||
{
|
||||
local pid pname sig="-TERM" # default signal
|
||||
if [ -f $1 ] ; then
|
||||
case $1 in
|
||||
*.tar.bz2) tar xvjf $1 ;;
|
||||
*.tar.gz) tar xvzf $1 ;;
|
||||
*.bz2) bunzip2 $1 ;;
|
||||
*.rar) unrar x $1 ;;
|
||||
*.gz) gunzip $1 ;;
|
||||
*.tar) tar xvf $1 ;;
|
||||
*.tbz2) tar xvjf $1 ;;
|
||||
*.tgz) tar xvzf $1 ;;
|
||||
*.zip) unzip $1 ;;
|
||||
*.Z) uncompress $1 ;;
|
||||
*.7z) 7z x $1 ;;
|
||||
*) echo "'$1' cannot be extracted via >extract<" ;;
|
||||
esac
|
||||
else
|
||||
echo "'$1' is not a valid file"
|
||||
fi
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------
|
||||
# Process/system related functions:
|
||||
#-------------------------------------------------------------
|
||||
|
||||
|
||||
function my_ps() { ps $@ -u $USER -o pid,%cpu,%mem,bsdtime,command ; }
|
||||
function pp() { my_ps f | awk '!/awk/ && $0~var' var=${1:-".*"} ; }
|
||||
|
||||
|
||||
function killps() # Kill by process name.
|
||||
{
|
||||
local pid pname sig="-TERM" # Default signal.
|
||||
if [ "$#" -lt 1 ] || [ "$#" -gt 2 ]; then
|
||||
echo "Usage: killps [-SIGNAL] pattern"
|
||||
return;
|
||||
|
@ -386,7 +441,7 @@ function killps() # kill by process name
|
|||
done
|
||||
}
|
||||
|
||||
function my_ip() # get IP adresses
|
||||
function my_ip() # Get IP adresses.
|
||||
{
|
||||
MY_IP=$(/sbin/ifconfig ppp0 | awk '/inet/ { print $2 } ' | \
|
||||
sed -e s/addr://)
|
||||
|
@ -394,7 +449,7 @@ sed -e s/addr://)
|
|||
sed -e s/P-t-P://)
|
||||
}
|
||||
|
||||
function ii() # get current host related info
|
||||
function ii() # Get current host related info.
|
||||
{
|
||||
echo -e "\nYou are logged on ${RED}$HOST"
|
||||
echo -e "\nAdditionnal information:$NC " ; uname -a
|
||||
|
@ -405,12 +460,15 @@ function ii() # get current host related info
|
|||
my_ip 2>&- ;
|
||||
echo -e "\n${RED}Local IP Address :$NC" ; echo ${MY_IP:-"Not connected"}
|
||||
echo -e "\n${RED}ISP Address :$NC" ; echo ${MY_ISP:-"Not connected"}
|
||||
echo -e "\n${RED}Open connections :$NC "; netstat -pan --inet;
|
||||
echo
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------
|
||||
# Misc utilities:
|
||||
#-------------------------------------------------------------
|
||||
|
||||
function repeat() # repeat n times command
|
||||
function repeat() # Repeat n times command.
|
||||
{
|
||||
local i max
|
||||
max=$1; shift;
|
||||
|
@ -419,7 +477,8 @@ function repeat() # repeat n times command
|
|||
done
|
||||
}
|
||||
|
||||
function ask()
|
||||
|
||||
function ask() # See 'killps' for example of use.
|
||||
{
|
||||
echo -n "$@" '[y/n] ' ; read ans
|
||||
case "$ans" in
|
||||
|
@ -428,24 +487,31 @@ function ask()
|
|||
esac
|
||||
}
|
||||
|
||||
#=======================================================================
|
||||
#
|
||||
# PROGRAMMABLE COMPLETION - ONLY SINCE BASH-2.04
|
||||
# Most are taken from the bash 2.05 documentation and from Ian McDonalds
|
||||
# 'Bash completion' package
|
||||
# (http://www.caliban.org/bash/index.shtml#completion)
|
||||
# You will in fact need bash-2.05a for some features
|
||||
#
|
||||
#=======================================================================
|
||||
function corename() # Get name of app that created a corefile.
|
||||
{
|
||||
for file ; do
|
||||
echo -n $file : ; gdb --core=$file --batch | head -1
|
||||
done
|
||||
}
|
||||
|
||||
if [ "${BASH_VERSION%.*}" \< "2.05" ]; then
|
||||
echo "You will need to upgrade to version 2.05 \
|
||||
for programmable completion"
|
||||
|
||||
|
||||
|
||||
#=========================================================================
|
||||
# PROGRAMMABLE COMPLETION - ONLY SINCE BASH-2.04
|
||||
# Most are taken from the bash 2.05 documentation and from Ian McDonald's
|
||||
# 'Bash completion' package (http://www.caliban.org/bash/#completion).
|
||||
# You will in fact need bash more recent than 3.0 for some features.
|
||||
#=========================================================================
|
||||
|
||||
if [ "${BASH_VERSION%.*}" \< "3.0" ]; then
|
||||
echo "You will need to upgrade to version 3.0 \
|
||||
for full programmable completion features."
|
||||
return
|
||||
fi
|
||||
|
||||
shopt -s extglob # necessary
|
||||
set +o nounset # otherwise some completions will fail
|
||||
shopt -s extglob # Necessary,
|
||||
#set +o nounset # otherwise some completions will fail.
|
||||
|
||||
complete -A hostname rsh rcp telnet rlogin r ftp ping disk
|
||||
complete -A export printenv
|
||||
|
@ -455,7 +521,7 @@ complete -A alias alias unalias
|
|||
complete -A function function
|
||||
complete -A user su mail finger
|
||||
|
||||
complete -A helptopic help # currently same as builtins
|
||||
complete -A helptopic help # Currently, same as builtins.
|
||||
complete -A shopt shopt
|
||||
complete -A stopped -P '%' bg
|
||||
complete -A job -P '%' fg jobs disown
|
||||
|
@ -472,36 +538,63 @@ 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 '!*.dvi' dvips dvipdf xdvi dviselect dvitype
|
||||
complete -f -o default -X '!*.pdf' acroread pdf2ps
|
||||
complete -f -o default -X '!*.+(pdf|ps)' gv
|
||||
complete -f -o default -X '!*.+(zip|ZIP|z|Z|gz|GZ|bz2|BZ2)' extract
|
||||
|
||||
|
||||
# Documents - Postscript,pdf,dvi.....
|
||||
complete -f -o default -X '!*.+(ps|PS)' gs ghostview ps2pdf ps2ascii
|
||||
complete -f -o default -X '!*.+(dvi|DVI)' dvips dvipdf xdvi dviselect dvitype
|
||||
complete -f -o default -X '!*.+(pdf|PDF)' acroread pdf2ps
|
||||
complete -f -o default -X \
|
||||
'!*.@(@(?(e)ps|?(E)PS|pdf|PDF)?(.gz|.GZ|.bz2|.BZ2|.Z))' gv ggv
|
||||
complete -f -o default -X '!*.texi*' makeinfo texi2dvi texi2html texi2pdf
|
||||
complete -f -o default -X '!*.tex' tex latex slitex
|
||||
complete -f -o default -X '!*.lyx' lyx
|
||||
complete -f -o default -X '!*.+(htm*|HTM*)' lynx html2ps
|
||||
complete -f -o default -X \
|
||||
'!*.+(doc|DOC|xls|XLS|ppt|PPT|sx?|SX?|csv|CSV|od?|OD?|ott|OTT)' soffice
|
||||
|
||||
# Multimedia
|
||||
complete -f -o default -X '!*.+(jp*g|gif|xpm|png|bmp)' xv gimp
|
||||
complete -f -o default -X \
|
||||
'!*.+(gif|GIF|jp*g|JP*G|bmp|BMP|xpm|XPM|png|PNG)' xv gimp ee gqview
|
||||
complete -f -o default -X '!*.+(mp3|MP3)' mpg123 mpg321
|
||||
complete -f -o default -X '!*.+(ogg|OGG)' ogg123
|
||||
complete -f -o default -X \
|
||||
'!*.@(mp[23]|MP[23]|ogg|OGG|wav|WAV|pls|m3u|xm|mod|s[3t]m|it|mtm|ult|flac)' xmms
|
||||
complete -f -o default -X \
|
||||
'!*.@(mp?(e)g|MP?(E)G|wma|avi|AVI|asf|vob|VOB|bin|dat|vcd|\
|
||||
ps|pes|fli|viv|rm|ram|yuv|mov|MOV|qt|QT|wmv|mp3|MP3|ogg|OGG|\
|
||||
ogm|OGM|mp4|MP4|wav|WAV|asx|ASX)' xine
|
||||
|
||||
|
||||
|
||||
complete -f -o default -X '!*.pl' perl perl5
|
||||
|
||||
|
||||
# This is a 'universal' completion function - it works when commands have
|
||||
# a so-called 'long options' mode , ie: 'ls --all' instead of 'ls -a'
|
||||
# Needs the '-o' option of grep
|
||||
# (try the commented-out version if not available).
|
||||
|
||||
_get_longopts ()
|
||||
# First, remove '=' from completion word separators
|
||||
# (this will allow completions like 'ls --color=auto' to work correctly).
|
||||
|
||||
COMP_WORDBREAKS=${COMP_WORDBREAKS/=/}
|
||||
|
||||
|
||||
_get_longopts()
|
||||
{
|
||||
$1 --help | sed -e '/--/!d' -e 's/.*--\([^[:space:].,]*\).*/--\1/'| \
|
||||
grep ^"$2" |sort -u ;
|
||||
#$1 --help | sed -e '/--/!d' -e 's/.*--\([^[:space:].,]*\).*/--\1/'| \
|
||||
#grep ^"$2" |sort -u ;
|
||||
$1 --help | grep -o -e "--[^[:space:].,]*" | grep -e "$2" |sort -u
|
||||
}
|
||||
|
||||
_longopts_func ()
|
||||
_longopts()
|
||||
{
|
||||
case "${2:-*}" in
|
||||
local cur
|
||||
cur=${COMP_WORDS[COMP_CWORD]}
|
||||
|
||||
case "${cur:-*}" in
|
||||
-*) ;;
|
||||
*) return ;;
|
||||
esac
|
||||
|
@ -510,86 +603,143 @@ _longopts_func ()
|
|||
\~*) eval cmd="$1" ;;
|
||||
*) cmd="$1" ;;
|
||||
esac
|
||||
COMPREPLY=( $(_get_longopts ${1} ${2} ) )
|
||||
COMPREPLY=( $(_get_longopts ${1} ${cur} ) )
|
||||
}
|
||||
complete -o default -F _longopts_func configure bash
|
||||
complete -o default -F _longopts_func wget id info a2ps ls recode
|
||||
complete -o default -F _longopts configure bash
|
||||
complete -o default -F _longopts wget id info a2ps ls recode
|
||||
|
||||
|
||||
_make_targets ()
|
||||
_tar()
|
||||
{
|
||||
local mdef makef gcmd cur prev i
|
||||
local cur ext regex tar untar
|
||||
|
||||
COMPREPLY=()
|
||||
cur=${COMP_WORDS[COMP_CWORD]}
|
||||
prev=${COMP_WORDS[COMP_CWORD-1]}
|
||||
|
||||
# if prev argument is -f, return possible filename completions.
|
||||
# we could be a little smarter here and return matches against
|
||||
# `makefile Makefile *.mk', whatever exists
|
||||
case "$prev" in
|
||||
-*f) COMPREPLY=( $(compgen -f $cur ) ); return 0;;
|
||||
esac
|
||||
|
||||
# if we want an option, return the possible posix options
|
||||
# If we want an option, return the possible long options.
|
||||
case "$cur" in
|
||||
-) COMPREPLY=(-e -f -i -k -n -p -q -r -S -s -t); return 0;;
|
||||
-*) COMPREPLY=( $(_get_longopts $1 $cur ) ); return 0;;
|
||||
esac
|
||||
|
||||
# make reads `makefile' before `Makefile'
|
||||
if [ -f makefile ]; then
|
||||
mdef=makefile
|
||||
elif [ -f Makefile ]; then
|
||||
mdef=Makefile
|
||||
else
|
||||
mdef=*.mk # local convention
|
||||
if [ $COMP_CWORD -eq 1 ]; then
|
||||
COMPREPLY=( $( compgen -W 'c t x u r d A' -- $cur ) )
|
||||
return 0
|
||||
fi
|
||||
|
||||
# before we scan for targets, see if a makefile name was specified
|
||||
# with -f
|
||||
case "${COMP_WORDS[1]}" in
|
||||
?(-)c*f)
|
||||
COMPREPLY=( $( compgen -f $cur ) )
|
||||
return 0
|
||||
;;
|
||||
+([^Izjy])f)
|
||||
ext='tar'
|
||||
regex=$ext
|
||||
;;
|
||||
*z*f)
|
||||
ext='tar.gz'
|
||||
regex='t\(ar\.\)\(gz\|Z\)'
|
||||
;;
|
||||
*[Ijy]*f)
|
||||
ext='t?(ar.)bz?(2)'
|
||||
regex='t\(ar\.\)bz2\?'
|
||||
;;
|
||||
*)
|
||||
COMPREPLY=( $( compgen -f $cur ) )
|
||||
return 0
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
if [[ "$COMP_LINE" == tar*.$ext' '* ]]; then
|
||||
# Complete on files in tar file.
|
||||
#
|
||||
# Get name of tar file from command line.
|
||||
tar=$( echo "$COMP_LINE" | \
|
||||
sed -e 's|^.* \([^ ]*'$regex'\) .*$|\1|' )
|
||||
# Devise how to untar and list it.
|
||||
untar=t${COMP_WORDS[1]//[^Izjyf]/}
|
||||
|
||||
COMPREPLY=( $( compgen -W "$( echo $( tar $untar $tar \
|
||||
2>/dev/null ) )" -- "$cur" ) )
|
||||
return 0
|
||||
|
||||
else
|
||||
# File completion on relevant files.
|
||||
COMPREPLY=( $( compgen -G $cur\*.$ext ) )
|
||||
|
||||
fi
|
||||
|
||||
return 0
|
||||
|
||||
}
|
||||
|
||||
complete -F _tar -o default tar
|
||||
|
||||
_make()
|
||||
{
|
||||
local mdef makef makef_dir="." makef_inc gcmd cur prev i;
|
||||
COMPREPLY=();
|
||||
cur=${COMP_WORDS[COMP_CWORD]};
|
||||
prev=${COMP_WORDS[COMP_CWORD-1]};
|
||||
case "$prev" in
|
||||
-*f)
|
||||
COMPREPLY=($(compgen -f $cur ));
|
||||
return 0
|
||||
;;
|
||||
esac;
|
||||
case "$cur" in
|
||||
-*)
|
||||
COMPREPLY=($(_get_longopts $1 $cur ));
|
||||
return 0
|
||||
;;
|
||||
esac;
|
||||
|
||||
# make reads `GNUmakefile', then `makefile', then `Makefile'
|
||||
if [ -f ${makef_dir}/GNUmakefile ]; then
|
||||
makef=${makef_dir}/GNUmakefile
|
||||
elif [ -f ${makef_dir}/makefile ]; then
|
||||
makef=${makef_dir}/makefile
|
||||
elif [ -f ${makef_dir}/Makefile ]; then
|
||||
makef=${makef_dir}/Makefile
|
||||
else
|
||||
makef=${makef_dir}/*.mk # Local convention.
|
||||
fi
|
||||
|
||||
|
||||
# Before we scan for targets, see if a Makefile name was
|
||||
# specified with -f ...
|
||||
for (( i=0; i < ${#COMP_WORDS[@]}; i++ )); do
|
||||
if [[ ${COMP_WORDS[i]} == -*f ]]; then
|
||||
eval makef=${COMP_WORDS[i+1]} # eval for tilde expansion
|
||||
if [[ ${COMP_WORDS[i]} == -f ]]; then
|
||||
# eval for tilde expansion
|
||||
eval makef=${COMP_WORDS[i+1]}
|
||||
break
|
||||
fi
|
||||
done
|
||||
[ ! -f $makef ] && return 0
|
||||
|
||||
[ -z "$makef" ] && makef=$mdef
|
||||
# deal with included Makefiles
|
||||
makef_inc=$( grep -E '^-?include' $makef | \
|
||||
sed -e "s,^.* ,"$makef_dir"/," )
|
||||
for file in $makef_inc; do
|
||||
[ -f $file ] && makef="$makef $file"
|
||||
done
|
||||
|
||||
# if we have a partial word to complete, restrict completions to
|
||||
# matches of that word
|
||||
if [ -n "$2" ]; then gcmd='grep "^$2"' ; else gcmd=cat ; fi
|
||||
|
||||
# if we don't want to use *.mk, we can take out the cat and use
|
||||
# test -f $makef and input redirection
|
||||
COMPREPLY=( $(cat $makef 2>/dev/null | \
|
||||
awk 'BEGIN {FS=":"} /^[^.# ][^=]*:/ {print $1}' \
|
||||
| tr -s ' ' '\012' | sort -u | eval $gcmd ) )
|
||||
# If we have a partial word to complete, restrict completions to
|
||||
# matches of that word.
|
||||
if [ -n "$cur" ]; then gcmd='grep "^$cur"' ; else gcmd=cat ; fi
|
||||
|
||||
COMPREPLY=( $( awk -F':' '/^[a-zA-Z0-9][^$#\/\t=]*:([^=]|$)/ \
|
||||
{split($1,A,/ /);for(i in A)print A[i]}' \
|
||||
$makef 2>/dev/null | eval $gcmd ))
|
||||
|
||||
}
|
||||
|
||||
complete -F _make_targets -X '+($*|*.[cho])' make gmake pmake
|
||||
complete -F _make -X '+($*|*.[cho])' make gmake pmake
|
||||
|
||||
|
||||
# cvs(1) completion
|
||||
_cvs ()
|
||||
{
|
||||
local cur prev
|
||||
COMPREPLY=()
|
||||
cur=${COMP_WORDS[COMP_CWORD]}
|
||||
prev=${COMP_WORDS[COMP_CWORD-1]}
|
||||
|
||||
if [ $COMP_CWORD -eq 1 ] || [ "${prev:0:1}" = "-" ]; then
|
||||
COMPREPLY=( $( compgen -W 'add admin checkout commit diff \
|
||||
export history import log rdiff release remove rtag status \
|
||||
tag update' $cur ))
|
||||
else
|
||||
COMPREPLY=( $( compgen -f $cur ))
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
complete -F _cvs cvs
|
||||
|
||||
_killall ()
|
||||
_killall()
|
||||
{
|
||||
local cur prev
|
||||
COMPREPLY=()
|
||||
|
@ -608,62 +758,57 @@ _killall ()
|
|||
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()
|
||||
# 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,
|
||||
# but still quite useful (By Ian McDonald, modified by me).
|
||||
|
||||
|
||||
_meta_comp()
|
||||
{
|
||||
local cur func cline cspec
|
||||
|
||||
COMPREPLY=()
|
||||
cur=${COMP_WORDS[COMP_CWORD]}
|
||||
|
||||
cmdline=${COMP_WORDS[@]}
|
||||
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 <function>
|
||||
#
|
||||
else
|
||||
cmd=${COMP_WORDS[1]} # Find command.
|
||||
cspec=$( complete -p ${cmd} ) # Find spec of that command.
|
||||
|
||||
# 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
|
||||
# completion routine:
|
||||
# Get current command line minus initial command,
|
||||
cline="${COMP_LINE#$1 }"
|
||||
# split current command line tokens into array,
|
||||
COMP_WORDS=( $cline )
|
||||
# set current token number to 1 less than now.
|
||||
COMP_CWORD=$(( $COMP_CWORD - 1 ))
|
||||
# get function name
|
||||
# If current arg is empty, add it to COMP_WORDS array
|
||||
# (otherwise that information will be lost).
|
||||
if [ -z $cur ]; then COMP_WORDS[COMP_CWORD]="" ; fi
|
||||
|
||||
if [ "${cspec%%-F *}" != "${cspec}" ]; then
|
||||
# if -F then get function:
|
||||
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/' )
|
||||
eval $func $cline # Evaluate it.
|
||||
else
|
||||
func=$( echo $cspec | sed -e 's/^complete//' -e 's/[^ ]*$//' )
|
||||
COMPREPLY=( $( eval compgen $func $cur ) )
|
||||
elif [ "${cspec#*-A}" != "$cspec" ]; then
|
||||
# complete -A <type>
|
||||
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
|
||||
complete -o default -F _meta_comp nohup \
|
||||
eval exec trace truss strace sotruss gdb
|
||||
complete -o default -F _meta_comp command type which man nice time
|
||||
|
||||
# Local Variables:
|
||||
# mode:shell-script
|
||||
|
|
|
@ -20,7 +20,7 @@ DICT=/usr/share/dict/word.lst
|
|||
#+ download the author's "yawl" word list package.
|
||||
# http://ibiblio.org/pub/Linux/libs/yawl-0.3.2.tar.gz
|
||||
# or
|
||||
# http://personal.riverusers.com/~thegrendel/yawl-0.3.2.tar.gz
|
||||
# http://bash.neuralshortcircuit.com/yawl-0.3.2.tar.gz
|
||||
|
||||
|
||||
if [ -z "$1" ] # If no word pattern specified
|
||||
|
|
|
@ -144,6 +144,12 @@ echo $diff
|
|||
|
||||
exit 0
|
||||
|
||||
# Exercise:
|
||||
# --------
|
||||
# If given only one command-line parameter, have the script
|
||||
#+ use today's date as the second.
|
||||
|
||||
|
||||
# Compare this script with
|
||||
#+ the implementation of Gauss' Formula in a C program at
|
||||
#+ http://buschencrew.hypermart.net/software/datedif
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
# empty-array.sh
|
||||
|
||||
# Thanks to Stephane Chazelas for the original example,
|
||||
#+ and to Michael Zick, Omair Eshkenazi, for extending it.
|
||||
#+ and to Michael Zick and Omair Eshkenazi, for extending it.
|
||||
# And to Nathan Coulter for clarifications and corrections.
|
||||
|
||||
|
||||
|
@ -117,9 +117,10 @@ echo "Elements in array8: ${array8[@]}"
|
|||
|
||||
# Michael Zick: Question, are those strings hard or soft quotes?
|
||||
# Nathan Coulter: There is no such thing as "soft quotes."
|
||||
# What's really happening is that
|
||||
#+ the pattern matching happens after all the other expansions of [word]
|
||||
#+ in cases like ${parameter#word}.
|
||||
#! What's really happening is that
|
||||
#!+ the pattern matching happens after
|
||||
#!+ all the other expansions of [word]
|
||||
#!+ in cases like ${parameter#word}.
|
||||
|
||||
|
||||
zap='new*'
|
||||
|
|
|
@ -1,8 +1,15 @@
|
|||
#!/bin/bash
|
||||
# Killing ppp to force a log-off.
|
||||
# For dialup connection, of course.
|
||||
|
||||
# Script should be run as root user.
|
||||
|
||||
SERPORT=ttyS3
|
||||
# Depending on the hardware and even the kernel version,
|
||||
#+ the modem port on your machine may be different --
|
||||
#+ /dev/ttyS1 or /dev/ttyS2.
|
||||
|
||||
|
||||
killppp="eval kill -9 `ps ax | awk '/ppp/ { print $1 }'`"
|
||||
# -------- process ID of ppp -------
|
||||
|
||||
|
@ -11,18 +18,13 @@ $killppp # This variable is now a command.
|
|||
|
||||
# The following operations must be done as root user.
|
||||
|
||||
chmod 666 /dev/ttyS3 # Restore read+write permissions, or else what?
|
||||
chmod 666 /dev/$SERPORT # Restore r+w permissions, or else what?
|
||||
# Since doing a SIGKILL on ppp changed the permissions on the serial port,
|
||||
#+ we restore permissions to previous state.
|
||||
|
||||
rm /var/lock/LCK..ttyS3 # Remove the serial port lock file. Why?
|
||||
rm /var/lock/LCK..$SERPORT # Remove the serial port lock file. Why?
|
||||
|
||||
# Note:
|
||||
# Depending on the hardware and even the kernel version,
|
||||
#+ the modem port on your machine may be different --
|
||||
#+ /dev/ttyS1 or /dev/ttyS2.
|
||||
|
||||
exit 0
|
||||
exit $?
|
||||
|
||||
# Exercises:
|
||||
# ---------
|
||||
|
|
|
@ -102,7 +102,7 @@ Optional environment variables
|
|||
Additional documentation
|
||||
Download the archived set of scripts
|
||||
explaining and illustrating the function contained within this script.
|
||||
http://personal.riverusers.com/mszick_clf.tar.bz2
|
||||
http://bash.neuralshortcircuit.com/mszick_clf.tar.bz2
|
||||
|
||||
|
||||
Study notes
|
||||
|
|
|
@ -0,0 +1,610 @@
|
|||
#!/bin/bash
|
||||
# ktour.sh
|
||||
|
||||
# author: mendel cooper
|
||||
# reldate: 12 Jan 2009
|
||||
# license: public domain
|
||||
# (Not much sense in GPLing something that's pretty much in the common
|
||||
#+ domain anyhow.)
|
||||
|
||||
###################################################################
|
||||
# The Knight's Tour, a classic problem. #
|
||||
# ===================================== #
|
||||
# The knight must move onto every square of the chess board, #
|
||||
# but cannot revisit any square he has already visited. #
|
||||
# #
|
||||
# And just why is Sir Knight unwelcome for a return visit? #
|
||||
# Could it be that he has a habit of partying into the wee hours #
|
||||
#+ of the morning? #
|
||||
# Possibly he leaves pizza crusts in the bed, empty beer bottles #
|
||||
#+ all over the floor, and clogs the plumbing. ... #
|
||||
# #
|
||||
# ------------------------------------------------------------- #
|
||||
# #
|
||||
# Usage: ktour.sh [start-square] [stupid] #
|
||||
# #
|
||||
# Note that start-square can be a square number #
|
||||
#+ in the range 0 - 63 ... or #
|
||||
# a square designator in conventional chess notation, #
|
||||
# such as a1, f5, h3, etc. #
|
||||
# #
|
||||
# If start-square-number not supplied, #
|
||||
#+ then starts on a random square somewhere on the board. #
|
||||
# #
|
||||
# "stupid" as second parameter sets the stupid strategy. #
|
||||
# #
|
||||
# Examples: #
|
||||
# ktour.sh 23 starts on square #23 (h3) #
|
||||
# ktour.sh g6 stupid starts on square #46, #
|
||||
# using "stupid" (non-Warnsdorff) strategy. #
|
||||
###################################################################
|
||||
|
||||
DEBUG= # Set this to echo debugging info to stdout.
|
||||
SUCCESS=0
|
||||
FAIL=99
|
||||
BADMOVE=-999
|
||||
FAILURE=1
|
||||
LINELEN=21 # How many moves to display per line.
|
||||
# ---------------------------------------- #
|
||||
# Board array params
|
||||
ROWS=8 # 8 x 8 board.
|
||||
COLS=8
|
||||
let "SQUARES = $ROWS * $COLS"
|
||||
let "MAX = $SQUARES - 1"
|
||||
MIN=0
|
||||
# 64 squares on board, indexed from 0 to 63.
|
||||
|
||||
VISITED=1
|
||||
UNVISITED=-1
|
||||
UNVSYM="##"
|
||||
# ---------------------------------------- #
|
||||
# Global variables.
|
||||
startpos= # Starting position (square #, 0 - 63).
|
||||
currpos= # Current position.
|
||||
movenum= # Move number.
|
||||
CRITPOS=37 # Have to patch for f5 starting position!
|
||||
|
||||
declare -i board
|
||||
# Use a one-dimensional array to simulate a two-dimensional one.
|
||||
# This can make life difficult and result in ugly kludges; see below.
|
||||
declare -i moves # Offsets from current knight position.
|
||||
|
||||
|
||||
initialize_board ()
|
||||
{
|
||||
local idx
|
||||
|
||||
for idx in {0..63}
|
||||
do
|
||||
board[$idx]=$UNVISITED
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
|
||||
print_board ()
|
||||
{
|
||||
local idx
|
||||
|
||||
echo " _____________________________________"
|
||||
for row in {7..0} # Reverse order of rows ...
|
||||
do #+ so it prints in chessboard order.
|
||||
let "rownum = $row + 1" # Start numbering rows at 1.
|
||||
echo -n "$rownum |" # Mark board edge with border and
|
||||
for column in {0..7} #+ "algebraic notation."
|
||||
do
|
||||
let "idx = $ROWS*$row + $column"
|
||||
if [ ${board[idx]} -eq $UNVISITED ]
|
||||
then
|
||||
echo -n "$UNVSYM " ##
|
||||
else # Mark square with move number.
|
||||
printf "%02d " "${board[idx]}"; echo -n " "
|
||||
fi
|
||||
done
|
||||
echo -e -n "\b\b\b|" # \b is a backspace.
|
||||
echo # -e enables echoing escaped chars.
|
||||
done
|
||||
|
||||
echo " -------------------------------------"
|
||||
echo " a b c d e f g h"
|
||||
}
|
||||
|
||||
|
||||
|
||||
failure()
|
||||
{ # Whine, then bail out.
|
||||
echo
|
||||
print_board
|
||||
echo
|
||||
echo " Waah!!! Ran out of squares to move to!"
|
||||
echo -n " Knight's Tour attempt ended"
|
||||
echo " on $(to_algebraic $currpos) [square #$currpos]"
|
||||
echo " after just $movenum moves!"
|
||||
echo
|
||||
exit $FAIL
|
||||
}
|
||||
|
||||
|
||||
|
||||
xlat_coords () # Translate x/y coordinates to board position
|
||||
{ #+ (board-array element #).
|
||||
# For user input of starting board position as x/y coords.
|
||||
# This function not used in initial release of ktour.sh.
|
||||
# May be used in an updated version, for compatibility with
|
||||
#+ standard implementation of the Knight's Tour in C, Python, etc.
|
||||
if [ -z "$1" -o -z "$2" ]
|
||||
then
|
||||
return $FAIL
|
||||
fi
|
||||
|
||||
local xc=$1
|
||||
local yc=$2
|
||||
|
||||
let "board_index = $xc * $ROWS + yc"
|
||||
|
||||
if [ $board_index -lt $MIN -o $board_index -gt $MAX ]
|
||||
then
|
||||
return $FAIL # Strayed off the board!
|
||||
else
|
||||
return $board_index
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
|
||||
to_algebraic () # Translate board position (board-array element #)
|
||||
{ #+ to standard algebraic notation used by chess players.
|
||||
if [ -z "$1" ]
|
||||
then
|
||||
return $FAIL
|
||||
fi
|
||||
|
||||
local element_no=$1 # Numerical board position.
|
||||
local col_arr=( a b c d e f g h )
|
||||
local row_arr=( 1 2 3 4 5 6 7 8 )
|
||||
|
||||
let "row_no = $element_no / $ROWS"
|
||||
let "col_no = $element_no % $ROWS"
|
||||
t1=${col_arr[col_no]}; t2=${row_arr[row_no]}
|
||||
local apos=$t1$t2 # Concatenate.
|
||||
echo $apos
|
||||
}
|
||||
|
||||
|
||||
|
||||
from_algebraic () # Translate standard algebraic chess notation
|
||||
{ #+ to numerical board position (board-array element #).
|
||||
# Or recognize numerical input & return it unchanged.
|
||||
if [ -z "$1" ]
|
||||
then
|
||||
return $FAIL
|
||||
fi # If no command-line arg, then will default to random start pos.
|
||||
|
||||
local ix
|
||||
local ix_count=0
|
||||
local b_index # Board index [0-63]
|
||||
local alpos="$1"
|
||||
|
||||
arow=${alpos:0:1} # position = 0, length = 1
|
||||
acol=${alpos:1:1}
|
||||
|
||||
if [[ $arow =~ [[:digit:]] ]] # Numerical input?
|
||||
then # POSIX char class
|
||||
if [[ $acol =~ [[:alpha:]] ]] # Number followed by a letter? Illegal!
|
||||
then return $FAIL
|
||||
else if [ $alpos -gt $MAX ] # Off board?
|
||||
then return $FAIL
|
||||
else return $alpos # Return digit(s) unchanged . . .
|
||||
fi #+ if within range.
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ $acol -eq $MIN || $acol -gt $ROWS ]]
|
||||
then # Outside of range 1 - 8?
|
||||
return $FAIL
|
||||
fi
|
||||
|
||||
for ix in a b c d e f g h
|
||||
do # Convert column letter to column number.
|
||||
if [ "$arow" = "$ix" ]
|
||||
then
|
||||
break
|
||||
fi
|
||||
((ix_count++)) # Find index count.
|
||||
done
|
||||
|
||||
((acol--)) # Decrementing converts to zero-based array.
|
||||
let "b_index = $ix_count + $acol * $ROWS"
|
||||
|
||||
if [ $b_index -gt $MAX ] # Off board?
|
||||
then
|
||||
return $FAIL
|
||||
fi
|
||||
|
||||
return $b_index
|
||||
|
||||
}
|
||||
|
||||
|
||||
generate_moves () # Calculate all valid knight moves,
|
||||
{ #+ relative to current position ($1),
|
||||
#+ and store in ${moves} array.
|
||||
local kt_hop=1 # One square :: short leg of knight move.
|
||||
local kt_skip=2 # Two squares :: long leg of knight move.
|
||||
local valmov=0 # Valid moves.
|
||||
local row_pos; let "row_pos = $1 % $COLS"
|
||||
|
||||
|
||||
let "move1 = -$kt_skip + $ROWS" # 2 sideways to-the-left, 1 up
|
||||
if [[ `expr $row_pos - $kt_skip` -lt $MIN ]] # An ugly, ugly kludge!
|
||||
then # Can't move off board.
|
||||
move1=$BADMOVE # Not even temporarily.
|
||||
else
|
||||
((valmov++))
|
||||
fi
|
||||
let "move2 = -$kt_hop + $kt_skip * $ROWS" # 1 sideways to-the-left, 2 up
|
||||
if [[ `expr $row_pos - $kt_hop` -lt $MIN ]] # Kludge continued ...
|
||||
then
|
||||
move2=$BADMOVE
|
||||
else
|
||||
((valmov++))
|
||||
fi
|
||||
let "move3 = $kt_hop + $kt_skip * $ROWS" # 1 sideways to-the-right, 2 up
|
||||
if [[ `expr $row_pos + $kt_hop` -ge $COLS ]]
|
||||
then
|
||||
move3=$BADMOVE
|
||||
else
|
||||
((valmov++))
|
||||
fi
|
||||
let "move4 = $kt_skip + $ROWS" # 2 sideways to-the-right, 1 up
|
||||
if [[ `expr $row_pos + $kt_skip` -ge $COLS ]]
|
||||
then
|
||||
move4=$BADMOVE
|
||||
else
|
||||
((valmov++))
|
||||
fi
|
||||
let "move5 = $kt_skip - $ROWS" # 2 sideways to-the-right, 1 dn
|
||||
if [[ `expr $row_pos + $kt_skip` -ge $COLS ]]
|
||||
then
|
||||
move5=$BADMOVE
|
||||
else
|
||||
((valmov++))
|
||||
fi
|
||||
let "move6 = $kt_hop - $kt_skip * $ROWS" # 1 sideways to-the-right, 2 dn
|
||||
if [[ `expr $row_pos + $kt_hop` -ge $COLS ]]
|
||||
then
|
||||
move6=$BADMOVE
|
||||
else
|
||||
((valmov++))
|
||||
fi
|
||||
let "move7 = -$kt_hop - $kt_skip * $ROWS" # 1 sideways to-the-left, 2 dn
|
||||
if [[ `expr $row_pos - $kt_hop` -lt $MIN ]]
|
||||
then
|
||||
move7=$BADMOVE
|
||||
else
|
||||
((valmov++))
|
||||
fi
|
||||
let "move8 = -$kt_skip - $ROWS" # 2 sideways to-the-left, 1 dn
|
||||
if [[ `expr $row_pos - $kt_skip` -lt $MIN ]]
|
||||
then
|
||||
move8=$BADMOVE
|
||||
else
|
||||
((valmov++))
|
||||
fi # There must be a better way to do this.
|
||||
|
||||
local m=( $valmov $move1 $move2 $move3 $move4 $move5 $move6 $move7 $move8 )
|
||||
# ${moves[0]} = number of valid moves.
|
||||
# ${moves[1]} ... ${moves[8]} = possible moves.
|
||||
echo "${m[*]}" # Elements of array to stdout for capture in a var.
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
is_on_board () # Is position actually on the board?
|
||||
{
|
||||
if [[ "$1" -lt "$MIN" || "$1" -gt "$MAX" ]]
|
||||
then
|
||||
return $FAILURE
|
||||
else
|
||||
return $SUCCESS
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
|
||||
do_move () # Move the knight!
|
||||
{
|
||||
local valid_moves=0
|
||||
local aapos
|
||||
currposl="$1"
|
||||
lmin=$ROWS
|
||||
iex=0
|
||||
squarel=
|
||||
mpm=
|
||||
mov=
|
||||
declare -a p_moves
|
||||
|
||||
########################## DECIDE-MOVE #############################
|
||||
if [ $startpos -ne $CRITPOS ]
|
||||
then # CRITPOS = square #37
|
||||
decide_move
|
||||
else # Needs a special patch for startpos=37 !!!
|
||||
decide_move_patched # Why this particular move and no other ???
|
||||
fi
|
||||
####################################################################
|
||||
|
||||
(( ++movenum )) # Increment move count.
|
||||
let "square = $currposl + ${moves[iex]}"
|
||||
|
||||
################## DEBUG ###############
|
||||
if [ "$DEBUG" ]
|
||||
then debug # Echo debugging information.
|
||||
fi
|
||||
##############################################
|
||||
|
||||
if [[ "$square" -gt $MAX || "$square" -lt $MIN ||
|
||||
${board[square]} -ne $UNVISITED ]]
|
||||
then
|
||||
(( --movenum )) # Decrement move count,
|
||||
echo "RAN OUT OF SQUARES!!!" #+ since previous one was invalid.
|
||||
return $FAIL
|
||||
fi
|
||||
|
||||
board[square]=$movenum
|
||||
currpos=$square # Update current position.
|
||||
((valid_moves++)); # moves[0]=$valid_moves
|
||||
aapos=$(to_algebraic $square)
|
||||
echo -n "$aapos "
|
||||
test $(( $Moves % $LINELEN )) -eq 0 && echo
|
||||
# Print LINELEN=21 moves per line. A valid tour shows 3 complete lines.
|
||||
return $valid_moves # Found a square to move to!
|
||||
}
|
||||
|
||||
|
||||
|
||||
do_move_stupid() # Dingbat algorithm,
|
||||
{ #+ courtesy of script author, *not* Warnsdorff.
|
||||
local valid_moves=0
|
||||
local movloc
|
||||
local squareloc
|
||||
local aapos
|
||||
local cposloc="$1"
|
||||
|
||||
for movloc in {1..8}
|
||||
do # Move to first-found unvisited square.
|
||||
let "squareloc = $cposloc + ${moves[movloc]}"
|
||||
is_on_board $squareloc
|
||||
if [ $? -eq $SUCCESS ] && [ ${board[squareloc]} -eq $UNVISITED ]
|
||||
then # Add conditions to above if-test to improve algorithm.
|
||||
(( ++movenum ))
|
||||
board[squareloc]=$movenum
|
||||
currpos=$squareloc # Update current position.
|
||||
((valid_moves++)); # moves[0]=$valid_moves
|
||||
aapos=$(to_algebraic $squareloc)
|
||||
echo -n "$aapos "
|
||||
test $(( $Moves % $LINELEN )) -eq 0 && echo # Print 21 moves/line.
|
||||
return $valid_moves # Found a square to move to!
|
||||
fi
|
||||
done
|
||||
|
||||
return $FAIL
|
||||
# If no square found in all 8 loop iterations,
|
||||
#+ then Knight's Tour attempt ends in failure.
|
||||
|
||||
# Dingbat algorithm will typically fail after about 30 - 40 moves,
|
||||
#+ but executes _much_ faster than Warnsdorff's in do_move() function.
|
||||
}
|
||||
|
||||
|
||||
|
||||
decide_move () # Which move will we make?
|
||||
{ # But, fails on startpos=37 !!!
|
||||
for mov in {1..8}
|
||||
do
|
||||
let "squarel = $currposl + ${moves[mov]}"
|
||||
is_on_board $squarel
|
||||
if [[ $? -eq $SUCCESS && ${board[squarel]} -eq $UNVISITED ]]
|
||||
then # Find accessible square with least possible future moves.
|
||||
# This is Warnsdorff's algorithm.
|
||||
# What happens is that the knight wanders toward the outer edge
|
||||
#+ of the board, then pretty much spirals inward.
|
||||
# Given two or more possible moves with same value of
|
||||
#+ least-possible-future-moves, this implementation chooses
|
||||
#+ the _first_ of those moves.
|
||||
# This means that there is not necessarily a unique solution
|
||||
#+ for any given starting position.
|
||||
|
||||
possible_moves $squarel
|
||||
mpm=$?
|
||||
p_moves[mov]=$mpm
|
||||
|
||||
if [ $mpm -lt $lmin ] # If less than previous minimum ...
|
||||
then # ^^
|
||||
lmin=$mpm # Update minimum.
|
||||
iex=$mov # Save index.
|
||||
fi
|
||||
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
|
||||
decide_move_patched () # Decide which move to make,
|
||||
{ # ^^^^^^^ #+ but only if startpos=37 !!!
|
||||
for mov in {1..8}
|
||||
do
|
||||
let "squarel = $currposl + ${moves[mov]}"
|
||||
is_on_board $squarel
|
||||
if [[ $? -eq $SUCCESS && ${board[squarel]} -eq $UNVISITED ]]
|
||||
then
|
||||
possible_moves $squarel
|
||||
mpm=$?
|
||||
p_moves[mov]=$mpm
|
||||
|
||||
if [ $mpm -le $lmin ] # If less-than-or equal to prev. minimum!
|
||||
then # ^^
|
||||
lmin=$mpm
|
||||
iex=$mov
|
||||
fi
|
||||
|
||||
fi
|
||||
done # There has to be a better way to do this.
|
||||
}
|
||||
|
||||
|
||||
|
||||
possible_moves () # Calculate number of possible moves,
|
||||
{ #+ given the current position.
|
||||
|
||||
if [ -z "$1" ]
|
||||
then
|
||||
return $FAIL
|
||||
fi
|
||||
|
||||
local curr_pos=$1
|
||||
local valid_movl=0
|
||||
local icx=0
|
||||
local movl
|
||||
local sq
|
||||
declare -a movesloc
|
||||
|
||||
movesloc=( $(generate_moves $curr_pos) )
|
||||
|
||||
for movl in {1..8}
|
||||
do
|
||||
let "sq = $curr_pos + ${movesloc[movl]}"
|
||||
is_on_board $sq
|
||||
if [ $? -eq $SUCCESS ] && [ ${board[sq]} -eq $UNVISITED ]
|
||||
then
|
||||
((valid_movl++));
|
||||
fi
|
||||
done
|
||||
|
||||
return $valid_movl # Found a square to move to!
|
||||
}
|
||||
|
||||
|
||||
strategy ()
|
||||
{
|
||||
echo
|
||||
|
||||
if [ -n "$STUPID" ]
|
||||
then
|
||||
for Moves in {1..63}
|
||||
do
|
||||
cposl=$1
|
||||
moves=( $(generate_moves $currpos) )
|
||||
do_move_stupid "$currpos"
|
||||
if [ $? -eq $FAIL ]
|
||||
then
|
||||
failure
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# Don't need an "else" clause here,
|
||||
#+ because Stupid Strategy will always fail and exit!
|
||||
for Moves in {1..63}
|
||||
do
|
||||
cposl=$1
|
||||
moves=( $(generate_moves $currpos) )
|
||||
do_move "$currpos"
|
||||
if [ $? -eq $FAIL ]
|
||||
then
|
||||
failure
|
||||
fi
|
||||
|
||||
done
|
||||
# Could have condensed above two do-loops into a single one,
|
||||
echo #+ but this would have slowed execution.
|
||||
|
||||
print_board
|
||||
echo
|
||||
echo "Knight's Tour ends on $(to_algebraic $currpos) [square #$currpos]."
|
||||
return $SUCCESS
|
||||
}
|
||||
|
||||
debug ()
|
||||
{ # Enable this by setting DEBUG=1 near beginning of script.
|
||||
local n
|
||||
|
||||
echo "================================="
|
||||
echo " At move number $movenum:"
|
||||
echo " *** possible moves = $mpm ***"
|
||||
# echo "### square = $square ###"
|
||||
echo "lmin = $lmin"
|
||||
echo "${moves[@]}"
|
||||
|
||||
for n in {1..8}
|
||||
do
|
||||
echo -n "($n):${p_moves[n]} "
|
||||
done
|
||||
|
||||
echo
|
||||
echo "iex = $iex :: moves[iex] = ${moves[iex]}"
|
||||
echo "square = $square"
|
||||
echo "================================="
|
||||
echo
|
||||
} # Gives pretty complete status after ea. move.
|
||||
|
||||
|
||||
|
||||
# =============================================================== #
|
||||
# int main () {
|
||||
from_algebraic "$1"
|
||||
startpos=$?
|
||||
if [ "$startpos" -eq "$FAIL" ] # Okay even if no $1.
|
||||
then # ^^^^^^^^^^^ Okay even if input -lt 0.
|
||||
echo "No starting square specified (or illegal input)."
|
||||
let "startpos = $RANDOM % $SQUARES" # 0 - 63 permissable range.
|
||||
fi
|
||||
|
||||
|
||||
if [ "$2" = "stupid" ]
|
||||
then
|
||||
STUPID=1
|
||||
echo -n " ### Stupid Strategy ###"
|
||||
else
|
||||
STUPID=''
|
||||
echo -n " *** Warnsdorff's Algorithm ***"
|
||||
fi
|
||||
|
||||
|
||||
initialize_board
|
||||
|
||||
movenum=0
|
||||
board[startpos]=$movenum # Mark each board square with move number.
|
||||
currpos=$startpos
|
||||
algpos=$(to_algebraic $startpos)
|
||||
|
||||
echo; echo "Starting from $algpos [square #$startpos] ..."; echo
|
||||
echo -n "Moves:"
|
||||
|
||||
strategy "$currpos"
|
||||
|
||||
echo
|
||||
|
||||
exit 0 # return 0;
|
||||
|
||||
# } # End of main() pseudo-function.
|
||||
# =============================================================== #
|
||||
|
||||
|
||||
# Exercises:
|
||||
# ---------
|
||||
#
|
||||
# 1) Extend this example to a 10 x 10 board or larger.
|
||||
# 2) Improve the "stupid strategy" by modifying the
|
||||
# do_move_stupid function.
|
||||
# Hint: Prevent straying into corner squares in early moves
|
||||
# (the exact opposite of Warnsdorff's algorithm!).
|
||||
# 3) This script could stand considerable improvement and
|
||||
# streamlining, especially in the poorly-written
|
||||
# generate_moves() function
|
||||
# and in the DECIDE-MOVE patch in the do_move() function.
|
||||
# Must figure out why standard algorithm fails for startpos=37 ...
|
||||
#+ but _not_ on any other, including symmetrical startpos=26.
|
||||
# Possibly, when calculating possible moves, counts the move back
|
||||
#+ to the originating square. If so, it might be a relatively easy fix.
|
|
@ -42,7 +42,7 @@ fi
|
|||
#+ and
|
||||
#+ default file "gen0" not present.
|
||||
|
||||
E_NOSTARTFILE=68
|
||||
E_NOSTARTFILE=86
|
||||
|
||||
if [ ! -e "$startfile" ]
|
||||
then
|
||||
|
@ -65,7 +65,7 @@ COLS=10
|
|||
# ---------------------------------------------------------- #
|
||||
|
||||
GENERATIONS=10 # How many generations to cycle through.
|
||||
# Adjust this upwards,
|
||||
# Adjust this upwards
|
||||
#+ if you have time on your hands.
|
||||
|
||||
NONE_ALIVE=85 # Exit status on premature bailout,
|
||||
|
@ -120,7 +120,7 @@ do
|
|||
fi
|
||||
|
||||
echo -n "$cell" | sed -e 's/_/ /g'
|
||||
# Print out array and change underscores to spaces.
|
||||
# Print out array, changing underscores to spaces.
|
||||
done
|
||||
|
||||
return
|
||||
|
@ -164,7 +164,7 @@ return $TRUE # Valid coordinate.
|
|||
|
||||
|
||||
IsAlive () # Test whether cell is alive.
|
||||
# Takes array, cell number,
|
||||
# Takes array, cell number, and
|
||||
{ #+ state of cell as arguments.
|
||||
GetCount "$1" $2 # Get alive cell count in neighborhood.
|
||||
local nhbd=$?
|
||||
|
@ -179,7 +179,7 @@ IsAlive () # Test whether cell is alive.
|
|||
return $ALIVE
|
||||
fi
|
||||
|
||||
return $DEAD # Dead by default.
|
||||
return $DEAD # Dead, by default.
|
||||
|
||||
}
|
||||
|
||||
|
@ -222,7 +222,7 @@ GetCount () # Count live cells in passed cell's neighborhood.
|
|||
if [ $? -eq "$TRUE" ]
|
||||
then
|
||||
if [ ${array[$t_cen]} = "$ALIVE1" ] # Is it alive?
|
||||
then # Yes?
|
||||
then # If yes, then ...
|
||||
let "count += 1" # Increment count.
|
||||
fi
|
||||
fi
|
||||
|
@ -294,7 +294,7 @@ echo "Generation $generation - $alive alive"
|
|||
if [ "$alive" -eq 0 ]
|
||||
then
|
||||
echo
|
||||
echo "Unexpected exit: no more cells alive!"
|
||||
echo "Premature exit: no more cells alive!"
|
||||
exit $NONE_ALIVE # No point in continuing
|
||||
fi #+ if no live cells.
|
||||
|
||||
|
@ -307,8 +307,8 @@ fi #+ if no live cells.
|
|||
|
||||
# Load initial array with contents of startup file.
|
||||
initial=( `cat "$startfile" | sed -e '/#/d' | tr -d '\n' |\
|
||||
sed -e 's/\./\. /g' -e 's/_/_ /g'` )
|
||||
# Delete lines containing '#' comment character.
|
||||
sed -e 's/\./\. /g' -e 's/_/_ /g'` )
|
||||
# Remove linefeeds and insert space between elements.
|
||||
|
||||
clear # Clear screen.
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# A rudimentary man page editor
|
||||
|
||||
# Version: 0.1 (Alpha, probably buggy)
|
||||
# Author: Mendel Cooper <thegrendel@theriver.com>
|
||||
# Author: Mendel Cooper <thegrendel.abs@gmail.com>
|
||||
# Reldate: 16 June 2008
|
||||
# License: GPL3
|
||||
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
#!/bin/bash
|
||||
# msquare.sh
|
||||
# Magic Square generator (odd-order squares only!)
|
||||
|
||||
# Author: mendel cooper
|
||||
# reldate: 19 Jan. 2009
|
||||
# License: Public Domain
|
||||
# A C-program by Kwon Young Shin inspired this script.
|
||||
# See http://user.chollian.net/~brainstm/MagicSquare.htm ...
|
||||
|
||||
# Definition: A "magic square" is a two-dimensional array
|
||||
# of integers in which all the rows, columns,
|
||||
# and *long* diagonals add up to the same number.
|
||||
# Being "square," the array has the same number
|
||||
# of rows and columns.
|
||||
# An example of a magic square of order 3 is:
|
||||
# 8 1 6
|
||||
# 3 5 7
|
||||
# 4 9 2
|
||||
# All the rows, columns, and long diagonals add up to 15.
|
||||
|
||||
|
||||
# Globals
|
||||
EVEN=2
|
||||
MAXSIZE=31 # 31 rows x 31 cols.
|
||||
E_usage=90 # Invocation error.
|
||||
dimension=
|
||||
declare -i square
|
||||
|
||||
usage_message ()
|
||||
{
|
||||
echo "Usage: $0 square-size"
|
||||
echo " ... where \"square-size\" is an ODD integer"
|
||||
echo " in the range 3 - 31."
|
||||
# Actually works for squares up to order 159,
|
||||
#+ but large squares will not display pretty-printed in a term window.
|
||||
# Try increasing MAXSIZE, above.
|
||||
exit $E_usage
|
||||
}
|
||||
|
||||
|
||||
calculate () # Here's where the actual work gets done.
|
||||
{
|
||||
local row col index dimadj j k cell_val=1
|
||||
dimension=$1
|
||||
|
||||
let "dimadj = $dimension * 3"; let "dimadj /= 2" # x 1.5, then truncate.
|
||||
|
||||
for ((j=0; j < dimension; j++))
|
||||
do
|
||||
for ((k=0; k < dimension; k++))
|
||||
do # Calculate indices, then convert to 1-dim. array index.
|
||||
# Bash doesn't support multidimensional arrays. Pity.
|
||||
let "col = $k - $j + $dimadj"; let "col %= $dimension"
|
||||
let "row = $j * 2 - $k + $dimension"; let "row %= $dimension"
|
||||
let "index = $row*($dimension) + $col"
|
||||
square[$index]=cell_val; ((cell_val++))
|
||||
done
|
||||
done
|
||||
} # Plain math, no visualization required.
|
||||
|
||||
|
||||
print_square () # Output square, one row at a time.
|
||||
{
|
||||
local row col idx d1
|
||||
let "d1 = $dimension - 1" # Adjust for zero-indexed array.
|
||||
|
||||
for row in $(seq 0 $d1)
|
||||
do
|
||||
|
||||
for col in $(seq 0 $d1)
|
||||
do
|
||||
let "idx = $row * $dimension + $col"
|
||||
printf "%3d " "${square[idx]}"; echo -n " "
|
||||
done # Displays up to 13-order neatly in 80-column term window.
|
||||
|
||||
echo # Newline after each row.
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
#################################################
|
||||
if [[ -z "$1" ]] || [[ "$1" -gt $MAXSIZE ]]
|
||||
then
|
||||
usage_message
|
||||
fi
|
||||
|
||||
let "test_even = $1 % $EVEN"
|
||||
if [ $test_even -eq 0 ]
|
||||
then # Can't handle even-order squares.
|
||||
usage_message
|
||||
fi
|
||||
|
||||
calculate $1
|
||||
print_square # echo "${square[@]}" # DEBUG
|
||||
|
||||
exit $?
|
||||
#################################################
|
||||
|
||||
|
||||
# Exercises:
|
||||
# ---------
|
||||
# 1) Add a function to calculate the sum of each row, column,
|
||||
# and *long* diagonal. The sums must match.
|
||||
# This is the "magic constant" of that particular order square.
|
||||
# 2) Have the print_square function auto-calculate how much space
|
||||
# to allot between square elements for optimized display.
|
||||
# This might require parameterizing the "printf" line.
|
||||
# 3) Add appropriate functions for generating magic squares
|
||||
# with an *even* number of rows/columns.
|
||||
# This is non-trivial(!).
|
||||
# See the URL for Kwon Young Shin, above, for help.
|
|
@ -15,13 +15,11 @@ volume=$'\xc0' # Max volume = \xff (or \x00).
|
|||
mute=$'\x80' # No volume = \x80 (the middle).
|
||||
|
||||
function mknote () # $1=Note Hz in bytes (e.g. A = 440Hz ::
|
||||
#+ 8000 fps / 440 = 16 :: A = 16 bytes per second)
|
||||
{
|
||||
{ #+ 8000 fps / 440 = 16 :: A = 16 bytes per second)
|
||||
for t in `seq 0 $duration`
|
||||
do
|
||||
test $(( $t % $1 )) = 0 && echo -n $volume || echo -n $mute
|
||||
done
|
||||
|
||||
}
|
||||
|
||||
e=`mknote 49`
|
||||
|
@ -39,4 +37,4 @@ echo -n "$g$e2$d$c$d$c$a$g$n$g$e$n$g$e2$d$c$c$b$c$cis$n$cis$d \
|
|||
$n$g$e2$d$c$d$c$a$g$n$g$e$n$g$a$d$c$b$a$b$c" > /dev/dsp
|
||||
# dsp = Digital Signal Processor
|
||||
|
||||
exit $? # A "bonny" example of a shell script!
|
||||
exit # A "bonny" example of a shell script!
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
#!/bin/bash
|
||||
# pad.sh
|
||||
|
||||
######################################################
|
||||
#######################################################
|
||||
# PAD (xml) file creator
|
||||
#+ Written by Mendel Cooper <thegrendel@theriver.com>.
|
||||
#+ Written by Mendel Cooper <thegrendel.abs@gmail.com>.
|
||||
#+ Released to the Public Domain.
|
||||
#
|
||||
# Generates a "PAD" descriptor file for shareware
|
||||
#+ packages, according to the specifications
|
||||
#+ of the ASP.
|
||||
# http://www.asp-shareware.org/pad
|
||||
######################################################
|
||||
#######################################################
|
||||
|
||||
|
||||
# Accepts (optional) save filename as a command-line argument.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#!/bin/bash
|
||||
# poem.sh: Pretty-prints one of the document author's favorite poems.
|
||||
# poem.sh: Pretty-prints one of the ABS Guide author's favorite poems.
|
||||
|
||||
# Lines of the poem (single stanza).
|
||||
Line[1]="I do not know which to prefer,"
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
##############################################################
|
||||
# QUACKEY: a somewhat simplified version of Perquackey [TM]. #
|
||||
# #
|
||||
# Author: Mendel Cooper <thegrendel@theriver.com> #
|
||||
# Author: Mendel Cooper <thegrendel.abs@gmail.com> #
|
||||
# version 0.1.02 03 May, 2008 #
|
||||
# License: GPL3 #
|
||||
##############################################################
|
||||
|
@ -13,9 +13,9 @@ WLIST=/usr/share/dict/word.lst
|
|||
# ^^^^^^^^ Word list file found here.
|
||||
# ASCII word list, one word per line, UNIX format.
|
||||
# A suggested list is the script author's "yawl" word list package.
|
||||
# http://ibiblio.org/pub/Linux/libs/yawl-0.3.2.tar.gz
|
||||
# http://bash.neuralshortciruit.com/yawl-0.3.2.tar.gz
|
||||
# or
|
||||
# http://personal.riverusers.com/~thegrendel/yawl-0.3.2.tar.gz
|
||||
# http://ibiblio.org/pub/Linux/libs/yawl-0.3.2.tar.gz
|
||||
|
||||
NONCONS=0 # Word not constructable from letter set.
|
||||
CONS=1 # Constructable.
|
||||
|
@ -462,4 +462,4 @@ exit $?
|
|||
# 7) Fix bugs!!!
|
||||
|
||||
# Reference for more info:
|
||||
# http://personal.riverusers.com/~thegrendel/qky.README.html
|
||||
# http://bash.neuralshortcircuit.com/qky.README.html
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
# quote-fetch.sh: Download a stock quote.
|
||||
|
||||
|
||||
E_NOPARAMS=66
|
||||
E_NOPARAMS=86
|
||||
|
||||
if [ -z "$1" ] # Must specify a stock (symbol) to fetch.
|
||||
then echo "Usage: `basename $0` stock-symbol"
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
# rand-string.sh
|
||||
# Generating an 8-character "random" string.
|
||||
|
||||
if [ "-n $1" ] # If command-line argument present,
|
||||
if [ -n "$1" ] # If command-line argument present,
|
||||
then #+ then set start-string to it.
|
||||
str0="$1"
|
||||
else # Else use PID of script as start-string.
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
# Soundex script
|
||||
# by
|
||||
# Mendel Cooper
|
||||
# thegrendel@theriver.com
|
||||
# 23 January, 2002
|
||||
# thegrendel.abs@gmail.com
|
||||
# reldate: 23 January, 2002
|
||||
#
|
||||
# Placed in the Public Domain.
|
||||
#
|
||||
|
@ -18,7 +18,7 @@
|
|||
|
||||
|
||||
ARGCOUNT=1 # Need name as argument.
|
||||
E_WRONGARGS=70
|
||||
E_WRONGARGS=90
|
||||
|
||||
if [ $# -ne "$ARGCOUNT" ]
|
||||
then
|
||||
|
@ -82,9 +82,9 @@ let "char_pos += 1" # Bump character position to 2nd letter of name.
|
|||
name1=${name:$char_pos}
|
||||
|
||||
|
||||
# ++++++++++++++++++++++++++ Exception Patch +++++++++++++++++++++++++++++++++
|
||||
# Now, we run both the input name and the name shifted one char to the right
|
||||
#+ through the value-assigning function.
|
||||
# ++++++++++++++++++++++++++ Exception Patch ++++++++++++++++++++++++++++++
|
||||
# Now, we run both the input name and the name shifted one char
|
||||
#+ to the right through the value-assigning function.
|
||||
# If we get the same value out, that means that the first two characters
|
||||
#+ of the name have the same value assigned, and that one should cancel.
|
||||
# However, we also need to test whether the first letter of the name
|
||||
|
@ -111,7 +111,7 @@ then
|
|||
else
|
||||
suffix=${s2:$char_pos}
|
||||
fi
|
||||
# ++++++++++++++++++++++ end Exception Patch +++++++++++++++++++++++++++++++++
|
||||
# ++++++++++++++++++++++ end Exception Patch ++++++++++++++++++++++++++++++
|
||||
|
||||
|
||||
padding=000 # Use at most 3 zeroes to pad.
|
||||
|
|
|
@ -23,7 +23,7 @@ IMGDIR="images" # Image directory
|
|||
# Headers
|
||||
HDR01='<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">'
|
||||
HDR02='<!-- Converted to HTML by ***tohtml.sh*** script -->'
|
||||
HDR03='<!-- script author: M. Leo Cooper <thegrendel@theriver.com> -->'
|
||||
HDR03='<!-- script author: M. Leo Cooper <thegrendel.abs@gmail.com> -->'
|
||||
HDR10='<html>'
|
||||
HDR11='<head>'
|
||||
HDR11a='</head>'
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
# ===========================================================
|
||||
# Standard Check for Script Argument(s)
|
||||
ARGS=1
|
||||
E_BADARGS=65
|
||||
E_NOFILE=66
|
||||
E_BADARGS=85
|
||||
E_NOFILE=86
|
||||
|
||||
if [ $# -ne $ARGS ]
|
||||
then
|
||||
|
@ -31,7 +31,7 @@ WORDFILE=/usr/share/dict/linux.words # Dictionary file.
|
|||
# May specify a different word list file
|
||||
#+ of one-word-per-line format.
|
||||
# For example, the "yawl" word-list package,
|
||||
# http://personal.riverusers.com/~thegrendel/yawl-0.3.2.tar.gz
|
||||
# http://bash.neuralshortcircuit.com/yawl-0.3.2.tar.gz
|
||||
|
||||
|
||||
wlist=`strings "$1" | tr A-Z a-z | tr '[:space:]' Z | \
|
||||
|
|
Loading…
Reference in New Issue