aboutsummaryrefslogtreecommitdiffstats
path: root/examples/scripts.v2
diff options
context:
space:
mode:
Diffstat (limited to 'examples/scripts.v2')
-rw-r--r--examples/scripts.v2/PERMISSION59
-rw-r--r--examples/scripts.v2/README37
-rw-r--r--examples/scripts.v2/arc2tarz85
-rw-r--r--examples/scripts.v2/bashrand76
-rw-r--r--examples/scripts.v2/cal2day.bash49
-rw-r--r--examples/scripts.v2/cdhist.bash176
-rw-r--r--examples/scripts.v2/corename43
-rw-r--r--examples/scripts.v2/fman281
-rwxr-xr-xexamples/scripts.v2/frcp288
-rw-r--r--examples/scripts.v2/lowercase44
-rw-r--r--examples/scripts.v2/ncp187
-rw-r--r--examples/scripts.v2/newext64
-rw-r--r--examples/scripts.v2/nmv187
-rw-r--r--examples/scripts.v2/pages187
-rw-r--r--examples/scripts.v2/pf127
-rw-r--r--examples/scripts.v2/pmtop25
-rw-r--r--examples/scripts.v2/ren585
-rw-r--r--examples/scripts.v2/rename122
-rw-r--r--examples/scripts.v2/repeat121
-rw-r--r--examples/scripts.v2/shprof66
-rw-r--r--examples/scripts.v2/untar80
-rw-r--r--examples/scripts.v2/uudec45
-rw-r--r--examples/scripts.v2/uuenc69
-rw-r--r--examples/scripts.v2/vtree137
-rw-r--r--examples/scripts.v2/where111
25 files changed, 3251 insertions, 0 deletions
diff --git a/examples/scripts.v2/PERMISSION b/examples/scripts.v2/PERMISSION
new file mode 100644
index 0000000..f65e848
--- /dev/null
+++ b/examples/scripts.v2/PERMISSION
@@ -0,0 +1,59 @@
+From spcecdt@armory.com Wed May 10 10:21:11 1995
+Flags: 10
+Return-Path: spcecdt@armory.com
+Received: from po.cwru.edu (root@po.CWRU.Edu [129.22.4.2]) by odin.INS.CWRU.Edu with ESMTP (8.6.10+cwru/CWRU-2.1-ins)
+ id KAA22876; Wed, 10 May 1995 10:21:10 -0400 (from spcecdt@armory.com for <chet@odin.INS.CWRU.Edu>)
+Received: from deepthought.armory.com (mmdf@deepthought.armory.com [192.122.209.42]) by po.cwru.edu with SMTP (8.6.10+cwru/CWRU-2.3)
+ id BAA16354; Wed, 10 May 1995 01:33:22 -0400 (from spcecdt@armory.com for <chet@po.cwru.edu>)
+From: John DuBois <spcecdt@armory.com>
+Date: Tue, 9 May 1995 22:33:12 -0700
+In-Reply-To: Chet Ramey <chet@odin.ins.cwru.edu>
+ "ksh scripts" (May 9, 1:36pm)
+X-Www: http://www.armory.com/~spcecdt/
+X-Mailer: Mail User's Shell (7.2.5 10/14/92)
+To: chet@po.cwru.edu
+Subject: Re: ksh scripts
+Message-ID: <9505092233.aa13001@deepthought.armory.com>
+
+ Sure. The canonical versions are available on ftp.armory.com; you might
+want to pick up the latest versions before modifying them.
+
+ John
+
+On May 9, 1:36pm, Chet Ramey wrote:
+} Subject: ksh scripts
+} From odin.ins.cwru.edu!chet Tue May 9 10:39:51 1995
+} Received: from odin.INS.CWRU.Edu by deepthought.armory.com id aa22336;
+} 9 May 95 10:39 PDT
+} Received: (chet@localhost) by odin.INS.CWRU.Edu (8.6.10+cwru/CWRU-2.1-ins)
+} id NAA20487; Tue, 9 May 1995 13:39:24 -0400 (from chet)
+} Date: Tue, 9 May 1995 13:36:54 -0400
+} From: Chet Ramey <chet@odin.ins.cwru.edu>
+} To: john@armory.com
+} Subject: ksh scripts
+} Cc: chet@odin.ins.cwru.edu
+} Reply-To: chet@po.cwru.edu
+} Message-ID: <9505091736.AA20411.SM@odin.INS.CWRU.Edu>
+} Read-Receipt-To: chet@po.CWRU.Edu
+} MIME-Version: 1.0
+} Content-Type: text/plain; charset=us-ascii
+} Status: OR
+}
+} Hi. I'm the maintainer of bash (the GNU `Bourne Again shell') for
+} the FSF.
+}
+} I picked up a tar file of ksh scripts you wrote from an anon FTP site
+} a while back. I'd like your permission to include modified versions
+} of some of them in the next major bash distribution (with proper credit
+} given, of course). Is it OK if I do that?
+}
+} Chet Ramey
+}
+} --
+} ``The lyf so short, the craft so long to lerne.'' - Chaucer
+}
+} Chet Ramey, Case Western Reserve University Internet: chet@po.CWRU.Edu
+}-- End of excerpt from Chet Ramey
+
+
+
diff --git a/examples/scripts.v2/README b/examples/scripts.v2/README
new file mode 100644
index 0000000..74f27c5
--- /dev/null
+++ b/examples/scripts.v2/README
@@ -0,0 +1,37 @@
+This collection of scripts was originally written for ksh-88 by
+John DuBois <spcecdt@armory.com>. The conversion to bash v2
+syntax was done by Chet Ramey.
+
+These scripts are as-is; there is no copyright associated with
+any of them. They exist simply as examples of bash scripting.
+
+Here's a description of what's in this directory:
+
+arc2tarz Convert an "arc" archive to a compressed tar archive.
+cal2day.bash Convert a day number to a name.
+corename Tell what produced a core file.
+fman Fast man(1) replacement.
+frcp Copy files using ftp(1) but with rcp-type command line syntax.
+lowercase Change filenames to lower case.
+ncp A nicer front end for cp(1) (has -i, etc.).
+newext Change the extension of a group of files.
+nmv A nicer front end for mv(1) (has -i, etc.).
+pages Print specified pages from files.
+PERMISSION Permissions to use the scripts in this directory.
+pf A pager front end that handles compressed files.
+README README
+ren Rename files by changing parts of filenames that match a pattern.
+rename Change the names of files that match a pattern.
+repeat Execute a command multiple times.
+untar Unarchive a (possibly compressed) tarfile into a directory.
+uudec Carefully uudecode(1) multiple files.
+uuenc uuencode(1) multiple files.
+vtree Print a visual display of a directory tree.
+where Show where commands that match a pattern are.
+
+The following scripts were written or converted by Chet Ramey:
+
+bashrand Random number generator with upper and lower bounds and optional seed.
+cdhist.bash cd replacement with a directory stack added.
+pmtop Poor man's 'top(1)' for SunOS 4.x and BSD/OS.
+shprof Line profiler for bash scripts.
diff --git a/examples/scripts.v2/arc2tarz b/examples/scripts.v2/arc2tarz
new file mode 100644
index 0000000..285bede
--- /dev/null
+++ b/examples/scripts.v2/arc2tarz
@@ -0,0 +1,85 @@
+#! /bin/bash
+#
+# original from:
+# arc2tarz: convert arced file to tarred, compressed form.
+# @(#) arc2tarz.ksh 1.0 92/02/16
+# 91/03/28 john h. dubois iii (john@armory.com)
+# 92/02/16 added -h option for help
+#
+# conversion to bash v2 syntax by Chet Ramey
+
+unset ENV
+Usage="Usage: $0 arcfile [-hcg] [ tarzfile ]"
+
+phelp()
+{
+echo "$Usage
+arcfile is the name of an arc file to convert to tarred, compressed form.
+The file must have a .arc extension, but only the base name needs to be
+given. If no output file name is given, it will be created in the current
+directory with the name being the arcfile basename followed by .tar.EXT.
+If the -c option is given, compress will be used, and EXT will be Z.
+The default (also available with -g) is to use gzip, in which case EXT
+is gz. If the basename is too long the extension may be truncated. All
+uppercase letters in the names of files in the archive are moved to lowercase."
+}
+
+compress=gzip
+ext=gz
+
+while getopts "hcg" opt; do
+ case "$opt" in
+ h) phelp; exit 0;;
+ c) compress=compress; ext=Z;;
+ g) compress=gzip ; ext=gz ;;
+ *) echo "$Usage" 1>&2 ; exit 2;;
+ esac
+done
+
+shift $((OPTIND - 1))
+
+if [ $# = 0 ]; then
+ phelp
+ exit 0
+fi
+
+[ -z "$TMP" ] && tmpdir=/tmp/arc2tarz.$$ || tmpdir=$TMP/arc2tarz.$$
+
+case "$1" in
+*.arc) arcfile=$1 ;;
+*) arcfile=$1.arc ;;
+esac
+
+if [ ! -f $arcfile ] || [ ! -r $arcfile ]; then
+ echo "Could not open arc file \"$arcfile\"."
+ exit 1
+fi
+
+case "$arcfile" in
+/*) ;;
+*) arcfile=$PWD/$arcfile ;;
+esac
+
+basename=${arcfile%.arc}
+basename=${basename##*/}
+[ $# -lt 2 ] && tarzname=$PWD/$basename.tar.$ext || tarzname=$2
+
+trap 'rm -rf $tmpdir $tarzname' 1 2 3 6 15
+
+mkdir $tmpdir
+cd $tmpdir
+echo "unarcing files..."
+arc -ie $arcfile
+
+# lowercase
+for f in *; do
+ new=$(echo $f | tr A-Z a-z)
+ if [ "$f" != "$new" ]; then
+ mv $f $new
+ fi
+done
+
+echo "tarring/compressing files..."
+tar cf - * | $compress > $tarzname
+cd -
+rm -rf $tmpdir
diff --git a/examples/scripts.v2/bashrand b/examples/scripts.v2/bashrand
new file mode 100644
index 0000000..54260c0
--- /dev/null
+++ b/examples/scripts.v2/bashrand
@@ -0,0 +1,76 @@
+#! /bin/bash
+# bashrand - generate a random number in a specified range with an
+# optionally specified ``seed'' value.
+#
+# Original Author: Peter Turnbull, May 1993
+
+usage()
+{
+ echo "$PROG: usage: $PROG [-s seed] lower-limit upper-limit" >&2
+}
+
+PROG=${0##*/}
+
+SEED=$$ # Initialize random-number seed value with PID
+
+while getopts s: opt
+do
+ case "$opt" in
+ s) SEED=$OPTARG ;;
+ *) usage ; exit 2 ;;
+ esac
+done
+
+shift $((OPTIND - 1))
+
+# Process command-line arguments:
+case $# in
+ 2) Lower=$1; Upper=$2 ;;
+ *) usage ; exit 2 ;;
+esac
+
+# Check that specified values are integers:
+expr "$Lower" + 0 >/dev/null 2>&1 || {
+ echo "$PROG: lower ($Lower) not an integer" >&2
+ exit 1
+}
+
+expr "$Upper" + 0 >/dev/null 2>&1 || {
+ echo "$PROG: upper ($Upper) not an integer" >&2
+ exit 1
+}
+
+expr "$SEED" + 0 >/dev/null 2>&1 || {
+ echo "$PROG: seed ($SEED) not an integer" >&2
+ exit 1
+}
+
+# Check that values are in the correct range:
+(( $Lower < 0 )) || [ `expr "$Lower" : '.*'` -gt 5 ] && {
+ echo "$PROG: Lower limit ($Lower) out of range" >&2
+ exit 1
+}
+
+(( $Upper > 32767 )) || [ `expr "$Upper" : '.*'` -gt 5 ] && {
+ echo "$PROG: Upper limit ($Upper) out of range" >&2;
+ exit 1
+}
+
+(( $SEED < 0 )) || (( $SEED > 32767 )) || [ `expr "$SEED" : '.*'` -gt 5 ] && {
+ echo "$PROG: Seed value ($SEED) out of range (0 to 32767)" >&2
+ exit 1
+}
+
+(( $Upper <= $Lower )) && {
+ echo "$PROG: upper ($Upper) <= lower value ($Lower)" >&2
+ exit 1
+}
+
+# Seed the random-number generator:
+RANDOM=$SEED
+
+# Compute value, scaled within range:
+let rand="$RANDOM % ($Upper - $Lower + 1) + $Lower"
+
+# Report result:
+echo $rand
diff --git a/examples/scripts.v2/cal2day.bash b/examples/scripts.v2/cal2day.bash
new file mode 100644
index 0000000..f26128b
--- /dev/null
+++ b/examples/scripts.v2/cal2day.bash
@@ -0,0 +1,49 @@
+#!/bin/bash
+# cal2day - "parse" appropriate calendar output to match date number
+# with day name.
+#
+# usage: cal2day month day [year]
+#
+# ORIGINAL *TAG:33239 3:Dec 9 1997:0755:sh.d/cal2day:
+#
+# Obtained from usenet
+#
+# Converted to bash v2 syntax by Chet Ramey <chet@po.cwru.edu>
+
+#1 PARSE OPTIONS
+while getopts :dls _inst
+do case $_inst in
+ (d) format='%1d%.0s\n' ;; # 0, 1, ..., 7
+ (l) format='%0.s%-s\n' ;; # Sunday, Monday, ..., Saturday
+ (s) format='%0.s%-.3s\n' ;; # Sun, Mon, ..., Sat
+ esac
+done
+shift $((OPTIND-1))
+
+#2 PARAMETER VALUES
+((!$#)) && set -- $(date '+%m %d')
+: ${format:='%0.s%-.3s\n'}
+: ${1:?missing month parameter [1-12]}
+: ${2:?missing day parameter [1-31]}
+
+#3 CALCULATE DAY-OF-WEEK FROM DATE
+cal $1 ${3:-$(date +%Y)} | gawk -FX '
+BEGIN { day="Sunday Monday Tuesday WednesdayThursday Friday Saturday"
+ sub(/^0/, "", daynum)
+ dayre="(^| )" daynum "( |$)"
+ }
+#NR==2 { print length($0) }
+NR==1 || NR==2 \
+ { next }
+dayre { if (match($0, dayre))
+ { #print RSTART, RLENGTH, substr($0, RSTART, RLENGTH)
+ if (daynum<=9 || RSTART==1) RSTART-=1
+ exit
+ }
+ }
+END { # 20/21 char width assumed
+ printf format, RSTART/3, substr(day, RSTART*3+1, 9)
+ }
+' daynum=$2 format=$format -
+
+exit 0
diff --git a/examples/scripts.v2/cdhist.bash b/examples/scripts.v2/cdhist.bash
new file mode 100644
index 0000000..df8aea7
--- /dev/null
+++ b/examples/scripts.v2/cdhist.bash
@@ -0,0 +1,176 @@
+#! /bin/bash
+#
+# cdhist - cd replacement with a directory stack like pushd/popd
+#
+# usage: cd [-l] [-n] [-] [dir]
+#
+# options:
+# -l print the cd directory stack, one entry per line
+# - equivalent to $OLDPWD
+# -n cd to nth directory in cd directory stack
+# -s cd to first directory in stack matching (substring) `s'
+#
+# arguments:
+# dir cd to dir and push dir onto the cd directory stack
+#
+# If the new directory is a directory in the stack and the options selected
+# it (-n, -s), the new working directory is printed
+#
+# If the variable CDHISTFILE is set, the cd directory stack is loaded from
+# and written to $CDHISTFILE every time `cd' is executed.
+#
+# Note: I got this off the net somewhere; I don't know the original author
+#
+# Chet Ramey
+# chet@po.cwru.edu
+
+_cd_print()
+{
+ echo -e "$@"
+}
+
+cd()
+{
+ typeset -i cdlen i
+ typeset t
+
+ if [ $# -eq 0 ]
+ then
+ set -- $HOME
+ fi
+
+ if [ "$CDHISTFILE" ] && [ -r "$CDHISTFILE" ] # if directory history exists
+ then
+ typeset CDHIST
+ i=-1
+ while read -r t # read directory history file
+ do
+ CDHIST[i=i+1]=$t
+ done <$CDHISTFILE
+ fi
+
+ if [ "${CDHIST[0]}" != "$PWD" ] && [ -n "$PWD" ]
+ then
+ _cdins # insert $PWD into cd history
+ fi
+
+ cdlen=${#CDHIST[*]} # number of elements in history
+
+ case "$@" in
+ -) # cd to new dir
+ if [ "$OLDPWD" = "" ] && ((cdlen>1))
+ then
+ '_cdprint' ${CDHIST[1]}
+ builtin cd ${CDHIST[1]}
+ pwd
+ else
+ builtin cd "$@"
+ # pwd
+ fi
+ ;;
+ -l) # _cdprint directory list
+ ((i=cdlen))
+ while (((i=i-1)>=0))
+ do
+ num=$i
+ '_cdprint' "$num ${CDHIST[i]}"
+ done
+ return
+ ;;
+ -[0-9]|-[0-9][0-9]) # cd to dir in list
+ if (((i=${1#-})<cdlen))
+ then
+ '_cdprint' ${CDHIST[i]}
+ builtin cd ${CDHIST[i]}
+ pwd
+ else
+ builtin cd $@
+ # pwd
+ fi
+ ;;
+ -*) # cd to matched dir in list
+ t=${1#-}
+ i=1
+ while ((i<cdlen))
+ do
+ case ${CDHIST[i]} in
+ *$t*)
+ '_cdprint' ${CDHIST[i]}
+ builtin cd ${CDHIST[i]}
+ pwd
+ break
+ ;;
+ esac
+ ((i=i+1))
+ done
+ if ((i>=cdlen))
+ then
+ builtin cd $@
+ # pwd
+ fi
+ ;;
+ *) # cd to new dir
+ builtin cd $@
+ # pwd
+ ;;
+ esac
+
+ _cdins # insert $PWD into cd history
+
+ if [ "$CDHISTFILE" ]
+ then
+ cdlen=${#CDHIST[*]} # number of elements in history
+
+ i=0
+ while ((i<cdlen))
+ do
+ echo ${CDHIST[i]} # update directory history
+ ((i=i+1))
+ done >$CDHISTFILE
+ fi
+}
+
+_cdins() # insert $PWD into cd history
+{ # meant to be called only by cd
+ typeset -i i
+
+ i=0
+
+ while (( i < ${#CDHIST[*]} )) # see if dir is already in list
+ do
+ if [ "${CDHIST[$i]}" = "$PWD" ]
+ then
+ break
+ fi
+ ((i=i+1))
+ done
+
+ if (( i>22 )) # limit max size of list
+ then
+ i=22
+ fi
+
+ while (((i=i-1)>=0)) # bump old dirs in list
+ do
+ CDHIST[i+1]=${CDHIST[i]}
+ done
+
+ CDHIST[0]=$PWD # insert new directory in list
+}
+
+# examples
+shopt -s expand_aliases
+
+# go to known place before doing anything
+cd /
+
+echo CDHIST: "${CDHIST[@]}"
+for dir in /tmp /bin - -2 -l
+do
+ cd $dir
+ echo CDHIST: "${CDHIST[@]}"
+ echo PWD: $PWD
+
+done
+
+exit 0
diff --git a/examples/scripts.v2/corename b/examples/scripts.v2/corename
new file mode 100644
index 0000000..2b51e5d
--- /dev/null
+++ b/examples/scripts.v2/corename
@@ -0,0 +1,43 @@
+#! /bin/bash
+#
+# original from:
+# @(#) corename.ksh 1.0 93/04/01
+# 92/11/11 john h. dubois iii (john@armory.com)
+# 92/02/16 Added help option.
+# 92/02/22 Added cd to origdir to fix prob w/multiple relative paths.
+# 93/04/01 Added check for whether file exists.
+#
+# conversion to bash v2 syntax done by Chet Ramey
+
+# inspired by belal's equivalent utility
+
+if [ "$1" = -h ]; then
+ echo \
+"$0: print the names of executables that dumped core.
+Usage: $0 [corename ...]
+If no corename is given, \"core\" is assumed."
+ exit 0
+fi
+
+[ $# = 0 ] && set core
+origdir=$PWD
+for i; do
+ cd $origdir
+ file=${i##*/}
+ dir=${i%$file}
+ [ -z "$dir" ] && dir=$origdir/
+ if [ ! -f $dir$file ]; then
+ echo "$dir$file: No such file."
+ continue
+ fi
+ if [ ! -r $dir$file ]; then
+ echo "$dir$file: Cannot open."
+ continue
+ fi
+ cd $dir
+
+ # the adb output syntax is highly variable. this works on SunOS 4.x
+ set -- $(adb $file < /dev/null 2>&1 | sed 1q)
+ name=${7#??}
+ echo "$i: ${name%??}"
+done
diff --git a/examples/scripts.v2/fman b/examples/scripts.v2/fman
new file mode 100644
index 0000000..1e94d21
--- /dev/null
+++ b/examples/scripts.v2/fman
@@ -0,0 +1,281 @@
+#! /bin/bash
+#
+# original from:
+# fman: new man program
+# @(#) fman.ksh 1.5 94/04/16
+# 91/07/03 john h. dubois iii (john@armory.com)
+# 91/07/11 made it unpack man pages if neccessary
+# 91/07/16 fixed test for whether man file pattern was expanded
+# 92/01/21 made it read /etc/default/man to get section order,
+# and only display the first section found.
+# 92/02/06 changed name to fman
+# 92/02/07 fixed bug in notfound
+# 92/02/13 incorporated changes from DOS version
+# 92/03/11 changed to use MANPATH from environment if set,
+# and search all directories given in MANPATH
+# 92/03/15 exec pager or man w/o forking
+# 92/05/31 try using index if one exists
+# 92/10/01 Added "See also <other sections>"
+# 92/10/18 If PAGER is less, search for name of man page to make it easier
+# to find information in man pages for multiple items
+# 92/11/11 Make it work for compressed files not listed in index;
+# deal with man pages listed in index that don't exist.
+# 93/03/30 Fixed bug in MANPATH processing
+# 93/06/17 Include paths in "See also:" message if they would be needed
+# to get to a man page. Allow MANPATH spec on command line.
+# 93/07/09 Added -h and -e options.
+# 94/04/16 Added x option.
+#
+# conversion to bash v2 syntax done by Chet Ramey
+
+istrue()
+{
+ test 0 -ne "$1"
+}
+
+isfalse()
+{
+ test 0 -eq "$1"
+}
+
+# Finds all sections that man page $1 is in and puts them in the the
+# global array Sections[].
+# The filename of each page is put in FileNames[] with the same index.
+# Global vars used:
+# patharr[] MANPATH directories.
+
+FindSectionsInIndex ()
+{
+ typeset index indexes section mpath page=$1
+ typeset -i i=0 NIndex=0
+
+ for mpath in "${patharr[@]}"; do
+ if [ -r $mpath/index ]; then
+ indexes="$indexes $mpath/index"
+ let NIndex+=1
+ fi
+ done
+ [ -z "$indexes" ] && return
+ # Make grep give filename
+ [ NIndex -lt 2 ] && indexes="$indexes /dev/null"
+ # set positional parameters to
+ # indexfile:searchname pagename section ...
+ # e.g.
+ # /usr/man/index:FP_OFF Routines DOS
+ set -- `grep "^$page[ ]" $indexes`
+ while [ $# -gt 2 ]; do
+ FileNames[i]=${1%%index*}cat$3/$2.$3
+ Sections[i]=$3
+ shift 3
+ let i+=1
+ done
+}
+
+# Finds all sections that man page $1 is in by searching each man directory
+# in the order given in patharr[],
+# and puts them in the the global array Sections[].
+# The filename of each page is put in FileNames[] with the same index.
+# Global vars used:
+# patharr[] MANPATH directories.
+FindSectionsInDirs ()
+{
+ local page=$1 mpath AllPaths Path
+ typeset -i i
+
+ for mpath in "${patharr[@]}"; do
+ AllPaths="$AllPaths $mpath/cat[0-9]*/$page.* $mpath/man[0-9]*/$page.*"
+ done
+
+ i=0
+ for Path in $AllPaths; do
+ istrue $debug && echo Path = $Path
+ case "$Path" in
+ *\*) ;;
+ *)
+ # Remove compressed-file suffix to make FileNames be the same
+ # as it is when built by FindSectionsInIndex()
+ FileNames[i]=${Path%.[zZ]}
+ Path=${Path%/*}
+ Sections[i]=${Path##*/*.}
+ let i+=1 ;;
+ esac
+ done
+}
+
+# FindSection: display man page.
+# Uses ordarr[] (built from $ORDER) to display the version of the man
+# page that occurs first in $ORDER.
+# Sections[] gives the sections that a man page was found in.
+# If the global variable "exist" is set to 1, nothing is displayed;
+# the function instead returns zero if a page is found, nonzero if not.
+# The filename of each page is in FileNames[] with the same index.
+# Global vars used:
+# Sections[], FileNames[], ordarr[]
+FindSection ()
+{
+ typeset -i NumPages i foundsec
+ local section OtherSec filename NPAGER=$PAGER POpt page=$1 Pat
+ local PageFile
+
+ NumPages=${#Sections[*]} # Number of versions of man page found.
+ isfalse $NumPages && return 1
+ case "$PAGER" in
+ *less) Popt="-p$page" ;;
+ esac
+
+ # For each section in ORDER, determine if any man page was found in
+ # that section
+ for section in "${ordarr[@]}"; do
+ i=0
+ foundsec=0
+ while [ $i -lt $NumPages ]; do
+ if [ "${Sections[i]}" = $section ]; then
+ # Found a man page from this section of ORDER
+ filename=${FileNames[i]}
+ if [ -z "$PageFile" ]; then
+ PageFile=$filename
+ else
+ if istrue $foundsec; then
+ OtherSec="$OtherSec$page(${filename%/*/*} $section) "
+ else
+ OtherSec="$OtherSec$page($section) "
+ fi
+ fi
+ foundsec=1
+ istrue $exist && return
+ fi
+ let i+=1
+ done
+ done
+ # No pages with the specified section found.
+ [ -z "$PageFile" ] && return 1
+ # Return if all we want to know is whether the man page exists.
+ [ "$exist" = 1 ] && return 0
+ if [ -z "$OtherSec" ]; then
+ NPAGER="exec $PAGER"
+ fi
+ if [ -r $PageFile ]; then
+ $NPAGER $POpt $PageFile
+ elif [ -r $PageFile.z ]; then
+ pcat $PageFile.z | $NPAGER $POpt
+ elif [ -r $PageFile.Z ]; then
+ zcat $PageFile.Z | $NPAGER $POpt
+ elif [ -f $PageFile.gz ]; then
+ gzip -dc $PageFile.gz | $NPAGER $POpt
+ else
+ echo "$PageFile: cannot open." 1>&2
+ OtherSec=
+ unset Sections[i]
+ let i+=1
+ continue
+ fi
+ echo "See also $OtherSec"
+ exit 0
+}
+
+phelp()
+{
+echo "$name: print man pages.
+$name locates and prints the specified manual pages from the online UNIX
+documentation.
+$Usage
+Options:
+-e: Determine whether the specified man page exists. Nothing is printed;
+ $0 exits with a zero status if the page exists and a nonzero status if
+ it does not.
+-h: Print this help."
+}
+
+# main program
+
+typeset -i exist=0 debug=0
+
+name=${0##*/}
+Usage="Usage: $name [-eh] [[manpath] section] command-name"
+
+while getopts :hex opt; do
+ case $opt in
+ h) phelp; exit 0;;
+ e) exist=1 ;;
+ x) debug=1 ;;
+ +?) echo "$name: options should not be preceded by a '+'." 1>&2; exit 2;;
+ ?)
+ echo "$name: $OPTARG: bad option. Use -h for help." 1>&2 ; exit 2 ;;
+ esac
+done
+
+# remove args that were options
+shift $((OPTIND-1))
+
+if [ $# -lt 1 ]; then
+ echo -e "$Usage\nUse -h for help." 1>&2
+ exit
+fi
+
+P=$PAGER
+O=1:n:l:6:8:2:3:4:5:7:p:o
+T=$TERM
+M=${MANPATH:-/usr/local/man:/usr/man}
+[ -f /etc/default/man ] && . /etc/default/man
+[ -n "$P" ] && PAGER=$P
+[ -n "$O" ] && ORDER=$O
+[ -n "$T" ] && TERM=$T
+[ -n "$M" ] && MANPATH=$M
+
+case $# in
+0) echo "No man page specified." ; exit 1;;
+1) page=$1;;
+2) ORDER=$(echo $1 | tr a-z A-Z) ; page=$2;;
+3) MANPATH=$1
+ [ -n "$2" ] && ORDER=$(echo $2 | tr a-z A-Z)
+ page=$3;;
+*) echo "Too many arguments."; exit 1;;
+esac
+
+aargs=("$@")
+[ ! -t 0 ] && PAGER=cat
+
+OIFS=$IFS
+IFS=:
+patharr=($MANPATH)
+i=0
+for d in $MANPATH; do
+ for sec in $ORDER; do
+ ordarr[i]=$d/cat${sec}
+ let i+=1
+ ordarr[i]=$d/man${sec}
+ let i+=1
+ done
+done
+IFS=$OIFS
+
+istrue $debug && echo patharr = "${patharr[@]}"
+
+# if less or more is being used, remove multiple blank lines
+export LESS="-s $LESS"
+export MORE="-s $MORE"
+
+# Try using index
+FindSectionsInIndex "$page"
+# Exit 0 if a page was found and we're just testing for existence.
+FindSection "$page" && exit 0
+
+# Try searching directories
+unset Sections[*]
+FindSectionsInDirs "$page"
+FindSection "$page" && exit 0
+
+istrue $exist && exit 1
+
+# Try using man
+# If using more or less, make man run faster by letting more or less compress
+# multiple blank lines instead of rmb
+#case "$PAGER" in
+#*more|*less) manopt=-b;;
+#esac
+
+#cmd=(man $manopt -p$PAGER "${aargs[@]}")
+export PAGER
+cmd=(man $manopt "${aargs[@]}")
+istrue $debug && echo "$name: running ${cmd[*]}" 1>&2
+exec "${cmd[@]}"
diff --git a/examples/scripts.v2/frcp b/examples/scripts.v2/frcp
new file mode 100755
index 0000000..572aa7b
--- /dev/null
+++ b/examples/scripts.v2/frcp
@@ -0,0 +1,288 @@
+#! /bin/bash
+#
+# original from:
+#
+# @(#) frcp.ksh 2.2 93/11/14
+# 92/06/29 john h. dubois iii (john@armory.com)
+# 92/10/14 Cleaned up, improved, added -d and -r options
+# 92/11/11 Made work with a dest of '.'
+# 93/07/09 Added -l and -n options, & login as anonymous if no .netrc entry
+# 93/11/14 Use either passwd or password in .netrc, since ftp does.
+#
+# conversion to bash v2 syntax by Chet Ramey
+#
+# frcp: ftp front end with rcp-like syntax.
+# Note: requires any machine names given to be listed with
+# user and password in .netrc. If not, anonymous FTP is
+# done.
+#
+# full path to ftp binary
+if [ -x /usr/bin/ftp ]; then
+ FTP=/usr/bin/ftp;
+elif [ -x /usr/ucb/ftp ]; then
+ FTP=/usr/ucb/ftp
+else
+ FTP=ftp
+fi
+
+istrue()
+{
+ test 0 -ne "$1"
+}
+isfalse()
+{
+ test 0 -eq "$1"
+}
+
+# For each filename given, put the filename in filename[n]
+# and the machine it is on in machine[n].
+function SplitNames {
+ typeset file
+ typeset -i i=1
+
+ unset filename[*] machine[*]
+ for file; do
+ case "$file" in
+ *:*) machine[i]=${file%%:*} ;;
+ *) machine[i]=$LocalMach ;;
+ esac
+ filename[i]=${file#*:}
+ let i+=1
+ done
+}
+
+function verboseprint {
+ echo "$@"
+ echo "$@" 1>&2
+}
+
+function MakeDir {
+ OFS=$IFS
+ local IFS=/ dir component
+
+ case "$1" in
+ /*) ;;
+ *) dir=.
+ esac
+ set -- $1
+ IFS=$OFS
+ for component; do
+ dir=$dir/$component
+ if [ ! -d "$dir" ]; then
+ if mkdir "$dir"; then :; else
+ echo "Could not make directory $dir." >&2
+ return 1
+ fi
+ fi
+ done
+ return 0
+}
+
+lastisdot ()
+{
+ case "$1" in
+ */.|*/..) return 0;;
+ *) return 1;;
+ esac
+}
+
+# CopyFiles: issue ftp(TC) commands to copy files.
+# Usage: CopyFiles [sourcemachine:]sourcepath ... [destmachine:]destpath
+# Global vars:
+# Uses LocalMach (should be name of local machine)
+# Sets global arrs machine[]/filename[]
+function CopyFiles {
+ unset machine[*] filename[*]
+
+ SplitNames "$@" # split names into filename[1..n] and machine[1..n]
+
+ local DestMach=${machine[$#]} # Machine to copy files to
+ local DestPath=${filename[$#]} # Destination file/dir
+
+ unset machine[$#] filename[$#]
+
+ [ -z "$DestPath" ] && DestPath=. # dest was given as machine:
+
+ # Try to determine if destination should be a directory
+ # so that it can be forced to be a directory.
+
+ case "$DestPath" in
+ */) ;; # don't add / if trailing / already present
+ *) if [ $# -gt 2 ] || # if more than two args given, last must be a dir
+ # If dest in on local machine, check whether it is a directory
+ [ $DestMach = $LocalMach ] && [ -d "$DestPath" ] ||
+ # If dest ends with . or .., it is a directory
+ lastisdot "$DestPath"
+ then
+ DestPath=$DestPath/
+ fi ;;
+ esac
+
+ # If one of the above tests made us think dest is a directory,
+ # but it isn't, complain
+ case "$DestPath" in
+ */) if [ "$DestMach" = "$LocalMach" ] && [ ! -d "$DestPath" ]; then
+ echo "Destination is not a directory." 1>&2
+ exit 1
+ fi ;;
+ esac
+
+ DoCopy "$DestMach" "$DestPath"
+}
+
+# Usage: OpenMachine machine-name
+# Emits login sequence or doesn't, depending on .netrc file and global
+# variables anon and noanon
+OpenMachine ()
+{
+ local machine=$1 netrc=$HOME/.netrc user= password=
+
+ if isfalse $anon && [ -r $netrc ]; then
+ set -- $(gawk '
+ /machine (.* )?'"$machine"'($| )/,/^ *$/ {
+ Fields[$1] = $2
+ if ("passwd" in Fields)
+ Fields["password"] = Fields["passwd"]
+ if ("login" in Fields && "password" in Fields) {
+ print Fields["login"] " " Fields["password"]
+ exit
+ }
+ }
+ ' $netrc )
+ user=$1
+ password=$2
+ fi
+ if [ -z "$password" ]; then
+ if istrue $noanon; then
+ echo "No .netrc entry for machine $machine" 1>&2
+ exit 1
+ fi
+ user=anonymous
+ password=$USER@$LocalMach
+ fi
+ verboseprint open $machine
+ echo user $user "*******" 1>&2
+ echo user $user $password
+}
+
+# Usage: DoCopy destination-machine destination-path
+# Copies the files in global arrs machine[]/filename[] to the given dest
+# Global vars:
+# Uses machine[], filename[], LocalMach, check
+DoCopy ()
+{
+ local DestMach=$1
+ local DestPath=$2
+ local OpenMach # Machine that connection is currently open to
+ local OWD=$PWD SourceMach SourceFile
+ local FileName
+ typeset -i i=1
+
+ while [ $i -le ${#machine[*]} ]; do
+ istrue $check && verboseprint "runique"
+
+ SourceMach=${machine[i]}
+ SourceFile=${filename[i]}
+
+ DestFile=$DestPath
+ # if DestPath is a dir,
+ # add source filename to it without source path
+ case "$DestFile" in
+ */) DestFile=$DestFile${SourceFile##*/} ;;
+ esac
+
+ if [ $SourceMach = $LocalMach ]; then
+ if [ $DestMach != "$OpenMach" ]; then
+ OpenMachine $DestMach
+ OpenMach=$DestMach
+ fi
+ verboseprint put $SourceFile $DestFile
+ elif [ $DestMach = $LocalMach ]; then
+ if istrue $check && [ -f "$DestFile" ]; then
+ echo "$DestFile already exists." 1>&2
+ continue
+ fi
+ # If destination is on local machine,
+ # the dest will be a full dir/filename
+ if istrue $createdirs; then
+ MakeDir "${DestFile%/*}" || continue
+ fi
+ if [ $SourceMach != "$OpenMach" ]; then
+ OpenMachine $SourceMach
+ OpenMach=$SourceMach
+ fi
+ # If source filename has wildcards ([, ], *, ?) do an mget
+ case "$SourceFile" in
+ \[*\]|*\**|*\?*)
+ verboseprint lcd "$DestFile"
+ verboseprint mget "$SourceFile"
+ verboseprint lcd $OWD ;;
+ *) verboseprint get "$SourceFile" "$DestFile" ;;
+ esac
+ else
+ echo "Neither source machine \"$SourceMach\" "\
+"nor destination machine \"$DestMach\" is local." 1>&2
+ fi
+ let i+=1
+ done
+}
+
+# Start of main program
+name=${0##*/}
+
+if [ "$1" = -h ]; then
+ echo \
+"$name: do ftp transfers using rcp-style parameters.
+Usage: $name <source> <destpath> or $name <source> [<source> ...] <destdir>
+At least one of <source> and <destpath> must be the local system.
+A remote filename is given as machinename:filename
+If remote filenames contain wildcards, they will be globbed on the remote
+machine. Make sure they are quoted when $name is invoked.
+If the invoking user's .netrc file (see ftp(TC)) contains an entry for the
+remote system with a login and password supplied, $name will log in using
+the given login and password. If not, $name will login in as user
+anonymous and with the user@localsystem as the password.
+Options:
+-c: check: do not overwrite files.
+-d: create directories as needed.
+-f: force: overwrite files (default).
+-h: print this help.
+-l: fail if there is no entry with login and password for the remote system,
+ instead of logging in as anonymous.
+-n: log in as anonymous even if there is an entry for the remote system in
+ the user's .netrc file.
+-r: read source/dest filename pairs from the standard input,
+ one pair per line, and copy files accordingly."
+ exit 0
+fi
+
+typeset -i check=0 createdirs=0 readinput=0 anon=0 noanon=0
+
+while getopts :cdflnr Option
+do
+ case "$Option" in
+ c) check=1;;
+ d) createdirs=1;;
+ f) check=0;;
+ l) noanon=1;;
+ n) anon=1;;
+ r) readinput=1;;
+ \?) echo "$OPTARG: invalid option."; exit 1;;
+ esac
+done
+
+shift $((OPTIND-1))
+
+LocalMach=`hostname`
+
+if istrue $readinput; then
+ while read line; do
+ CopyFiles $line
+ done | $FTP -nv
+else
+ if [ $# -lt 2 ]; then
+ echo "$name: Not enough arguments. Use -h for help." 1>&2
+ exit
+ fi
+ CopyFiles "$@" | $FTP -nv
+fi
diff --git a/examples/scripts.v2/lowercase b/examples/scripts.v2/lowercase
new file mode 100644
index 0000000..fd2ec5d
--- /dev/null
+++ b/examples/scripts.v2/lowercase
@@ -0,0 +1,44 @@
+#! /bin/bash
+#
+# original from
+# @(#) lowercase.ksh 1.0 92/10/08
+# 92/10/08 john h. dubois iii (john@armory.com)
+#
+# conversion to bash v2 syntax done by Chet Ramey
+
+Usage="Usage: $name file ..."
+phelp()
+{
+echo "$name: change filenames to lower case.
+$Usage
+Each file is moved to a name with the same directory component, if any,
+and with a filename component that is the same as the original but with
+any upper case letters changed to lower case."
+}
+
+name=${0##*/}
+
+while getopts "h" opt; do
+ case "$opt" in
+ h) phelp; exit 0;;
+ *) echo "$Usage" 1>&2; exit 2;;
+ esac
+done
+
+shift $((OPTIND - 1))
+
+for file; do
+ filename=${file##*/}
+ case "$file" in
+ */*) dirname=${file%/*} ;;
+ *) dirname=. ;;
+ esac
+ nf=$(echo $filename | tr A-Z a-z)
+ newname="${dirname}/${nf}"
+ if [ "$nf" != "$filename" ]; then
+ mv "$file" "$newname"
+ echo "$0: $file -> $newname"
+ else
+ echo "$0: $file not changed."
+ fi
+done
diff --git a/examples/scripts.v2/ncp b/examples/scripts.v2/ncp
new file mode 100644
index 0000000..c91ba64
--- /dev/null
+++ b/examples/scripts.v2/ncp
@@ -0,0 +1,187 @@
+#! /bin/bash
+#
+# original from:
+# @(#) ncp.ksh,nmv.ksh 1.1 94/07/23
+# 92/01/18 john h. dubois iii (john@armory.com)
+# 92/01/31 added check for no args left after shifts
+# 92/02/17 added help
+# 92/02/25 remove path component from filename before tacking it onto dest.
+# 92/03/15 exec mv or cp
+# 93/07/13 Added -i
+# 93/09/29 Made abort if file exists optional.
+# 93/11/19 Exit before invoking mv if no files to move
+# 94/01/03 Added o option
+# 94/04/13 Added x option.
+# Fixed appending of source filename, broken by earlier change.
+# 94/07/23 Append only the filename part of the source path.
+#
+# conversion to bash v2 syntax done by Chet Ramey
+
+false()
+{
+ return 1
+}
+
+true()
+{
+ return 0
+}
+
+phelp()
+{
+echo "$name: do a $cmd with extra checking and options.
+$Usage
+$name is used as a front end for $cmd to get the [icfo] options, and so
+that a trailing / will force the last component of the path to be
+interpreted as a directory, so that $name foo bar/ will fail if bar is
+not an existing directory, instead of changing the name of foo to bar.
+Effectively, $name foo bar/ is short for $name foo bar/foo
+Options:
+-h prints this help.
+-c checks first for the existence of each file, and fails if it exists.
+-i is like -c except that if the file exists and stdin and stdout are a
+ tty, a query is printed and a reply is read; a file is overwritten only
+ if the reply begins with 'y'.
+-f unsets -c and -i (in case $cmd is aliased to $name).
+-o (overwrite only) checks that the named file(s) exist and fails for any
+ that do not. It is the complement of the -c option.
+Whichever of [cifo] comes later on the command line determines the behaviour.
+Any of these options must come before any standard $cmd options."
+}
+
+# interactive: Attempt to overwrite file should result in interactive
+# query rather than automatic failure.
+# noover: Do not overwrite files (if interactive is true, query, else fail)
+# overwrite: Only overwriting is allowed, not creation of new files.
+# debug: Print debugging info.
+typeset interactive=false noover=false overwrite=false debug=false
+name=${0##*/}
+
+case "$name" in
+ncp|nmv) cmd=/bin/${name#?} ;;
+*) echo "$name: Must be invoked as ncp or nmv." 1>&2 ; exit 2;;
+esac
+
+Usage="Usage: $name [-cfhio] $cmd-cmd-line"
+
+while getopts :cfhiox opt; do
+ case $opt in
+ h) phelp; exit 0;;
+ x) debug=true ;;
+ c) noover=true ;;
+ i) noover=true ; interactive=true ;;
+ f) noover=false ; interactive=false ;;
+ o) overwrite=true ; noover=false ; interactive=false;;
+ +?) echo "$name: options should not be preceded by a '+'." 1>&2; exit 2;;
+ ?) echo "$name: $OPTARG: bad option. Use -h for help." 1>&2 ; exit 2;;
+ esac
+done
+
+# remove args that were options
+shift $((OPTIND - 1))
+
+if [ $# -lt 2 ]; then
+ echo -e "$Usage\nUse -h for help."
+ exit
+fi
+
+Check()
+{
+ if [ ! -f "$1" ] && $overwrite; then
+ echo "$name: $1: File does not exist." 1>&2
+ return 1
+ elif [ -f "$1" ] && $noover; then
+ if [ $interactive = false ] || [ ! -t 0 ] || [ ! -t 1 ]; then
+ echo "$name: $1: File exists." 1>&2
+ return 1
+ else
+ while :; do
+ echo -n \
+"$name: $1: File exists. Overwrite? (y)es/(n)o/(a)bort/(Y)es for all: " 1>&2
+ read reply
+ case "$reply" in
+ y*)
+ echo "$name: Overwriting $1."
+ return 0
+ ;;
+ Y*)
+ echo "$name: Overwriting $1."
+ interactive=false
+ noover=false
+ return 0
+ ;;
+ [nN]*)
+ echo "$name: Skipping $2."
+ return 1
+ ;;
+ [aA]*)
+ echo "$name: Aborting."
+ exit 1
+ ;;
+ *)
+ echo "$name: Invalid response." 1>&2
+ ;;
+ esac
+ done
+ fi
+ else
+ return 0
+ fi
+}
+
+# i is the index of the filename being examined
+# lastarg is the index of the last filename before the dest directory name
+typeset -i i=0 lastarg=$(($#-1))
+
+# Sets argv[0..$#-1]
+argv=("$@")
+$debug && echo argv = "${argv[@]}" 1>&2
+dest=${argv[lastarg]}
+
+if $debug; then
+ echo \
+"interactive=$interactive noover=$noover overwrite=$overwrite debug=$debug
+lastarg=$lastarg dest=$dest name=$name cmd=$cmd
+files=$*" 1>&2
+fi
+
+if $noover || $overwrite; then
+ $debug && echo "checking for existance of directories..." 1>&2
+ # If the destination is not intended to be a directory...
+ if [ $# -eq 2 ] && [ ! -d "$dest" ]; then
+ Check "$dest" "$1" || exit 0 # No files to copy
+ else
+ while [ $i -lt $lastarg ]; do
+ Check "$dest/${argv[i]##*/}" "${argv[i]}" || unset argv[i]
+ let i+=1
+ done
+ fi
+fi
+
+[ ${#argv[@]} -lt 2 ] && exit 0
+
+# If only 2 args are given, mv/cp will not insist that the destination
+# be a directory, which we want if the destination ends in "/" or if
+# the original number of args was >2.
+# $# is still the original number of args.
+# Tack the file name onto the destination to force this behaviour.
+
+lastisslash()
+{
+ case "$1" in
+ */) return 0;;
+ *) return 1;;
+ esac
+}
+
+if [ ${#argv[@]} = 2 ] && { lastisslash "$2" || [ $# -gt 2 ]; }; then
+ $debug && echo "Appending filename." 1>&2
+ # Don't know which element of argv[] holds the source filename,
+ # since may have started with more than 1 source file & had some unset.
+ # So, compact args to make it easy to find the set one.
+ argv=("${argv[@]}")
+ argv[1]="${argv[1]}/${argv[0]##*/}"
+fi
+
+$debug && echo "Executing command: $cmd ${argv[@]}" 1>&2
+exec $cmd "${argv[@]}"
diff --git a/examples/scripts.v2/newext b/examples/scripts.v2/newext
new file mode 100644
index 0000000..37645bd
--- /dev/null
+++ b/examples/scripts.v2/newext
@@ -0,0 +1,64 @@
+#! /bin/bash
+#
+# original from:
+# newext: change filename extension
+# @(#) newext.sh 1.1 93/04/13
+# 90/06/06 john h. dubois iii (john@armory.com)
+# 90/11/14 changed ksh-specific code to hybrid: if running under Bourne,
+# uses expr instead of ksh builtin ops. Removed SYSV specific code.
+# 91/08/06 added -t option
+# 92/11/06 made earlier code actually work!
+# 93/04/13 If no filenames given, act on files in current dir
+#
+# conversion to bash v2 syntax by Chet Ramey
+
+usage="Usage: newext [-th] <oldext> <newext> [filename ...]"
+
+phelp()
+{
+echo "$usage
+Rename all given files that end in oldext with newext replacing oldext.
+If no filenames are given, all files in the current directory that end
+in oldext are acted on (no filename is equivalent to '*').
+Options:
+-h: Print this help.
+-t: Test: No action is taken except to print the mv commands that would
+be executed if -t was not given."
+}
+
+while getopts "th" opt; do
+ case "$opt" in
+ t) echo=echo;;
+ h) phelp; exit 0;;
+ *) echo "$usage" 1>&2; exit 2;;
+ esac
+done
+
+shift $((OPTIND - 1))
+
+oldext=$1
+newext=$2
+
+case $# in
+[01]) echo -e "$usage\nUse -h for help." 1>&2; exit 2;;
+2) shift ; shift; set -- *;;
+*) shift ; shift;;
+esac
+
+found=
+
+for file
+do
+ case "$file" in
+ *$oldext)
+ newname="${file%$oldext}$newext"
+ $echo mv "$file" "$newname"
+ found=true;;
+ esac
+done
+
+if [ -z "$found" ]; then
+ echo "No files ending in \"$oldext\"."
+ exit 1
+fi
+exit 0
diff --git a/examples/scripts.v2/nmv b/examples/scripts.v2/nmv
new file mode 100644
index 0000000..c91ba64
--- /dev/null
+++ b/examples/scripts.v2/nmv
@@ -0,0 +1,187 @@
+#! /bin/bash
+#
+# original from:
+# @(#) ncp.ksh,nmv.ksh 1.1 94/07/23
+# 92/01/18 john h. dubois iii (john@armory.com)
+# 92/01/31 added check for no args left after shifts
+# 92/02/17 added help
+# 92/02/25 remove path component from filename before tacking it onto dest.
+# 92/03/15 exec mv or cp
+# 93/07/13 Added -i
+# 93/09/29 Made abort if file exists optional.
+# 93/11/19 Exit before invoking mv if no files to move
+# 94/01/03 Added o option
+# 94/04/13 Added x option.
+# Fixed appending of source filename, broken by earlier change.
+# 94/07/23 Append only the filename part of the source path.
+#
+# conversion to bash v2 syntax done by Chet Ramey
+
+false()
+{
+ return 1
+}
+
+true()
+{
+ return 0
+}
+
+phelp()
+{
+echo "$name: do a $cmd with extra checking and options.
+$Usage
+$name is used as a front end for $cmd to get the [icfo] options, and so
+that a trailing / will force the last component of the path to be
+interpreted as a directory, so that $name foo bar/ will fail if bar is
+not an existing directory, instead of changing the name of foo to bar.
+Effectively, $name foo bar/ is short for $name foo bar/foo
+Options:
+-h prints this help.
+-c checks first for the existence of each file, and fails if it exists.
+-i is like -c except that if the file exists and stdin and stdout are a
+ tty, a query is printed and a reply is read; a file is overwritten only
+ if the reply begins with 'y'.
+-f unsets -c and -i (in case $cmd is aliased to $name).
+-o (overwrite only) checks that the named file(s) exist and fails for any
+ that do not. It is the complement of the -c option.
+Whichever of [cifo] comes later on the command line determines the behaviour.
+Any of these options must come before any standard $cmd options."
+}
+
+# interactive: Attempt to overwrite file should result in interactive
+# query rather than automatic failure.
+# noover: Do not overwrite files (if interactive is true, query, else fail)
+# overwrite: Only overwriting is allowed, not creation of new files.
+# debug: Print debugging info.
+typeset interactive=false noover=false overwrite=false debug=false
+name=${0##*/}
+
+case "$name" in
+ncp|nmv) cmd=/bin/${name#?} ;;
+*) echo "$name: Must be invoked as ncp or nmv." 1>&2 ; exit 2;;
+esac
+
+Usage="Usage: $name [-cfhio] $cmd-cmd-line"
+
+while getopts :cfhiox opt; do
+ case $opt in
+ h) phelp; exit 0;;
+ x) debug=true ;;
+ c) noover=true ;;
+ i) noover=true ; interactive=true ;;
+ f) noover=false ; interactive=false ;;
+ o) overwrite=true ; noover=false ; interactive=false;;
+ +?) echo "$name: options should not be preceded by a '+'." 1>&2; exit 2;;
+ ?) echo "$name: $OPTARG: bad option. Use -h for help." 1>&2 ; exit 2;;
+ esac
+done
+
+# remove args that were options
+shift $((OPTIND - 1))
+
+if [ $# -lt 2 ]; then
+ echo -e "$Usage\nUse -h for help."
+ exit
+fi
+
+Check()
+{
+ if [ ! -f "$1" ] && $overwrite; then
+ echo "$name: $1: File does not exist." 1>&2
+ return 1
+ elif [ -f "$1" ] && $noover; then
+ if [ $interactive = false ] || [ ! -t 0 ] || [ ! -t 1 ]; then
+ echo "$name: $1: File exists." 1>&2
+ return 1
+ else
+ while :; do
+ echo -n \
+"$name: $1: File exists. Overwrite? (y)es/(n)o/(a)bort/(Y)es for all: " 1>&2
+ read reply
+ case "$reply" in
+ y*)
+ echo "$name: Overwriting $1."
+ return 0
+ ;;
+ Y*)
+ echo "$name: Overwriting $1."
+ interactive=false
+ noover=false
+ return 0
+ ;;
+ [nN]*)
+ echo "$name: Skipping $2."
+ return 1
+ ;;
+ [aA]*)
+ echo "$name: Aborting."
+ exit 1
+ ;;
+ *)
+ echo "$name: Invalid response." 1>&2
+ ;;
+ esac
+ done
+ fi
+ else
+ return 0
+ fi
+}
+
+# i is the index of the filename being examined
+# lastarg is the index of the last filename before the dest directory name
+typeset -i i=0 lastarg=$(($#-1))
+
+# Sets argv[0..$#-1]
+argv=("$@")
+$debug && echo argv = "${argv[@]}" 1>&2
+dest=${argv[lastarg]}
+
+if $debug; then
+ echo \
+"interactive=$interactive noover=$noover overwrite=$overwrite debug=$debug
+lastarg=$lastarg dest=$dest name=$name cmd=$cmd
+files=$*" 1>&2
+fi
+
+if $noover || $overwrite; then
+ $debug && echo "checking for existance of directories..." 1>&2
+ # If the destination is not intended to be a directory...
+ if [ $# -eq 2 ] && [ ! -d "$dest" ]; then
+ Check "$dest" "$1" || exit 0 # No files to copy
+ else
+ while [ $i -lt $lastarg ]; do
+ Check "$dest/${argv[i]##*/}" "${argv[i]}" || unset argv[i]
+ let i+=1
+ done
+ fi
+fi
+
+[ ${#argv[@]} -lt 2 ] && exit 0
+
+# If only 2 args are given, mv/cp will not insist that the destination
+# be a directory, which we want if the destination ends in "/" or if
+# the original number of args was >2.
+# $# is still the original number of args.
+# Tack the file name onto the destination to force this behaviour.
+
+lastisslash()
+{
+ case "$1" in
+ */) return 0;;
+ *) return 1;;
+ esac
+}
+
+if [ ${#argv[@]} = 2 ] && { lastisslash "$2" || [ $# -gt 2 ]; }; then
+ $debug && echo "Appending filename." 1>&2
+ # Don't know which element of argv[] holds the source filename,
+ # since may have started with more than 1 source file & had some unset.
+ # So, compact args to make it easy to find the set one.
+ argv=("${argv[@]}")
+ argv[1]="${argv[1]}/${argv[0]##*/}"
+fi
+
+$debug && echo "Executing command: $cmd ${argv[@]}" 1>&2
+exec $cmd "${argv[@]}"
diff --git a/examples/scripts.v2/pages b/examples/scripts.v2/pages
new file mode 100644
index 0000000..66ebc5f
--- /dev/null
+++ b/examples/scripts.v2/pages
@@ -0,0 +1,187 @@
+#! /bin/bash
+#
+# original from:
+# @(#) pages.sh 1.0 92/09/26
+# 92/09/05 John H. DuBois III (jhdiii@armory.com)
+# 92/09/26 Added help
+#
+# conversion to bash v2 syntax by Chet Ramey
+
+Usage="$0 [-h] [-n lines/page] page-ranges [file ...]"
+
+usage()
+{
+ echo "$Usage" 1>&2
+}
+
+phelp()
+{
+echo "$0: print selected pages.
+Usage: $Usage
+
+If no file names are given, the standard input is read.
+
+The input is grouped into pages and a selected subset of them is printed.
+Formfeeds are acted on correctly.
+
+If the output device does automatic line wrap, lines that longer than
+the width of the output device will result in incorrect output.
+The first non-option argument is a list of pages to print.
+
+Pages are given as a list of ranges separated by commas.
+A range is either one number, two numbers separted by a dash,
+or one number followed by a dash. A range consisting of one
+number followed by a dash extends to the end of the document.
+
+Options:
+-n sets the number of lines per page to n. The default is 66."
+}
+
+while getopts "n:h" opt; do
+ case "$opt" in
+ n) LinesPerPage=$OPTARG;;
+ h) phelp; exit 0;;
+ *) usage; exit 2;;
+ esac
+done
+
+shift $(($OPTIND - 1))
+
+if [ $# -eq 0 ]; then
+ echo $0: no page ranges given. 1>&2
+ usage
+ exit 1
+fi
+
+PageList=$1
+shift
+
+gawk "
+BEGIN {
+ PageList = \"$PageList\"; LinesPerPage = \"$LinesPerPage\""'
+ if (LinesPerPage == "")
+ LinesPerPage = 66
+ else
+ if (LinesPerPage !~ "[1-9][0-9]*")
+ ErrExit("Bad value for lines per page: " LinesPerPage)
+ LinesPerPage += 0
+ NumRanges = split(PageList,Ranges,",")
+ for (i = 1; i <= NumRanges; i++) {
+ if ((StartRange = EndRange = Ranges[i]) !~ "^[0-9]+(-([0-9]+)?)?$")
+ ErrExit("Bad range \"" StartRange "\"")
+ sub("-.*","",StartRange)
+ sub(".*-","",EndRange)
+ if (EndRange == "")
+ EndRange = 2 ^ 30
+ # Force StartRange and EndRange to be numeric values
+ if ((StartRange += 0) == 0 || (EndRange += 0) == 0)
+ ErrExit("Invalid page number \"0\" in range " Ranges[i])
+ if (StartRange > EndRange)
+ ErrExit("Start page comes after end page in range " Ranges[i])
+ TmpRangeStarts[i] = StartRange
+ TmpRangeEnds[i] = EndRange
+ }
+
+ # Sort ranges
+ qsort(TmpRangeStarts,k)
+ RangeEnds[0] = 0
+ for (i = 1; i <= NumRanges; i++) {
+ RangeEnds[i] = TmpRangeEnds[k[i]]
+ if ((RangeStarts[i] = TmpRangeStarts[k[i]]) <= RangeEnds[i - 1])
+ ErrExit("Overlapping ranges: " Ranges[k[i]] "," Ranges[k[i - 1]])
+ }
+
+ RangeNum = LineNum = PageNum = 1
+ InRange = In(PageNum,RangeStarts[RangeNum],RangeEnds[RangeNum])
+ FS = "\014"
+}
+
+{
+ if (LineNum > LinesPerPage)
+ NewPage()
+ if (InRange)
+ printf "%s",$1
+ # Deal with formfeeds
+ for (i = 2; i <= NF; i++) {
+ if (InRange)
+ printf "\014"
+ NewPage()
+ if (InRange)
+ printf "%s",$i
+ }
+ if (InRange)
+ print ""
+ LineNum++
+}
+
+function NewPage() {
+ PageNum++
+ LineNum = 1
+ # At the start of each page, check whether we are in a print range
+ WereInRange = InRange
+ InRange = In(PageNum,RangeStarts[RangeNum],RangeEnds[RangeNum])
+ # If last page was in range and we no longer are, move to next range
+ if (WereInRange && !InRange && ++RangeNum > NumRanges)
+ exit
+}
+
+function In(a,Min,Max) {
+ return (Min <= a && a <= Max)
+}
+
+function ErrExit(S) {
+ print S > "/dev/stderr"
+ Err = 1
+ exit 1
+}
+
+# Arr is an array of values with arbitrary indices.
+# Array k is returned with numeric indices 1..n.
+# The values in k are the indices of array arr,
+# ordered so that if array arr is stepped through
+# in the order arr[k[1]] .. arr[k[n]], it will be stepped
+# through in order of the values of its elements.
+# The return value is the number of elements in the array (n).
+function qsort(arr,k, ArrInd,end) {
+ end = 0
+ for (ArrInd in arr)
+ k[++end] = ArrInd;
+ qsortseg(arr,k,1,end);
+ return end
+}
+
+function qsortseg(arr,k,start,end, left,right,sepval,tmp,tmpe,tmps) {
+ # handle two-element case explicitely for a tiny speedup
+ if ((end - start) == 1) {
+ if (arr[tmps = k[start]] > arr[tmpe = k[end]]) {
+ k[start] = tmpe
+ k[end] = tmps
+ }
+ return
+ }
+ left = start;
+ right = end;
+ sepval = arr[k[int((left + right) / 2)]]
+ # Make every element <= sepval be to the left of every element > sepval
+ while (left < right) {
+ while (arr[k[left]] < sepval)
+ left++
+ while (arr[k[right]] > sepval)
+ right--
+ if (left < right) {
+ tmp = k[left]
+ k[left++] = k[right]
+ k[right--] = tmp
+ }
+ }
+ if (left == right)
+ if (arr[k[left]] < sepval)
+ left++
+ else
+ right--
+ if (start < right)
+ qsortseg(arr,k,start,right)
+ if (left < end)
+ qsortseg(arr,k,left,end)
+}
+' "$@"
diff --git a/examples/scripts.v2/pf b/examples/scripts.v2/pf
new file mode 100644
index 0000000..ab6cd2c
--- /dev/null
+++ b/examples/scripts.v2/pf
@@ -0,0 +1,127 @@
+#! /bin/bash
+#
+# original from:
+#
+# @(#) p.ksh 1.1 93/11/09
+# p: page compressed & plain files in the order given
+# 92/01/23 john h. dubois iii (john@armory.com)
+# 92/02/14 changed incorrect zpack to pcat
+# 92/02/16 added help
+# 92/10/11 search for file.Z and file.z if file not found
+# 92/10/18 pass options to pager
+# 93/11/09 Understand gzipped files too
+# Wait after printing message about unreadable files
+# Make less prompt include name of file being uncompressed
+#
+# conversion to bash v2 by Chet Ramey; renamed to pf
+#
+DefPager=/local/bin/less
+
+istrue()
+{
+ test 0 -ne "$1"
+}
+
+warn()
+{
+ echo "$@" 1>&2
+}
+
+if [ "$1" = -h ]; then
+ echo \
+"$0: page a file.
+Usage: $0 [pager-option ...] [filename ...]
+Files are paged by the program specified in the user's PAGER
+environment variable, or by $DefPager if PAGER is not set.
+If no filename is given, text to page is read from the standard input.
+If filenames are given, they are either paged directly, or unpacked/
+uncompressed and then paged. Files are assumed to be in packed, compressed,
+or gzipped format if the filename ends in .Z, .z, or .gz respectively.
+If a filename that does not end in .Z, .z, or .gz is not found, it is
+searched for with one of those extensions attached.
+Each group of plain files is paged by a single instance of the pager.
+Each packed or compressed file is paged by a separate instance of the
+pager.
+Initial arguments beginning with + or - are taken to be pager options and
+are passed to each instance of the pager.
+If a pager option takes a value it should be given with the option as a
+single argument (with no space between the option and the value)."
+ exit 0
+fi
+
+# Get pager options
+while [ $# -gt 0 ]; do
+ case "$1" in
+ -*|+*) Opts="$Opts $1" ; shift;;
+ *) break;;
+ esac
+done
+
+[ -z "$PAGER" ] && PAGER=$DefPager
+
+# Read from stdin
+[ $# = 0 ] && exec $PAGER $Opts
+
+typeset -i filenum=0 badfile=0
+
+for file; do
+ if [ ! -r "$file" ]; then
+ case "$file" in
+ *.[Zz]|*.gz)
+ # Check if user specified a compressed file without giving its extension
+ for ext in Z z gz; do
+ if [ -r "$file.$ext" ]; then
+ file="$file.$ext"
+ break
+ fi
+ done;;
+ esac
+ fi
+ if [ ! -r "$file" ]; then
+ warn "$file: cannot read."
+ badfile=1
+ else
+ files[filenum]=$file
+ let filenum+=1
+ fi
+done
+
+if istrue $badfile && [ $filenum -gt 0 ]; then
+ echo -n "Press return to continue..." 1>&2
+ read
+fi
+
+unset plain
+
+for file in "${files[@]}"; do
+ case "$file" in
+ *.[zZ]|*.gz)
+ set -- Z zcat z pcat gz gzcat
+ # Find correct uncompression program
+ while [ $# -gt 0 ]; do
+ case "$file" in
+ *.$1)
+ # Page any uncompressed files so that they will be read
+ # in the correct order
+ [ ${#plain[@]} -gt 0 ] && $PAGER $Opts "${plain[@]}"
+ unset plain[*]
+ # If page is less, set the prompt to include the name of
+ # the file being uncompressed. Escape the . in the extension
+ # because less treats is specially in prompts (other dots
+ # in filenames will still be mucked with).
+ case "$PAGER" in
+ *less) Prompt="-P[${file%.$1}\\.$1] (%pb\\%)" ;;
+ *) unset Prompt ;;
+ esac
+ $2 "$file" | $PAGER "$Prompt" $Opts
+ break
+ esac
+ shift 2
+ done
+ ;;
+ *) plain[${#plain[@]}]=$file;;
+ esac
+done
+
+# Page any uncompressed files that haven't been paged yet
+[ ${#plain[@]} -gt 0 ] && exec $PAGER $Opts "${plain[@]}"
diff --git a/examples/scripts.v2/pmtop b/examples/scripts.v2/pmtop
new file mode 100644
index 0000000..cc419ac
--- /dev/null
+++ b/examples/scripts.v2/pmtop
@@ -0,0 +1,25 @@
+#! /bin/bash
+#
+# pmtop - poor man's `top' for SunOS 4.x
+#
+
+CLEAR=clear # could also be 'tput clear'
+HEADER="USER PID %CPU %MEM SZ RSS TT STAT START TIME COMMAND"
+
+if [ -n "$LINES" ]; then
+ SS=$(( $LINES - 2 ))
+else
+ SS=20
+fi
+
+while :
+do
+ $CLEAR
+ echo "$HEADER"
+ ps -aux | sort -nr -k 3 | sed ${SS}q
+ sleep 5
+done
+
+exit 0
+
+
diff --git a/examples/scripts.v2/ren b/examples/scripts.v2/ren
new file mode 100644
index 0000000..da76026
--- /dev/null
+++ b/examples/scripts.v2/ren
@@ -0,0 +1,585 @@
+#!/bin/bash
+#@ This program came from: ftp://ftp.armory.com/pub/scripts/ren
+#@ Look there for the latest version.
+#@ If you don't find it, look through http://www.armory.com/~ftp/
+#
+# @(#) ren 2.1.1 2002-03-17
+# 1990-06-01 John H. DuBois III (john@armory.com)
+# 1991-02-25 Improved help info
+# 1992-06-07 Remove quotes from around shell pattern as required by new ksh
+# 1994-05-10 Exit if no globbing chars given.
+# 1995-01-23 Allow filename set to be given on command line.
+# 1997-09-24 1.4 Let [] be used for globbing. Added x option.
+# 1997-11-26 1.4.1 Notice if the sequences of globbing chars aren't the same.
+# 1999-05-13 Changed name to ren to avoid conflict with /etc/rename
+# 2000-01-01 1.4.2 Let input patterns that contain whitespace be used.
+# 2001-02-14 1.5 Better test for whether old & new globbing seqs are identical.
+# 2001-02-20 1.6 Added pP options.
+# 2001-02-27 1.7 Added qf options. Improved interpretation of rename patterns.
+# 2001-05-10 1.8 Allow multiple pP options. Added Qr options.
+# 2001-07-25 2.0 Added mz options.
+# 2001-11-25 2.1 Allow segment ranges to be given with -m. Work under ksh93.
+# 2002-03-17 2.1.1 Fixed bug in test for legal expressions.
+
+# todo: It would be nice to be able to escape metacharacters with '\'
+# todo: Should enhance patterns to make ] in a pair of brackets work ([]])
+# todo: Allow use of all ksh globbing patterns.
+# todo: Allow use of extended regexps, with () to enumerate pieces and \num to
+# todo: select them.
+#
+# Modifications for bash made by Chet Ramey <chet@po.cwru.edu>
+
+name=${0##*/}
+Usage="Usage:
+$name [-fhqtv] [-m<segstart[:segend]=operation>] [-z<len>] [-[pP]<pattern>]
+ oldpattern [newpattern [filename ...]]
+or
+$name -r [same options as above] oldpattern newpattern directory ..."
+tell=false
+verbose=false
+warn=true
+warnNoFiles=true
+debug=false
+recurse=false
+inclPat=
+exclPat=
+declare -i inclCt=0 exclCt=0
+check=true
+declare -i j op_end_seg
+
+# Begin bash additions
+shopt -s extglob
+
+#
+# ksh print emulation
+#
+# print [-Rnprsu[n]] [-f format] [arg ...]
+#
+# - end of options
+# -R BSD-style -- only accept -n, no escapes
+# -n do not add trailing newline
+# -p no-op (no coprocesses)
+# -r no escapes
+# -s print to the history file
+# -u n redirect output to fd n
+# -f format printf "$format" "$@"
+#
+
+print()
+{
+ local eflag=-e
+ local nflag= fflag= c
+ local fd=1
+
+ OPTIND=1
+ while getopts "fRnprsu:" c
+ do
+ case $c in
+ R) eflag= ;;
+ r) eflag= ;;
+ n) nflag=-n ;;
+ s) sflag=y ;;
+ f) fflag=y ;;
+ u) fd=$OPTARG ;;
+ p) ;;
+ esac
+ done
+ shift $(( $OPTIND - 1 ))
+
+ if [ -n "$fflag" ]; then
+ builtin printf "$@" >&$fd
+ return
+ fi
+
+ case "$sflag" in
+ y) builtin history -s "$*" ;;
+ *) builtin echo $eflag $nflag "$@" >&$fd
+ esac
+}
+
+# End bash additions
+
+while getopts :htvxp:P:fqQrm:z: opt; do
+ case $opt in
+ h)
+ print -r -- \
+"$name: rename files by changing parts of filenames that match a pattern.
+$Usage
+oldpattern and newpattern are subsets of sh filename patterns; the only
+globbing operators (wildcards) allowed are ?, *, and []. All filenames that
+match oldpattern will be renamed with the filename characters that match the
+constant (non-globbing) characters of oldpattern changed to the corresponding
+constant characters of newpattern. The characters of the filename that match
+the globbing operators of oldpattern will be preserved. Globbing operators
+in oldpattern must occur in the same order in newpattern; for every globbing
+operators in newpattern there must be an identical globbing operators in
+oldpattern in the same sequence. Both arguments should be quoted since
+globbing operators are special to the shell. If filenames are given, only
+those named are acted on; if not, all filenames that match oldpattern are acted
+on. newpattern is required in all cases except when -m is given and no further
+arguments are given.
+If you are unsure whether a $name command will do what you intend, issue it
+with the -t option first to be sure.
+Examples:
+$name \"/tmp/foo*.ba.?\" \"/tmp/new*x?\"
+ All filenames in /tmp that match foo*.ba.? will have the \"foo\" part
+ replaced by \"new\" and the \".ba.\" part replaced by \"x\".
+ For example, /tmp/fooblah.ba.baz would be renamed to /tmp/newblahxbaz.
+$name \* \*- foo bar baz
+ foo, bar, and baz will be renamed to foo-, bar-, and baz-.
+$name '????????' '????-??-??'
+ All filenames that are 8 characters long will be changed such that dashes
+ are inserted after the 4th and 6th characters.
+Options:
+-h: Print this help.
+-r: Recursive operation. Filenames given on the command line after oldpattern
+ and newpattern are taken to be directories to traverse recursively. For
+ each subdirectory found, the specified renaming is applied to any matching
+ filenames. oldpattern and newpattern should not include any directory
+ components.
+-p<pattern>, -P<pattern>: Act only on filenames that do (if -p is given) or do
+ not (if -P is given) match the sh-style filename globbing pattern
+ <pattern>. This further restricts the filenames that are acted on, beyond
+ the filename selection produced by oldpattern and the filename list (if
+ any). <pattern> must be quoted to prevent it from being interpreted by the
+ shell. Multiple instances of these options may be given. In this case,
+ filenames are acted on only if they match at least one of the patterns
+ given with -p and do not match any of the patterns given with -P.
+-m<segstart[:segend]=operation>: For each file being renamed, perform a
+ mathematical operation on the string that results from concatenating
+ together the filename segments that matched globbing operator numbers
+ segstart through segend, where operators are numbered in order of
+ occurrence from the left. For example, in the pattern a?b*c[0-9]f, segment
+ 1 consists of the character that matched ?, segment 2 consists of the
+ character(s) that matched *, and segment 3 consists of the character that
+ matched [0-9]. The selected segments are replaced with the result of the
+ mathematical operation.
+ The concatenated string must consist of characters that can be interpreted
+ as a decimal integer; if it does not, the filename is not acted on. This
+ number is assigned to the variable 'i', which can be referenced by the
+ operation. The operations available are those understood by the ksh
+ interpreter, which includes most of the operators and syntax of the C
+ language. The original filename segment is replaced by the result of the
+ operation. If -m is used, newpattern may be an empty string or not given
+ at all (if no directory/file names are given). In this case, it is taken
+ to be the same as oldpattern.
+ If segend is given, any fixed text that occurs in the pattern between the
+ starting and ending globbing segments is discarded. If there are fewer
+ globbing segments than segend, no complaint is issued; the string is formed
+ from segment segstart through the last segment that does exist.
+ If segend is not given, the only segment acted on is startseg.
+ Examples:
+ $name -m3=i+6 '??*.ppm'
+ This is equivalent to:
+ $name -m3=i+6 '??*.ppm' '??*.ppm'
+ Since the old pattern and new pattern are identical, this would
+ normally be a no-op. But in this case, if a filename of ab079.ppm is
+ given, it is changed to ab85.ppm.
+ $name '-m1:2=i*2' 'foo??bar'
+ This will change a file named foo12bar to foo24bar
+ $name '-m1:2=i*2' 'foo?xyz?bar'
+ This will also change a file named foo1xyz2bar to foo24bar
+-z<len>: Set the size of the number fields that result when -m is used. The
+ field is truncated to the trailing <len> digits or filled out to <len>
+ digits with leading zeroes. In the above example, if -z3 is given, the
+ output filename will be ab085.ppm.
+-f: Force rename. By default, $name will not rename files if a file with the
+ new filename already exists. If -f is given, $name will carry out the
+ rename anyway.
+-q: Quiet operation. By default, if -f is given, $name will still notify the
+ user if a rename results in replacement of an already-existing filename.
+ If -q is given, no notification is issued.
+-Q: Suppress other warnings. By default, a warning is issued if no files are
+ selected for acting upon. If -Q is given, no warning is issued.
+-v: Show the rename commands being executed.
+-t: Show what rename commands would be done, but do not carry them out."
+ exit 0
+ ;;
+ f)
+ check=false
+ ;;
+ q)
+ warn=false
+ ;;
+ Q)
+ warnNoFiles=false
+ ;;
+ r)
+ warnNoFiles=false
+ recurse=true
+ ;;
+ t)
+ tell=true
+ ;;
+ v)
+ verbose=true
+ ;;
+ x)
+ verbose=true
+ debug=true
+ ;;
+ p)
+ inclPats[inclCt]=$OPTARG
+ ((inclCt+=1))
+ ;;
+ P)
+ exclPats[exclCt]=$OPTARG
+ ((exclCt+=1))
+ ;;
+ m)
+ # Store operation for each segment number in ops[num]
+ # Store ending segment number in op_end_seg[num]
+ range=${OPTARG%%=*}
+ op=${OPTARG#*=}
+ start=${range%%:*}
+ end=${range#*:}
+ if [[ "$start" != +([0-9]) || "$start" -eq 0 ]]; then
+ print -ru2 -- "$name: Bad starting segment number given with -m: $start"
+ exit 1
+ fi
+ if [[ "$end" != +([0-9]) || "$end" -eq 0 ]]; then
+ print -ru2 -- "$name: Bad ending segment number given with -m: $end"
+ exit 1
+ fi
+ if [[ start -gt end ]]; then
+ print -ru2 -- "$name: Ending segment ($end) is less than starting segment ($start)"
+ exit 1
+ fi
+ if [[ "$op" != @(|*[!_a-zA-Z0-9])i@(|[!_a-zA-Z0-9]*) ]]; then
+ print -ru2 -- \
+ "$name: Operation given with -m does not reference 'i': $op"
+ exit 1
+ fi
+ # Test whether operation is legal. let returns 1 both for error
+ # indication and when last expression evaluates to 0, so evaluate 1
+ # after test expression.
+ i=1
+ let "$op" 1 2>/dev/null || {
+ print -ru2 -- \
+ "$name: Bad operation given with -m: $op"
+ exit 1
+ }
+ ops[start]=$op
+ op_end_seg[start]=$end
+ ;;
+ z)
+ if [[ "$OPTARG" != +([0-9]) || "$OPTARG" -eq 0 ]]; then
+ print -ru2 -- "$name: Bad length given with -z: $OPTARG"
+ exit 1
+ fi
+ typeset -Z$OPTARG j || exit 1
+ ;;
+ +?) # no way to tell getopts to not treat +x as an option
+ print -r -u2 "$name: Do not prefix options with '+'."
+ exit 1
+ ;;
+ :)
+ print -r -u2 \
+"$name: Option -$OPTARG requires a value.
+$Usage
+Use -h for help."
+ exit 1
+ ;;
+ \?)
+ print -r -u2 \
+"$name: -$OPTARG: no such option.
+$Usage
+Use -h for help."
+ exit 1
+ ;;
+ esac
+done
+
+# remove args that were options
+let OPTIND=OPTIND-1
+shift $OPTIND
+
+oldpat=$1
+newpat=$2
+
+# If -m is given, a non-existant or null newpat should be set to oldpat
+if [ ${#ops[*]} -gt 0 ]; then
+ case $# in
+ 0)
+ ;;
+ 1)
+ set -- "$oldpat" "$oldpat"
+ newpat=$oldpat
+ $debug && print -ru2 -- "Set new pattern to: $newpat"
+ ;;
+ *)
+ if [ -z "$newpat" ]; then
+ shift 2
+ set -- "$oldpat" "$oldpat" "$@"
+ newpat=$oldpat
+ $debug && print -ru2 -- "Set new pattern to: $newpat"
+ fi
+ ;;
+ esac
+fi
+
+# Make sure input patterns that contain whitespace can be expanded properly
+IFS=
+
+origPat=$oldpat
+
+# Generate list of filenames to act on.
+case $# in
+[01])
+ print -u2 "$Usage\nUse -h for help."
+ exit 1
+ ;;
+2)
+ if $recurse; then
+ print -r -u2 "$name: No directory names given with -r. Use -h for help."
+ exit 1
+ fi
+ set -- $oldpat # Get list of all filenames that match 1st globbing pattern.
+ if [[ ! -a $1 ]]; then
+ $warnNoFiles && print -r -- "$name: No filenames match this pattern: $oldpat"
+ exit
+ fi
+ ;;
+*)
+ shift 2
+ ;;
+esac
+
+integer patSegNum=1 numPatSegs
+
+# For old ksh
+# while [[ "$oldpat" = *'[\*\?]'* ]]; do
+
+# Example oldpat: foo*.a
+# Example newpat: bar*.b
+
+# Build list of non-pattern segments and globbing segments found in arguments.
+# Note the patterns given are used to get the list of filenames to act on,
+# to delimit constant segments, and to determine which parts of filenames are
+# to be replaced.
+# Examples given for first iteration (in the example, the only iteration)
+# The || newpat is to ensure that new pattern does not have more globbing
+# segments than old pattern
+while [[ "$oldpat" = *@([\*\?]|\[+([!\]])\])* ||
+ "$newpat" = *@([\*\?]|\[+([!\]])\])* ]]; do
+ ## Get leftmost globbing pattern in oldpat
+
+ # Make r be oldpat with smallest left piece that includes a globbing
+ # pattern removed from it
+ r=${oldpat#*@([\*\?]|\[+([!\]])\])} # r=.a
+ # Make pat be oldpat with the above removed from it, leaving smallest
+ # left piece that includes a globbing pattern
+ pat=${oldpat%%"$r"} # pat=foo*
+ # Make l be pat with the globbing pattern removed from the right,
+ # leaving a constant string
+ l=${pat%@([\*\?]|\[+([!\]])\])} # l=foo
+ # Remove the constant part of pat from the left, leaving the globbing
+ # pattern
+ pat=${pat#"$l"} # pat=*
+
+ # Do the same thing for newpat, solely to provide a reliable test that
+ # both oldpat & newpat contain exactly the same sequence of globbing
+ # patterns.
+ r=${newpat#*@([\*\?]|\[+([!\]])\])} # r=.b
+ npat=${newpat%%"$r"} # pat=bar*
+ l=${npat%@([\*\?]|\[+([!\]])\])} # l=bar
+ npat=${npat#"$l"} # npat=*
+
+ if [[ "$pat" != "$npat" ]]; then
+ print -ru2 -- \
+"$name: Old-pattern and new-pattern do not have the same sequence of globbing chars.
+Pattern segment $patSegNum: Old pattern: $pat New pattern: $npat"
+ exit 1
+ fi
+
+ ## Find parts before & after pattern
+ # oldpre[] stores the old constant part before the pattern,
+ # so that it can be removed and replaced with the new constant part.
+ oldpre[patSegNum]=${oldpat%%"$pat"*} # oldpre[1]=foo
+ # oldsuf stores the part that follows the globbing pattern,
+ # so that it too can be removed.
+ # After oldpre[] & oldsuf[] have been removed from a filename, what remains
+ # is the part matched by the globbing pattern, which is to be retained.
+ oldsuf[patSegNum]=${oldpat#*"$pat"} # oldsuf[1]=.a
+ # newpre[] stores the new constant part before the pattern,
+ # so that it can be used to replace the old constant part.
+ newpre[patSegNum]=${newpat%%"$pat"*} # newpre[1]=bar
+ # Get rid of processed part of patterns
+ oldpat=${oldpat#${oldpre[patSegNum]}"$pat"} # oldpat=.a
+ newpat=${newpat#${newpre[patSegNum]}"$pat"} # newpat=.b
+ # Store either * or ? in pats[], depending on whether this segment matches 1
+ # or any number of characters.
+ [[ "$pat" = \[* ]] && pat=?
+ pats[patSegNum]=$pat
+ ((patSegNum+=1))
+done
+
+if [ patSegNum -eq 1 ]; then
+ print -u2 "No globbing chars in pattern."
+ exit 1
+fi
+
+oldpre[patSegNum]=${oldpat%%"$pat"*} # oldpre[2]=.a
+oldsuf[patSegNum]=${oldpat#*"$pat"} # oldsuf[2]=.a
+newpre[patSegNum]=${newpat%%"$pat"*} # newpre[2]=.b
+
+numPatSegs=patSegNum
+
+if $debug; then
+ patSegNum=1
+ while [[ patSegNum -le numPatSegs ]]; do
+ print -ru2 -- \
+"Old prefix: <${oldpre[patSegNum]}> Old suffix: <${oldsuf[patSegNum]}> New prefix: <${newpre[patSegNum]}> Pattern: <${pats[patSegNum]}>"
+ ((patSegNum+=1))
+ done
+fi
+
+# Example filename: foox.a
+# Example oldpat: foo*.a
+# Example newpat: bar*.b
+
+integer numFiles=0
+
+# Usage: renameFile filename [dirname]
+# [dirname] is a directory name to prefix filenames with when they are printed
+# for informational purposes.
+# Uses globals:
+# inclCt exclCt inclPats[] exclPats[] ops[]
+# numPatSegs oldpre[] oldsuf[] newpre[] pats[]
+# check warn tell verbose name
+# Modifies globals: numFiles
+function renameFile {
+ typeset file=$1 subdir=$2
+ integer patSegNum patnum
+ typeset origname porigname newfile matchtext pnewfile matchsegs
+ integer startseg endseg
+
+ origname=$file # origname=foox.a
+ porigname=$subdir$file
+ # Unfortunately, ksh88 does not do a good job of allowing for patterns
+ # stored in variables. Without the conditional expression being eval'ed,
+ # only sh patterns are recognized. If the expression is eval'ed, full
+ # ksh expressions can be used, but then expressions that contain whitespace
+ # break unless the user passed a pattern with the whitespace properly
+ # quoted, which is not intuititive. This is fixed in ksh93; full patterns
+ # work without being eval'ed.
+ if [ inclCt -gt 0 ]; then
+ patnum=0
+ while [ patnum -lt inclCt ]; do
+ [[ "$file" = ${inclPats[patnum]} ]] && break
+ ((patnum+=1))
+ done
+ if [ patnum -eq inclCt ]; then
+ $debug && print -ru2 -- "Skipping not-included filename '$porigname'"
+ return 1
+ fi
+ fi
+ patnum=0
+ while [ patnum -lt exclCt ]; do
+ if [[ "$file" = ${exclPats[patnum]} ]]; then
+ $debug && print -ru2 -- "Skipping excluded filename '$porigname'"
+ return 1
+ fi
+ ((patnum+=1))
+ done
+ # Extract matching segments from filename
+ ((numFiles+=1))
+ patSegNum=1
+ while [[ patSegNum -le numPatSegs ]]; do
+ # Remove a fixed prefix iteration: 1 2
+ file=${file#${oldpre[patSegNum]}} # file=x.a file=
+ # Save the part of this suffix that is to be retained. To do this, we
+ # need to know what part of the suffix matched the current globbing
+ # segment. If the globbing segment is a *, this is done by removing
+ # the minimum part of the suffix that matches oldsuf (since * matches
+ # the longest segment possible). If the globbing segment is ? or []
+ # (the latter has already been coverted to ?), it is done by taking the
+ # next character.
+ if [ "${pats[patSegNum]}" == \? ]; then
+ matchtext=${file#?}
+ matchtext=${file%$matchtext}
+ else
+ matchtext=${file%${oldsuf[patSegNum]}} # matchtext=x matchtext=
+ fi
+ $debug && print -ru2 -- "Matching segment $patSegNum: $matchtext"
+ file=${file#$matchtext} # file=.a file=.a
+
+ matchsegs[patSegNum]=$matchtext
+ ((patSegNum+=1))
+ done
+
+ # Paste fixed and matching segments together to form new filename.
+ patSegNum=0
+ newfile=
+ while [[ patSegNum -le numPatSegs ]]; do
+ matchtext=${matchsegs[patSegNum]}
+ startseg=patSegNum
+ if [ -n "${ops[startseg]}" ]; then
+ endseg=${op_end_seg[startseg]}
+ while [ patSegNum -lt endseg ]; do
+ ((patSegNum+=1))
+ matchtext=$matchtext${matchsegs[patSegNum]}
+ done
+ if [[ "$matchtext" != +([-0-9]) ]]; then
+ print -ru2 -- \
+"Segment(s) $startseg - $endseg ($matchtext) of file '$porigname' do not form an integer; skipping this file."
+ return 2
+ fi
+ i=$matchtext
+ let "j=${ops[startseg]}" || {
+ print -ru2 -- \
+"Operation failed on segment(s) $startseg - $endseg ($matchtext) of file '$file'; skipping this file."
+ return 2
+ }
+ $debug && print -ru2 -- "Converted $matchtext to $j"
+ matchtext=$j
+ fi
+ newfile=$newfile${newpre[startseg]}$matchtext # newfile=barx newfile=barx.b
+ ((patSegNum+=1))
+ done
+
+ pnewfile=$subdir$newfile
+ if $check && [ -e "$newfile" ]; then
+ $warn &&
+ print -ru2 -- "$name: Not renaming \"$porigname\"; destination filename \"$pnewfile\" already exists."
+ return 2
+ fi
+ if $tell; then
+ print -n -r -- "Would move: $porigname -> $pnewfile"
+ $warn && [ -e "$newfile" ] && print -n -r " (destination filename already exists; would replace it)"
+ print ""
+ else
+ if $verbose; then
+ print -n -r -- "Moving: $porigname -> $pnewfile"
+ $warn && [ -e "$newfile" ] && print -n -r -- " (replacing old destination filename \"$pnewfile\")"
+ print ""
+ elif $warn && [ -e "$newfile" ]; then
+ print -r -- "$name: Note: Replacing old file \"$pnewfile\""
+ fi
+ mv -f -- "$origname" "$newfile"
+ fi
+}
+
+if $recurse; then
+ oPWD=$PWD
+ find "$@" -depth -type d ! -name '*
+*' -print | while read dir; do
+ cd -- "$oPWD"
+ if cd -- "$dir"; then
+ for file in $origPat; do
+ renameFile "$file" "$dir/"
+ done
+ else
+ print -ru2 -- "$name: Could not access directory '$dir' - skipped."
+ fi
+ done
+else
+ for file; do
+ renameFile "$file"
+ done
+fi
+
+if [ numFiles -eq 0 ]; then
+ $warnNoFiles && print -ru2 -- \
+ "$name: All filenames were excluded by patterns given with -p or -P."
+fi
diff --git a/examples/scripts.v2/rename b/examples/scripts.v2/rename
new file mode 100644
index 0000000..96c46d6
--- /dev/null
+++ b/examples/scripts.v2/rename
@@ -0,0 +1,122 @@
+#! /bin/bash
+#
+# original from:
+# @(#) rename.ksh 1.1 94/05/10
+# 90/06/01 John DuBois (spcecdt@armory.com)
+# 91/02/25 Improved help info
+# 92/06/07 remove quotes from around shell pattern as required by new ksh
+# 94/05/10 Exit if no globbing chars given.
+#
+# conversion to bash v2 syntax by Chet Ramey
+
+phelp()
+{
+echo "$usage
+All files that match oldpattern will be renamed with the
+filename components that match the constant parts of oldpattern
+changed to the corresponding constant parts of newpattern.
+The components of the filename that match variable parts of
+oldpattern will be preserved. Variable parts in oldpattern
+must occur in the same order in newpattern. Variables parts
+can be '?' and '*'.
+Example:
+rename \"/tmp/foo*.ba.?\" \"/tmp/new*x?\"
+All files in /tmp that match foo*.ba.? will have the \"foo\" part
+replaced by \"new\" and the \".ba.\" part replaced by \"x\"."
+}
+
+usage="usage: $name [-htv] oldpattern newpattern"
+name=${0##/}
+
+while getopts "htv" opt; do
+ case "$opt" in
+ t) tell=true;;
+ v) verbose=true;;
+ h) phelp; exit 0;;
+ *) echo "$name: $usage" 1>&2; exit 2;;
+ esac
+done
+shift $((OPTIND - 1))
+
+if [ $# -lt 2 ]; then
+ phelp
+ exit 2
+fi
+
+oldpat=$1
+newpat=$2
+
+set -- $1
+if [ ! -e "$1" ]; then
+ echo "$name: no files match $oldpat."
+ exit 1
+fi
+
+typeset -i i=1 j
+
+# Example oldpat: foo*.a
+# Example newpat: bar*.b
+
+# Examples given for first iteration (in the example, the only interation)
+while :; do
+ case "$oldpat" in
+ *[\*\?]*) ;;
+ *) break;;
+ esac
+
+ # Get leftmost globbing pattern in oldpat
+ pat=${oldpat#*[\*\?]} # pat=.a
+ pat=${oldpat%%"$pat"} # pat=foo*
+ pat=${pat##*[!\?\*]} # pat=*
+ # Find parts before & after pattern
+ oldpre[i]=${oldpat%%"$pat"*} # oldpre[1]=foo
+ oldsuf[i]=${oldpat#*"$pat"} # oldsuf[1]=.a
+ newpre[i]=${newpat%%"$pat"*} # newpre[1]=bar
+ # Get rid of processed part of patterns
+ oldpat=${oldpat#${oldpre[i]}"$pat"} # oldpat=.a
+ newpat=${newpat#${newpre[i]}"$pat"} # newpat=.b
+ let i=i+1
+done
+
+if [ $i -eq 1 ]; then
+ echo "No globbing chars in pattern." 1>&2
+ exit 1
+fi
+
+oldpre[i]=${oldpat%%"$pat"*} # oldpre[2]=.a
+oldsuf[i]=${oldpat#*"$pat"} # oldsuf[2]=.a
+newpre[i]=${newpat%%"$pat"*} # newpre[2]=.b
+
+if [ -n "$verbose" ]; then
+ j=1
+ while let "j < i"; do
+ echo \
+"Old prefix: ${oldpre[j]} Old suffix: ${oldsuf[j]} New prefix: ${newpre[j]}"
+ let j=j+1
+ done
+fi
+
+# Example file: foox.a
+
+for file; do
+ j=1
+ origname=$file # origname=foox.a
+ newfile=
+ while let "j <= i"; do
+ # Peel off a prefix interation 1 2
+ file=${file#${oldpre[j]}} # file=x.a file=
+ # Save the part of this prefix that is to be retained
+ const=${file%${oldsuf[j]}} # const=x const=
+ newfile=$newfile${newpre[j]}$const # newfile=barx newfile=barx.b
+ file=${file#$const} # file=.a file=.a
+ let j=j+1
+ done
+ if [ -n "$tell" ]; then
+ echo "Would move \"$origname\" to \"$newfile\"."
+ else
+ if [ -n "$verbose" ]; then
+ echo "Moving \"$origname\" to \"$newfile\"."
+ fi
+ mv $origname $newfile
+ fi
+done
diff --git a/examples/scripts.v2/repeat b/examples/scripts.v2/repeat
new file mode 100644
index 0000000..b6fccac
--- /dev/null
+++ b/examples/scripts.v2/repeat
@@ -0,0 +1,121 @@
+#! /bin/bash
+#
+# original from:
+# repeat: repeat a command.
+# @(#) repeat.ksh 1.1 93/06/03
+# 90/05 john h. dubois iii (john@armory.com)
+# 90/11 added help
+# 93/06/03 Added s, h, p, and v options
+#
+# conversion to bash v2 syntax done by Chet Ramey
+
+istrue()
+{
+ test 0 -ne "$1"
+}
+
+isfalse()
+{
+ test 0 -eq "$1"
+}
+
+phelp()
+{
+echo "$name: repeatedly execute a command line.
+$Usage
+commandline is executed once for each integer from startcount through endcount
+inclusive. The default for startcount is 1 if a positive endcount or no
+endcount is given, and -1 if a negative endcount is given. A count
+parameter consisting of a single number is taken to be an endcount. If
+only an endcount is given and it is positive, commandline is executed
+endcount times. endcount may be less than startcount. If no endcount is
+given (e.g. a count parameter of \"10-\"), commandline execution repeats
+indefinitely with the iteration variable incrementing in a positive
+direction. A count parameter of consisting of \"-\" will repeat
+indefinitely starting with 1.
+
+Note that quoting and variables in commandline are interpreted twice, once
+when it is passed to the repeat command, and once when it is actually executed.
+
+The iteration variable is \"count\". If \$count is used in commandline, make
+sure it is quoted with ' or \.
+
+Options:
+-h: Print this help.
+-p: Print value of iteration variable on stderr before each iteration.
+-s <sec>: sleep for <sec> seconds after each iteration except the last.
+-v: Print start and end values before beginning."
+}
+
+name=${0##*/}
+Usage="Usage: repeat [-hpv] [-s <sec>] [[startcount]-][endcount] command [arg ...]"
+
+typeset -i count=1 forever=0 sleep=0 print=0 verbose=0
+
+while getopts :0123456789hpvs: opt; do
+ case $opt in
+ h) phelp; exit 0;;
+ s) sleep=$OPTARG || exit 1;;
+ p) print=1;;
+ v)verbose=1;;
+ [0-9]) break;;
+ +?) echo "$name: options should not be preceded by a '+'." 1>&2; exit 2;;
+ ?) echo "$name: $OPTARG: bad option. Use -h for help." 1>&2; exit 2;;
+ esac
+done
+
+# remove args that were options
+shift $((OPTIND-1))
+
+if [ $# -lt 2 ]; then
+ echo -e "$Usage\nUse -h for help." 1>&2
+ exit 2
+fi
+
+case "$1" in
+-[0-9]*-|[0-9]*-)
+ # Start value only
+ count=${1%-}
+ forever=1
+ end="-1";
+ ;;
+-[0-9]*-[0-9]*|[0-9]*-[0-9]*)
+ # Start and end value
+ s=${1%-}
+ end=${s##[0-9]*-}
+ count=${s%-$end}
+ ;;
+-[0-9]*|[0-9]*)
+ end=$1
+ case "$end" in
+ -\*) count=-1;;
+ esac
+ ;;
+-)
+ forever=1
+ end="-1";
+ ;;
+*)
+ echo "$name: bad count parameter: $1" 1>&2
+ exit 1
+ ;;
+esac
+
+shift
+
+[ -z "$end" ] && [ $count -le "$end" ] && increment=1 || increment=-1
+
+istrue $verbose && echo "start=$count end=$end" 1>&2
+
+# Need to do this here so that up to this point, -0 will keep the leading -
+# and end will not be 0 if no value assigned
+typeset -i end
+
+let end+=increment # make loop inclusive of original endcount
+
+while istrue $forever || [ $count -ne $end ]; do
+ istrue $print && echo $count 1>&2
+ eval "$@"
+ istrue $sleep && sleep $sleep
+ let count+=increment
+done
diff --git a/examples/scripts.v2/shprof b/examples/scripts.v2/shprof
new file mode 100644
index 0000000..73a1bb9
--- /dev/null
+++ b/examples/scripts.v2/shprof
@@ -0,0 +1,66 @@
+#! /bin/bash
+#
+# shprof - a line profiler for shell scripts
+#
+# adapted from a similar program included in `The New KornShell' by
+# Bolsky and Korn and posted to usenet by bsh20858@challenger.fhda.edu
+#
+# converted to bash v2 syntax by Chet Ramey
+#
+TMPFILE=${TMP:-/tmp}/shprof$$
+
+trap 'rm -f $TMPFILE' EXIT
+
+errexit()
+{
+ echo $0: "$@" >&2
+ exit 1
+}
+
+# create script with profiling enabled
+cat > $TMPFILE <<- \_EOF_
+ declare -a _line
+ _profend()
+ {
+ case "$1" in
+ /*|./*) file="$1" ;;
+ *) file=$(type -path "$1") ;;
+ esac
+
+ echo "*** line profile for $file ***"
+ i=1;
+ while read -r && [ $i -le $NLINE ]; do
+ count=${_line[$i]}
+ if [ "$count" -gt 0 ]; then
+ echo "[$count] $i: $REPLY"
+ fi
+ i=$((i + 1))
+ done <$file
+_EOF_
+# make the profiling script remove itself after printing line stats
+echo "rm -f $TMPFILE" >> $TMPFILE
+cat >> $TMPFILE <<- \_EOF_
+ }
+ _command=$1
+ shift
+ i=1
+ NLINE=$(wc -l < "$_command")
+ while [ $i -le $NLINE ]; do
+ _line[$i]=0
+ i=$((i + 1))
+ done
+ unset i
+ trap "_profend ${_command}" EXIT
+ trap '_line[$LINENO]=$((${_line[$LINENO]} + 1))' DEBUG
+ LINENO=0
+_EOF_
+
+case "$1" in
+/*|./*) file=$1 ;;
+*) file=$((type -path "$1")) ;;
+esac
+
+cat "${file-$1}" >> $TMPFILE || errexit "${1}: cannot open"
+chmod +x $TMPFILE
+
+exec -a "$file" $TMPFILE "$@"
diff --git a/examples/scripts.v2/untar b/examples/scripts.v2/untar
new file mode 100644
index 0000000..1ba6b6b
--- /dev/null
+++ b/examples/scripts.v2/untar
@@ -0,0 +1,80 @@
+#! /bin/bash
+#
+# original from:
+# @(#) untar.ksh 1.0 93/11/10
+# 92/10/08 john h. dubois iii (john@armory.com)
+# 92/10/31 make it actually work if archive isn't in current dir!
+# 93/11/10 Added pack and gzip archive support
+#
+# conversion to bash v2 syntax done by Chet Ramey
+
+phelp()
+{
+echo \
+"$name: extract tar archives into directories, uncompressing if neccessary.
+Usage: $name archive[.tar[.[Z|gz]]] ..
+If an archive name given does not end in .tar, .tar.Z, or .tar.gz, it is
+searched for first with .tar added, then .tar.Z, and then .tar.gz added.
+The real filename must end in either .tar, .tar.Z, or .tar.gz. A
+directory with the name of the archive is created in the current directory
+(not necessarily the directory that the archive is in) if it does not
+exist, and the the contents of the archive are extracted into it.
+Absolute pathnames in tarfiles are suppressed."
+}
+
+if [ $# -eq 0 ]; then
+ phelp
+ exit 1
+fi
+
+name=${0##/}
+OWD=$PWD
+
+for file; do
+ cd $OWD
+ case "$file" in
+ *.tar.Z) ArchiveName=${file%%.tar.Z} zcat=zcat;;
+ *.tar.z) ArchiveName=${file%%.tar.z} zcat=pcat;;
+ *.tar.gz) ArchiveName=${file%%.tar.gz} zcat=gzcat;;
+ *) ArchiveName=$file
+ for ext in "" .Z .z .gz; do
+ if [ -f "$file.tar$ext" ]; then
+ file="$file.tar$ext"
+ break
+ fi
+ done
+ if [ ! -f "$file" ]; then
+ echo "$file: cannot find archive." 1>&2
+ continue
+ fi
+ ;;
+ esac
+ if [ ! -r "$file" ]; then
+ echo "$file: cannot read." >&2
+ continue
+ fi
+ DirName=${ArchiveName##*/}
+ [ -d "$DirName" ] || {
+ mkdir "$DirName" || {
+ echo "$DirName: could not make archive directory." 1>&2
+ continue
+ }
+ }
+
+ cd $DirName || {
+ echo "$name: cannot cd to $DirName" 1>&2
+ continue
+ }
+
+ case "$file" in
+ /*) ;;
+ *) file=$OWD/$file ;;
+ esac
+
+ echo "Extracting archive $file into directory $DirName..."
+ case "$file" in
+ *.tar.Z|*.tar.z|*.tar.gz) $zcat $file | tar xvf -;;
+ *.tar) tar xvf $file;;
+ esac
+ echo "Done extracting archive $file into directory $DirName."
+done
diff --git a/examples/scripts.v2/uudec b/examples/scripts.v2/uudec
new file mode 100644
index 0000000..7984058
--- /dev/null
+++ b/examples/scripts.v2/uudec
@@ -0,0 +1,45 @@
+:
+# @(#) uudec.sh 1.0 93/11/22
+# 92/08/04 john@armory.com (John H. DuBois III)
+# 93/11/22 Added help.
+
+isfalse()
+{
+ test 0 -eq "$1"
+}
+
+phelp()
+{
+"$name: process uuencoded files.
+Usage: uudec [-h] filename ...
+Options:
+-h: Print this help."
+}
+
+name=${0##*/}
+
+typeset -i force=0
+
+while getopts "hf" opt; do
+ case "$opt" in
+ h) phelp; exit 0;;
+ f) force=1;;
+ *) echo "$Usage" 1>&2; exit 2;;
+ esac
+done
+
+shift $((OPTIND - 1))
+
+for file; do
+ echo "$file"
+ while read b mode filename && [ "$b" != begin ]; do :; done < "$file"
+ if [ "$b" = begin ]; then
+ if [ -f "$filename" ] && isfalse $force; then
+ echo "Output file \"$filename\" exists. Not written."
+ else
+ uudecode "$file"
+ fi
+ else
+ echo "No begin line."
+ fi
+done
diff --git a/examples/scripts.v2/uuenc b/examples/scripts.v2/uuenc
new file mode 100644
index 0000000..480aa48
--- /dev/null
+++ b/examples/scripts.v2/uuenc
@@ -0,0 +1,69 @@
+#! /bin/bash
+#
+# original from:
+# @(#) uuenc.ksh 1.0 93/09/18
+# 93/09/18 john h. dubois iii (john@armory.com)
+#
+# conversion to bash v2 syntax by Chet Ramey
+
+istrue()
+{
+ test 0 -ne "$1"
+}
+
+isfalse()
+{
+ test 0 -eq "$1"
+}
+
+phelp()
+{
+echo "$name: uuencode files.
+$Usage
+For each filename given, $name uuencodes the file, using the final
+component of the file's path as the stored filename in the uuencoded
+archive and, with a .${SUF} appended, as the name to store the archive in.
+Example:
+$name /tmp/foo
+The file /tmp/foo is uuencoded, with \"foo\" stored as the name to uudecode
+the file into, and the output is stored in a file in the current directory
+with the name \"foo.${SUF}\".
+Options:
+-f: Normally, if the file the output would be stored in already exists,
+ it is not overwritten and an error message is printed. If -f (force)
+ is given, it is silently overwritten.
+-h: Print this help."
+}
+
+name=${0##*/}
+Usage="Usage: $name [-hf] <filename> ..."
+typeset -i force=0
+
+SUF=uu
+
+while getopts :hf opt; do
+ case $opt in
+ h) phelp; exit 0;;
+ f) force=1;;
+ +?) echo "$name: options should not be preceded by a '+'." 1>&2 ; exit 2;;
+ ?) echo "$name: $OPTARG: bad option. Use -h for help." 1>&2 ; exit 2;;
+ esac
+done
+
+# remove args that were options
+shift $((OPTIND - 1))
+
+if [ $# -lt 1 ]; then
+ echo "$Usage\nUse -h for help." 1>&2
+ exit
+fi
+
+for file; do
+ tail=${file##*/}
+ out="$tail.${SUF}"
+ if isfalse $force && [ -a "$out" ]; then
+ echo "$name: $out: file exists. Use -f to overwrite." 1>&2
+ else
+ uuencode $file $tail > $out
+ fi
+done
diff --git a/examples/scripts.v2/vtree b/examples/scripts.v2/vtree
new file mode 100644
index 0000000..7523cc8
--- /dev/null
+++ b/examples/scripts.v2/vtree
@@ -0,0 +1,137 @@
+#! /bin/bash
+#
+# original from:
+# vtree: visual directory tree
+# @(#) vtree.sh 1.1 91/07/01
+# 90/04 john h. dubois iii (john@armory.com)
+# 91/07/01 fixed bug that caused problems when dir given on command line,
+# added some info to help, changed to 4-space indenting
+#
+# conversion to bash v2 syntax done by Chet Ramey
+#
+help=\
+"Syntax: vtree [startdir] [namelen=#] [linelen=#]
+If startdir is not specified, tree will start at current dir.
+
+namelen specifies the minimum number of characters of a directory name that
+are guaranteed to be printed.
+This is a tradeoff between the number of tree levels that can fit on a
+screen line and the number of chars of each dir name that can be printed.
+In most cases it will be possible to print more than namelen characters of
+the name (a name up to namelen+1 chars will always be printed in full),
+but in some cases truncation down to namelen chars will occur.
+If truncation occurs, a '>' is printed at the end of the name.
+namelen=8 (the default) typically causes about 5 dirs/1000 to be truncated.
+namelen=7 typically causes about 10 dirs/1000 to be truncated.
+namelen=8 will allow 6 full length dirs to be printed in 79 columns.
+namelen=7 will allow 7 full length dirs to be printed in 79 columns;
+
+linelen specifies the maximum number of characters to print on one screen
+line. All characters beyond this are truncated. The default is 1024.
+To avoid line wrap on an 80 column terminal with autowrap, use linelen=79.
+"
+
+for i in "$@"; do
+ case $i in
+ -h) echo "$help"; exit;;
+ *=*)
+ vars="$vars $i"
+ ;;
+ *)
+ if [ ! -x $i ] || [ ! -d $i ]; then # arg must be a dir and executable
+ echo "$i: directory not accessible."
+ exit
+ fi
+ cd $i
+ ;;
+ esac
+ shift
+done
+
+pwd # print path of root of tree
+
+# find all directories depth first; ignore permission errors
+find . -type d -print 2> /dev/null | \
+gawk -F/ '
+
+# Do this block for NR == 1 instead of BEGIN because command line var
+# assignments are not done until after BEGIN block is executed.
+NR == 1 {
+ if (namelen)
+ MaxLen = namelen;
+ else
+ MaxLen = 8;
+ if (!linelen)
+ linelen = 1024
+ HSpace = substr(" ",1,MaxLen); # used to indent tree
+ n = 0; # number of dirs found on one major branch
+}
+
+$0 != "." { # do for every line produced by find except tree root dir
+ if (NF == 2 && n > 0) # print major branch whenever a new one starts
+ list();
+ Depth[n] = NF - 1; # record depth and name of dir
+ Name[n++] = $NF;
+}
+
+END {
+ list() # print last major branch
+}
+
+function list() {
+ Line = Name[0]; # initialize first line of branch to be branch base
+ for (i = 1; i < n; i++) { # for each name in major branch
+ if (Depth[i] == Depth[i-1] + 1)
+ AddHLink(); # if moving deeper into branch, use same line
+ else {
+ print substr(Line,1,linelen); # last line is done; print it
+ Line = ""; # start new line
+ # print indentation, vert links, and vert/horiz links
+ for (d = 1; d < Depth[i] - 1; d++) # for each level of indentation
+ # if a vert. link has been established for this level
+ if (VLink[d])
+ Line = Line HSpace " | ";
+ else # print empty indentation
+ Line = Line HSpace " ";
+ # Print last part of vert. link
+ if (VLink[d] == i) {
+ VLink[d] = 0; # mark level for no vert link
+ Line = Line HSpace " \\--";
+ }
+ else
+ Line = Line HSpace " |--";
+ }
+ Line = Line Name[i]; # Add dir name to line
+ }
+ print substr(Line,1,linelen); # print last line of major branch
+ n = 0; # reset name counter
+}
+
+function AddHLink() {
+ NDepth = Depth[i]; # Depth of this name
+ VLink[NDepth - 1] = 0;
+ # search until a name found at a level less than this one
+ for (j = i + 1; j < n && Depth[j] >= NDepth; j++)
+ # keep track of last name that VLink should connect to
+ if (Depth[j] == NDepth)
+ VLink[NDepth - 1] = j;
+ if (VLink[NDepth - 1]) {
+ NLine = substr(Line,1,(NDepth - 2) * (MaxLen + 4) + MaxLen + 1);
+ if (length(NLine) < length(Line))
+ Line = substr(NLine,1,length(NLine) - 1) ">"
+ else
+ Line = NLine;
+ Line = Line substr("--------------+--",
+ 18 - ((NDepth - 1) * (MaxLen + 4) - length(Line)));
+ }
+ else {
+ NLine = substr(Line,1,(NDepth - 2) * (MaxLen + 4) + MaxLen + 3);
+ if (length(NLine) < length(Line))
+ Line = substr(NLine,1,length(NLine) - 1) ">"
+ else
+ Line = NLine;
+ Line = Line substr("-----------------",
+ 1,(NDepth - 1) * (MaxLen + 4) - length(Line));
+ }
+}
+' $vars
diff --git a/examples/scripts.v2/where b/examples/scripts.v2/where
new file mode 100644
index 0000000..7a1dbde
--- /dev/null
+++ b/examples/scripts.v2/where
@@ -0,0 +1,111 @@
+#! /bin/bash
+#
+# original from:
+# @(#) where.ksh 1.1 94/07/11
+# 91/01/12 john h. dubois iii (john@armory.com)
+# 92/08/10 Only print executable *files*.
+# 92/10/06 Print err msg if no match found.
+# 92/11/27 Added implicit *
+# 93/07/23 Print help only if -h is given.
+# 94/01/01 Added -x option
+# 94/07/11 Don't bother with eval
+#
+# conversion to bash v2 syntax done by Chet Ramey
+
+name=${0##*/}
+Usage="Usage: $name [-hx] 'pattern' ..."
+typeset -i exact=0
+
+phelp()
+{
+echo "$name: find executable files in PATH that match patterns.
+$Usage
+$name searches each directory specified in the PATH environment variable
+for executable files that match the specified patterns. Patterns are
+given as Korn shell filename patterns. They are surrounded by implicit
+'*' characters, so that \"foo\" will match any executble file whose name
+contains contains \"foo\". This can be overridden by using '^' and '$' to
+force a match to start at the beginning and end at the end of a filename
+respectively. Characters that are special to the shell must generally
+be protected from the shell by surrounding them with quotes.
+Examples:
+$name foo
+lists all executable files in PATH that contain foo.
+$name '^b*sh$'
+lists all executable files in PATH that start with b and end with sh.
+An error message is printed if a no matching file is found for a pattern.
+Options:
+-h: Print this help.
+-x: Find exact matches only; equivalent to putting ^ and $ at the start
+ and end of each pattern."
+}
+
+istrue()
+{
+ test 0 -ne "$1"
+}
+
+isfalse()
+{
+ test 0 -eq "$1"
+}
+
+while getopts "xh" opt; do
+ case "$opt" in
+ x) exact=1;;
+ h) phelp ; exit 0;;
+ *) echo -e "$Usage\nUse -h for help." 1>&2; exit 2;;
+ esac
+done
+
+shift $((OPTIND-1))
+
+set +f # make sure filename globbing is on
+Args=("$@") # save args
+
+OIFS=$IFS
+IFS=: # Make PATH be split on :
+Paths=($PATH)
+IFS=$OIFS
+
+for arg in "${Args[@]}"; do
+
+ # get rid of leading ^
+ if istrue $exact; then
+ arg=${arg}
+ else
+ case "$arg" in
+ ^*) arg=${arg#?};;
+ *) arg="*$arg" ;; # Pattern is not anchored at start
+ esac
+ fi
+
+ # get rid of trailing $
+ if istrue $exact; then
+ arg="$arg"
+ else
+ case "$arg" in
+ *\$) arg=${arg%?} ;;
+ *) arg="$arg*" ;;
+ esac
+ fi
+
+ found=0 # Pattern not found yet
+ Patterns=
+ # Make a pattern for each element of PATH
+ for PathElem in "${Paths[@]}"; do
+ [ -z "$PathElem" ] && PathElem=.
+ Patterns="$Patterns $PathElem/$arg"
+ done
+
+ # Find all pattern matches that are executable regular files.
+ for file in $Patterns; do
+ if [ -x "$file" ] && [ -f "$file" ]; then
+ echo "$file"
+ found=1
+ fi
+ done
+ if [ $found = 0 ]; then
+ echo "$arg: not found." 1>&2
+ fi
+done