aboutsummaryrefslogtreecommitdiffstats
path: root/examples/functions
diff options
context:
space:
mode:
Diffstat (limited to 'examples/functions')
-rw-r--r--examples/functions/array-stuff103
-rw-r--r--examples/functions/array-to-string15
-rw-r--r--examples/functions/autoload111
-rw-r--r--examples/functions/autoload.v2192
-rw-r--r--examples/functions/autoload.v3125
-rw-r--r--examples/functions/basename23
-rw-r--r--examples/functions/basename243
-rw-r--r--examples/functions/coproc.bash108
-rw-r--r--examples/functions/coshell.README53
-rw-r--r--examples/functions/coshell.bash127
-rw-r--r--examples/functions/csh-compat48
-rw-r--r--examples/functions/dirfuncs142
-rw-r--r--examples/functions/dirname21
-rw-r--r--examples/functions/emptydir28
-rw-r--r--examples/functions/exitstat22
-rw-r--r--examples/functions/external50
-rw-r--r--examples/functions/fact13
-rw-r--r--examples/functions/fstty59
-rw-r--r--examples/functions/func27
-rw-r--r--examples/functions/gethtml35
-rw-r--r--examples/functions/getoptx.bash301
-rw-r--r--examples/functions/inetaddr60
-rw-r--r--examples/functions/inpath14
-rw-r--r--examples/functions/isnum.bash52
-rw-r--r--examples/functions/isnum222
-rw-r--r--examples/functions/isvalidip14
-rw-r--r--examples/functions/jdate.bash78
-rw-r--r--examples/functions/jj.bash12
-rw-r--r--examples/functions/keep62
-rw-r--r--examples/functions/ksh-cd35
-rw-r--r--examples/functions/ksh-compat-test40
-rw-r--r--examples/functions/kshenv228
-rw-r--r--examples/functions/login11
-rw-r--r--examples/functions/lowercase27
-rw-r--r--examples/functions/manpage129
-rw-r--r--examples/functions/mhfold16
-rw-r--r--examples/functions/notify.bash58
-rw-r--r--examples/functions/pathfuncs45
-rw-r--r--examples/functions/recurse63
-rw-r--r--examples/functions/repeat243
-rw-r--r--examples/functions/repeat312
-rw-r--r--examples/functions/seq29
-rw-r--r--examples/functions/seq237
-rw-r--r--examples/functions/shcat7
-rw-r--r--examples/functions/shcat219
-rw-r--r--examples/functions/sort-pos-params50
-rw-r--r--examples/functions/substr79
-rw-r--r--examples/functions/substr281
-rw-r--r--examples/functions/term35
-rw-r--r--examples/functions/whatis52
-rw-r--r--examples/functions/whence59
-rw-r--r--examples/functions/which44
-rw-r--r--examples/functions/xalias.bash22
-rw-r--r--examples/functions/xfind.bash52
54 files changed, 3233 insertions, 0 deletions
diff --git a/examples/functions/array-stuff b/examples/functions/array-stuff
new file mode 100644
index 0000000..97ed512
--- /dev/null
+++ b/examples/functions/array-stuff
@@ -0,0 +1,103 @@
+# usage: reverse arrayname
+reverse()
+{
+ local -a R
+ local -i i
+ local rlen temp
+
+ # make r a copy of the array whose name is passed as an arg
+ eval R=\( \"\$\{$1\[@\]\}\" \)
+
+ # reverse R
+ rlen=${#R[@]}
+
+ for ((i=0; i < rlen/2; i++ ))
+ do
+ temp=${R[i]}
+ R[i]=${R[rlen-i-1]}
+ R[rlen-i-1]=$temp
+ done
+
+ # and assign R back to array whose name is passed as an arg
+ eval $1=\( \"\$\{R\[@\]\}\" \)
+}
+
+A=(1 2 3 4 5 6 7)
+echo "${A[@]}"
+reverse A
+echo "${A[@]}"
+reverse A
+echo "${A[@]}"
+
+# unset last element of A
+alen=${#A[@]}
+unset A[$alen-1]
+echo "${A[@]}"
+
+# ashift -- like shift, but for arrays
+
+ashift()
+{
+ local -a R
+ local n
+
+ case $# in
+ 1) n=1 ;;
+ 2) n=$2 ;;
+ *) echo "$FUNCNAME: usage: $FUNCNAME array [count]" >&2
+ exit 2;;
+ esac
+
+ # make r a copy of the array whose name is passed as an arg
+ eval R=\( \"\$\{$1\[@\]\}\" \)
+
+ # shift R
+ R=( "${R[@]:$n}" )
+
+ # and assign R back to array whose name is passed as an arg
+ eval $1=\( \"\$\{R\[@\]\}\" \)
+}
+
+ashift A 2
+echo "${A[@]}"
+
+ashift A
+echo "${A[@]}"
+
+ashift A 7
+echo "${A[@]}"
+
+# Sort the members of the array whose name is passed as the first non-option
+# arg. If -u is the first arg, remove duplicate array members.
+array_sort()
+{
+ local -a R
+ local u
+
+ case "$1" in
+ -u) u=-u ; shift ;;
+ esac
+
+ if [ $# -eq 0 ]; then
+ echo "array_sort: argument expected" >&2
+ return 1
+ fi
+
+ # make r a copy of the array whose name is passed as an arg
+ eval R=\( \"\$\{$1\[@\]\}\" \)
+
+ # sort R
+ R=( $( printf "%s\n" "${A[@]}" | sort $u) )
+
+ # and assign R back to array whose name is passed as an arg
+ eval $1=\( \"\$\{R\[@\]\}\" \)
+ return 0
+}
+
+A=(3 1 4 1 5 9 2 6 5 3 2)
+array_sort A
+echo "${A[@]}"
+
+A=(3 1 4 1 5 9 2 6 5 3 2)
+array_sort -u A
+echo "${A[@]}"
diff --git a/examples/functions/array-to-string b/examples/functions/array-to-string
new file mode 100644
index 0000000..0d2fbe5
--- /dev/null
+++ b/examples/functions/array-to-string
@@ -0,0 +1,15 @@
+#! /bin/bash
+
+# Format: array_to_string vname_of_array vname_of_string separator
+array_to_string()
+{
+ (( ($# < 2) || ($# > 3) )) && {
+ "$FUNCNAME: usage: $FUNCNAME arrayname stringname [separator]"
+ return 2
+ }
+
+ local array=$1 string=$2
+ ((3==$#)) && [[ $3 = ? ]] && local IFS="${3}${IFS}"
+ eval $string="\"\${$array[*]}\""
+ return 0
+}
diff --git a/examples/functions/autoload b/examples/functions/autoload
new file mode 100644
index 0000000..a563a77
--- /dev/null
+++ b/examples/functions/autoload
@@ -0,0 +1,111 @@
+#
+# An almost ksh-compatible `autoload'. A function declared as `autoload' will
+# be read in from a file the same name as the function found by searching the
+# $FPATH (which works the same as $PATH), then that definition will be run.
+#
+# To do this without source support, we define a dummy function that, when
+# executed, will load the file (thereby re-defining the function), then
+# execute that newly-redefined function with the original arguments.
+#
+# It's not identical to ksh because ksh apparently does lazy evaluation
+# and looks for the file to load from only when the function is referenced.
+# This one requires that the file exist when the function is declared as
+# `autoload'.
+#
+# usage: autoload func [func...]
+#
+# The first cut of this was by Bill Trost, trost@reed.bitnet
+#
+# Chet Ramey
+# chet@ins.CWRU.Edu
+
+#
+# Declare a function ($1) to be autoloaded from a file ($2) when it is first
+# called. This defines a `temporary' function that will `.' the file
+# containg the real function definition, then execute that new definition with
+# the arguments given to this `fake' function. The autoload function defined
+# by the file and the file itself *must* be named identically.
+#
+
+aload()
+{
+ eval $1 '() { . '$2' ; '$1' "$@" ; return $? ; }'
+}
+
+#
+# Search $FPATH for a file the same name as the function given as $1, and
+# autoload the function from that file. There is no default $FPATH.
+#
+
+autoload()
+{
+ #
+ # Save the list of functions; we're going to blow away the arguments
+ # in a second. If any of the names contain white space, TFB.
+ #
+
+ local args="$*"
+
+ #
+ # This should, I think, list the functions marked as autoload and not
+ # yet defined, but we don't have enough information to do that here.
+ #
+ if [ $# -eq 0 ] ; then
+ echo "usage: autoload function [function...]" >&2
+ return 1
+ fi
+
+ #
+ # If there is no $FPATH, there is no work to be done
+ #
+
+ if [ -z "$FPATH" ] ; then
+ echo autoload: FPATH not set or null >&2
+ return 1
+ fi
+
+ #
+ # This treats FPATH exactly like PATH: a null field anywhere in the
+ # FPATH is treated the same as the current directory.
+ #
+ # The path splitting command is taken from Kernighan and Pike
+ #
+
+# fp=$(echo $FPATH | sed 's/^:/.:/
+# s/::/:.:/g
+# s/:$/:./
+# s/:/ /g')
+
+ # replaced with builtin mechanisms 2001 Oct 10
+
+ fp=${FPATH/#:/.:}
+ fp=${fp//::/:.:}
+ fp=${fp/%:/:.}
+ fp=${fp//:/ }
+
+ for FUNC in $args ; do
+ #
+ # We're blowing away the arguments to autoload here...
+ # We have to; there are no arrays (well, there are, but
+ # this doesn't use them yet).
+ #
+ set -- $fp
+
+ while [ $# -ne 0 ] ; do
+ if [ -f $1/$FUNC ] ; then
+ break # found it!
+ fi
+ shift
+ done
+
+ if [ $# -eq 0 ] ; then
+ echo "$FUNC: autoload function not found" >&2
+ continue
+ fi
+
+# echo auto-loading $FUNC from $1/$FUNC
+ aload $FUNC $1/$FUNC
+ done
+
+ return 0
+}
diff --git a/examples/functions/autoload.v2 b/examples/functions/autoload.v2
new file mode 100644
index 0000000..e8f3433
--- /dev/null
+++ b/examples/functions/autoload.v2
@@ -0,0 +1,192 @@
+#
+# An almost ksh-compatible `autoload'. A function declared as `autoload' will
+# be read in from a file the same name as the function found by searching the
+# $FPATH (which works the same as $PATH), then that definition will be run.
+#
+# To do this without source support, we define a dummy function that, when
+# executed, will load the file (thereby re-defining the function), then
+# execute that newly-redefined function with the original arguments.
+#
+# It's not identical to ksh because ksh apparently does lazy evaluation
+# and looks for the file to load from only when the function is referenced.
+# This one requires that the file exist when the function is declared as
+# `autoload'.
+#
+# usage: autoload [-pu] [func ...]
+#
+# options:
+# -p print in a format that can be reused as input
+# -u unset each function and remove it from the autoload list
+#
+# The first cut of this was by Bill Trost, trost@reed.edu
+#
+# Chet Ramey
+# chet@ins.CWRU.Edu
+
+unset _AUTOLOADS
+_aindex=0
+
+#
+# Declare a function ($1) to be autoloaded from a file ($2) when it is first
+# called. This defines a `temporary' function that will `.' the file
+# containg the real function definition, then execute that new definition with
+# the arguments given to this `fake' function. The autoload function defined
+# by the file and the file itself *must* be named identically.
+#
+
+_aload()
+{
+ eval $1 '() { . '$2' ; '$1' "$@" ; return $? ; }'
+ _autoload_addlist "$1"
+}
+
+_autoload_addlist()
+{
+ local i=0
+
+ while (( i < $_aindex )); do
+ case "${_AUTOLOADS[i]}" in
+ "$1") return 1 ;;
+ esac
+ (( i += 1 ))
+ done
+ _AUTOLOADS[_aindex]="$1"
+ (( _aindex += 1 ))
+ return 0
+}
+
+_autoload_dump()
+{
+ local func
+
+ for func in ${_AUTOLOADS[@]}; do
+ [ -n "$1" ] && echo -n "autoload "
+ echo "$func"
+ done
+}
+
+# Remove $1 from the list of autoloaded functions
+_autoload_remove_one()
+{
+ local i=0 nnl=0
+ local -a nlist
+
+ while (( i < _aindex )); do
+ case "${_AUTOLOADS[i]}" in
+ "$1") ;;
+ *) nlist[nnl]="${_AUTOLOADS[i]}" ; (( nnl += 1 ));;
+ esac
+ (( i += 1 ))
+ done
+ unset _AUTOLOADS _aindex
+ eval _AUTOLOADS=( ${nlist[@]} )
+ _aindex=$nnl
+}
+
+# Remove all function arguments from the list of autoloaded functions
+_autoload_remove()
+{
+ local func i es=0
+
+ # first unset the autoloaded functions
+ for func; do
+ i=0
+ while (( i < _aindex )); do
+ case "${_AUTOLOADS[i]}" in
+ "$func") unset -f $func ; break ;;
+ esac
+ (( i += 1 ))
+ done
+ if (( i == _aindex )); then
+ echo "autoload: $func: not an autoloaded function" >&2
+ es=1
+ fi
+ done
+
+ # then rebuild the list of autoloaded functions
+ for func ; do
+ _autoload_remove_one "$func"
+ done
+
+ return $es
+}
+
+#
+# Search $FPATH for a file the same name as the function given as $1, and
+# autoload the function from that file. There is no default $FPATH.
+#
+
+autoload()
+{
+ local -a fp
+ local _autoload_unset nfp i
+
+ if (( $# == 0 )) ; then
+ _autoload_dump
+ return 0
+ fi
+
+ OPTIND=1
+ while getopts pu opt
+ do
+ case "$opt" in
+ p) _autoload_dump printable; return 0;;
+ u) _autoload_unset=y ;;
+ *) echo "autoload: usage: autoload [-pu] [function ...]" >&2
+ return 1 ;;
+ esac
+ done
+
+ shift $(( $OPTIND - 1 ))
+
+ if [ -n "$_autoload_unset" ]; then
+ _autoload_remove "$@"
+ return $?
+ fi
+
+ #
+ # If there is no $FPATH, there is no work to be done
+ #
+
+ if [ -z "$FPATH" ] ; then
+ echo "autoload: FPATH not set or null" >&2
+ return 1
+ fi
+
+ #
+ # This treats FPATH exactly like PATH: a null field anywhere in the
+ # FPATH is treated the same as the current directory.
+ #
+ # This turns $FPATH into an array, substituting `.' for `'
+ #
+ eval fp=( $(
+ IFS=':'
+ set -- ${FPATH}
+ for p in "$@" ; do echo -n "${p:-.} "; done
+ )
+ )
+
+ nfp=${#fp[@]}
+
+ for FUNC ; do
+ i=0;
+ while (( i < nfp )) ; do
+ if [ -f ${fp[i]}/$FUNC ] ; then
+ break # found it!
+ fi
+ (( i += 1 ))
+ done
+
+ if (( i == nfp )) ; then
+ echo "autoload: $FUNC: autoload function not found" >&2
+ es=1
+ continue
+ fi
+
+# echo auto-loading $FUNC from ${fp[i]}/$FUNC
+ _aload $FUNC ${fp[i]}/$FUNC
+ es=0
+ done
+
+ return $es
+}
diff --git a/examples/functions/autoload.v3 b/examples/functions/autoload.v3
new file mode 100644
index 0000000..b1e5dfe
--- /dev/null
+++ b/examples/functions/autoload.v3
@@ -0,0 +1,125 @@
+#From: Mark Kennedy <mark.t.kennedy@gmail.com> (<mtk@ny.ubs.com>)
+#Message-ID: <35E2B899.63A02DF5@ny.ubs.com>
+#Date: Tue, 25 Aug 1998 09:14:01 -0400
+#To: chet@nike.ins.cwru.edu
+#Subject: a newer version of the ksh-style 'autoload'
+
+#enclosed you'll find 'autoload.v3', a version of the autoloader
+#that emulates the ksh semantics of delaying the resolution (and loading) of the function
+#until its first use. i took the liberty of simplifying the code a bit although it still uses the
+#same functional breakdown. i recently went through the exercise of converting
+#my ksh-based environment to bash (a very, very pleasant experience)
+#and this popped out.
+
+# the psuedo-ksh autoloader.
+
+# The first cut of this was by Bill Trost, trost@reed.bitnet.
+# The second cut came from Chet Ramey, chet@ins.CWRU.Edu
+# The third cut came from Mark Kennedy, mtk@ny.ubs.com. 1998/08/25
+
+unset _AUTOLOADS
+
+_aload()
+{
+ local func
+ for func; do
+ eval $func '()
+ {
+ local f=$(_autoload_resolve '$func')
+ if [[ $f ]]; then
+ . $f
+ '$func' "$@"
+ return $?
+ else
+ return 1
+ fi
+ }'
+ _autoload_addlist $func
+ done
+}
+
+_autoload_addlist()
+{
+ local func
+
+ for func in ${_AUTOLOADS[@]}; do
+ [[ $func = "$1" ]] && return
+ done
+
+ _AUTOLOADS[${#_AUTOLOADS[@]}]=$1
+}
+
+_autoload_dump()
+{
+ local func
+
+ for func in ${_AUTOLOADS[@]}; do
+ [[ $1 ]] && echo -n "autoload "
+ echo $func
+ done
+}
+
+_autoload_remove_one()
+{
+ local func
+ local -a NEW_AUTOLOADS
+
+ for func in ${_AUTOLOADS[@]}; do
+ [[ $func != "$1" ]] && NEW_AUTOLOADS[${#NEW_AUTOLOADS[@]}]=$func
+ done
+
+ _AUTOLOADS=( ${NEW_AUTOLOADS[@]} )
+}
+
+_autoload_remove()
+{
+ local victim func
+
+ for victim; do
+ for func in ${_AUTOLOADS[@]}; do
+ [[ $victim = "$func" ]] && unset -f $func && continue 2
+ done
+ echo "autoload: $func: not an autoloaded function" >&2
+ done
+
+ for func; do
+ _autoload_remove_one $func
+ done
+}
+
+_autoload_resolve()
+{
+ if [[ ! "$FPATH" ]]; then
+ echo "autoload: FPATH not set or null" >&2
+ return
+ fi
+
+ local p
+
+ for p in $( (IFS=':'; set -- ${FPATH}; echo "$@") ); do
+ p=${p:-.}
+ if [ -f $p/$1 ]; then echo $p/$1; return; fi
+ done
+
+ echo "autoload: $1: function source file not found" >&2
+}
+
+autoload()
+{
+ if (( $# == 0 )) ; then _autoload_dump; return; fi
+
+ local opt OPTIND
+
+ while getopts pu opt
+ do
+ case $opt in
+ p) _autoload_dump printable; return;;
+ u) shift $((OPTIND-1)); _autoload_remove "$@"; return;;
+ *) echo "autoload: usage: autoload [-pu] [function ...]" >&2; return;;
+ esac
+ done
+
+ shift $(($OPTIND-1))
+
+ _aload "$@"
+}
diff --git a/examples/functions/basename b/examples/functions/basename
new file mode 100644
index 0000000..a541349
--- /dev/null
+++ b/examples/functions/basename
@@ -0,0 +1,23 @@
+# Date: Fri, 11 Oct 91 11:22:36 edt
+# From: friedman@gnu.ai.mit.edu
+# To: bfox@gnu.ai.mit.edu
+
+# A replacement for basename(1). Not all the systems I use have this
+# program. Usage: basename [path] {extension}
+function basename ()
+{
+ local path="$1"
+ local suffix="$2"
+ local tpath="${path%/}"
+
+ # Strip trailing '/' characters from path (unusual that this should
+ # ever occur, but basename(1) seems to deal with it.)
+ while [ "${tpath}" != "${path}" ]; do
+ tpath="${path}"
+ path="${tpath%/}"
+ done
+
+ path="${path##*/}" # Strip off pathname
+ echo ${path%${suffix}} # Also strip off extension, if any.
+}
+
diff --git a/examples/functions/basename2 b/examples/functions/basename2
new file mode 100644
index 0000000..a42231c
--- /dev/null
+++ b/examples/functions/basename2
@@ -0,0 +1,43 @@
+#From: "Grigoriy Strokin" <grg@philol.msu.ru>
+#Newsgroups: comp.unix.shell
+#Subject: fast basename and dirname functions for BASH/SH
+#Date: Sat, 27 Dec 1997 21:18:40 +0300
+#
+#Please send your comments to grg@philol.msu.ru
+
+function basename()
+{
+ local name="${1##*/}"
+ echo "${name%$2}"
+}
+
+function dirname()
+{
+ local dir="${1%${1##*/}}"
+ [ "${dir:=./}" != "/" ] && dir="${dir%?}"
+ echo "$dir"
+}
+
+# Two additional functions:
+# 1) namename prints the basename without extension
+# 2) ext prints extension of a file, including "."
+
+function namename()
+{
+ local name=${1##*/}
+ local name0="${name%.*}"
+ echo "${name0:-$name}"
+}
+function ext()
+{
+ local name=${1##*/}
+ local name0="${name%.*}"
+ local ext=${name0:+${name#$name0}}
+ echo "${ext:-.}"
+}
+
+
+
+
+
+
diff --git a/examples/functions/coproc.bash b/examples/functions/coproc.bash
new file mode 100644
index 0000000..61dc8d7
--- /dev/null
+++ b/examples/functions/coproc.bash
@@ -0,0 +1,108 @@
+# coprocess.bash
+#
+# vi:set sts=2 sw=2 ai:
+#
+
+coprocess_pid=
+
+#
+# coprocess - Start, control, and end coprocesses.
+#
+function coprocess ()
+{
+ while (( $# > 0 )) ; do
+ case "$1" in
+ #
+ # coprocess close
+ #
+ c|cl|clo|clos|close)
+ shift
+ exec 61>&- 62<&-
+ coprocess_pid=
+ if [ "$1" = "-SIGPIPE" ] ; then
+ # Only print message in an interactive shell
+ case "$-" in
+ *i*)
+ echo 'SIGPIPE' >&2
+ ;;
+ esac
+ return 1
+ fi
+ return 0
+ ;;
+
+ #
+ # coprocess open
+ #
+ o|op|ope|open)
+ shift
+ local fifo="/var/tmp/coprocess.$$.$RANDOM"
+
+ local cmd="/bin/bash"
+ if (( $# > 0 )) ; then
+ cmd="$@"
+ fi
+
+ mkfifo "$fifo.in" || return $?
+ mkfifo "$fifo.out" || {
+ ret=$?
+ rm -f "$fifo.in"
+ return $?
+ }
+
+ ( "$@" <$fifo.in >$fifo.out ; rm -f "$fifo.in" "$fifo.out" ) &
+ coprocess_pid=$!
+ exec 61>$fifo.in 62<$fifo.out
+ return 0
+ ;;
+
+ #
+ # coprocess print - write to the coprocess
+ #
+ p|pr|pri|prin|print)
+ shift
+ local old_trap=$(trap -p SIGPIPE)
+ trap 'coprocess close -SIGPIPE' SIGPIPE
+ if [ $# -eq 1 ] && [ "$1" = "--stdin" ] ; then
+ cat >&61
+ else
+ echo "$@" >&61
+ fi
+ local ret=$?
+ eval "$old_trap"
+ return $ret
+ ;;
+
+ #
+ # coprocess read - read from the coprocess
+ #
+ r|re|rea|read)
+ shift
+ local old_trap=$(trap -p SIGPIPE)
+ trap '_coprocess_close -SIGPIPE' SIGPIPE
+ builtin read "$@" <&62
+ local ret=$?
+ eval "$old_trap"
+ return $ret
+ ;;
+
+ s|st|sta|stat|statu|status)
+ if [ -z "$coprocess_pid" ] ; then
+ echo 'no active coprocess'
+ return 1
+ else
+ echo " coprocess is active [$coprocess_pid]"
+ return 0
+ fi
+ ;;
+
+ *)
+ coprocess print "$@"
+ return $?
+ ;;
+ esac
+ shift
+ done
+ coprocess status
+ return $?
+}
diff --git a/examples/functions/coshell.README b/examples/functions/coshell.README
new file mode 100644
index 0000000..9675cda
--- /dev/null
+++ b/examples/functions/coshell.README
@@ -0,0 +1,53 @@
+Date: Fri, 21 Sep 2001 14:50:29 -0400
+From: "Jason M. Felice" <jfelice@cronosys.com>
+To: bash-maintainers@gnu.org, chet@po.cwru.edu
+Subject: Bash co-processes functions
+Message-ID: <20010921145029.A6093@argo.eraserhead.net>
+Mime-Version: 1.0
+
+Attached to this message you will find coprocess.bash and coshell.bash.
+Here's a brief synopsis of use:
+
+coprocess open telnet localhost
+while coprocess read il ; do
+ echo "$il"
+ case "$il" in
+ *ogin:*)
+ coprocess print 'user'
+ ;;
+ *ord:*)
+ echo 'pass' |coprocess print --stdin
+ ;;
+ *$ *)
+ coprocess print 'exit'
+ break
+ ;;
+ esac
+done
+coprocess close
+
+And here's an example of the coshell function:
+
+coshell open ssh -l root otherbox
+coshell eval hostname
+coshell ls -l
+if coshell test -d /tmp ; then echo 'otherbox has a /tmp!' ; fi
+
+coshell sendfile /var/lib/upgrade.rpm /tmp/test.rpm || exit $?
+coshell eval rpm -ivh /tmp/test.rpm || exit $?
+coshell eval rm -f /tmp/test.rpm || exit $?
+coshell close
+exit 0
+
+There are a few minor issues that I'd like to work out, but it works well
+enough for me ;-) The issues are:
+
+- Shell quoting issue with 'coshell eval' commands - need to somehow
+ re-quote words.
+- Interactive commands hang 'coshell eval', tried redirecting in </dev/null
+ to executed command, but it caused strange shell exit problems.
+- Some way to copy stdin from local coshell eval to remote shell. Probably
+ logically impossible, but would be wonderfully useful.
+
+I'm using it for writing scripts to publish websites and other scripts to
+co-located servers.
diff --git a/examples/functions/coshell.bash b/examples/functions/coshell.bash
new file mode 100644
index 0000000..dc177b3
--- /dev/null
+++ b/examples/functions/coshell.bash
@@ -0,0 +1,127 @@
+# vi:set sts=2 sw=2 ai:
+#
+# coshell.bash - Control shell coprocesses (see coprocess.bash).
+#
+
+function coshell ()
+{
+ while (( $# > 0 )) ; do
+ case "$1" in
+ #
+ # coshell open
+ #
+ o|op|ope|open)
+ shift
+ coprocess open "$@"
+ local ret=$?
+
+ # This should eat any ssh error messages or what not.
+ coshell eval : >/dev/null 2>&1
+ return $ret
+ ;;
+
+ #
+ # coshell close
+ #
+ c|cl|clo|close)
+ shift
+ coprocess close "$@"
+ return $?
+ ;;
+
+ #
+ # coshell eval
+ #
+ e|ev|eva|eval)
+ shift
+ local cookie=$RANDOM
+ if (( $# == 0 )) ; then
+ echo "coshell eval: no argumentsl" >&2
+ return 1
+ fi
+ if [ x$coprocess_pid = x ] ; then
+ echo "coshell eval: no active coshell" >&2
+ return 1
+ fi
+
+ coprocess print "$@"
+ coprocess print "coprocess_rc=\$?"
+ coprocess print "printf 'coprocess-$cookie----\n%d\n' \$coprocess_rc"
+ if [ x$coprocess_pid = x ] ; then
+ return 0
+ fi
+
+ local ol
+ while coprocess read ol ; do
+ case "$ol" in
+ *coprocess-$cookie----*)
+ ol="${ol%coprocess-$cookie----}"
+ echo -n "$ol"
+ break
+ ;;
+ esac
+ echo "$ol"
+ done
+ coprocess read ol
+ return $ol
+ ;;
+
+ #
+ # coshell sendfile
+ #
+ s|se|sen|send|sendf|sendfi|sendfil|sendfile)
+ shift
+ if (( $# != 2 )) ; then
+ echo "coshell sendfile: syntax is 'coshell sendfile SRC TARGET'" >&2
+ return 1
+ fi
+ if [ x$coprocess_pid = x ] ; then
+ echo "coshell sendfile: no active coshell" >&2
+ return 1
+ fi
+
+ local target=$2
+ if coshell test -d "$target" ; then
+ target="$target/${1##*/}"
+ fi
+
+ coprocess print "uudecode <<END_OF_FILE"
+ uuencode -m "$target" <$1 |coprocess print --stdin
+ coshell eval "END_OF_FILE"
+ return $?
+ ;;
+
+ #
+ # coshell getfile
+ #
+ g|ge|get|getf|getfi|getfil|getfile)
+ shift
+ if (( $# != 2 )) ; then
+ echo "coshell getfile: syntax is 'coshell getfile SRC TARGET'" >&2
+ return 1
+ fi
+ if [ x$coprocess_pid = x ] ; then
+ echo "coshell getfile: no active coshell" >&2
+ return 1
+ fi
+
+ local target=$2
+ if test -d "$target" ; then
+ target="$target/${1##*/}"
+ fi
+
+ coshell eval uuencode -m "$target" "<" "$1" |uudecode
+ return $?
+ ;;
+
+ *)
+ coshell eval "$@"
+ return $?
+ ;;
+ esac
+ shift
+ done
+ coprocess status
+ return $?
+}
+
diff --git a/examples/functions/csh-compat b/examples/functions/csh-compat
new file mode 100644
index 0000000..b8dcf8f
--- /dev/null
+++ b/examples/functions/csh-compat
@@ -0,0 +1,48 @@
+# C-shell compatabilty package.
+# setenv VAR VALUE
+function setenv ()
+{
+ export $1="$2"
+}
+
+function unsetenv ()
+{
+ unset $1
+}
+
+# Can't write foreach yet. Need pattern matching, and a few extras.
+function foreach () {
+echo 'Can'\''t do `foreach'\'' yet. Type "help for".'
+}
+
+# Make this work like csh's. Special case "term" and "path".
+#set () {
+#}
+
+chdir ()
+{
+ builtin cd "$@"
+}
+
+# alias - convert csh alias commands to bash functions
+# from Mohit Aron <aron@cs.rice.edu>
+# posted to usenet as <4i5p17$bnu@larry.rice.edu>
+function alias ()
+{
+ if [ "x$2" = "x" ]
+ then
+ declare -f $1
+ else
+ case $2 in
+ *[#\!]*)
+ comm=$(echo $2 | sed 's/\\!\*/\"$\@\"/g
+ s/\\!:\([1-9]\)/\"$\1\"/g
+ s/#/\\#/g')
+ ;;
+ *)
+ comm="$2 \"\$@\"" ;;
+ esac
+
+ eval function $1 \(\) "{" command "$comm" "; }"
+ fi
+}
diff --git a/examples/functions/dirfuncs b/examples/functions/dirfuncs
new file mode 100644
index 0000000..3958bbe
--- /dev/null
+++ b/examples/functions/dirfuncs
@@ -0,0 +1,142 @@
+#
+# Directory manipulation functions from the book 'The Korn Shell'
+# Modified for use with bash Mon Apr 18 08:37 1994 by
+# Ken Konecki (kenk@wfg.com)
+#
+# Modified by Chet Ramey
+#
+# This could stand to have calls to `select' added back in
+#
+
+alias integer="declare -i"
+
+integer _push_max=${CDSTACK-31} _push_top=${CDSTACK-31}
+
+unalias cd
+# alias cd=_cd
+
+# Display directory stack -- $HOME display as ~
+dirs()
+{
+ dir="${PWD#$HOME/}"
+ case $dir in
+ $HOME) dir=\~ ;;
+ /*) ;;
+ *) dir=\~/$dir ;;
+ esac
+
+ integer i=_push_top
+ integer n=1
+
+ echo "$n) $dir"
+ while let "i < $_push_max"
+ do
+ n=n+1
+ eval "echo \$n\) \$_push_stack_$i"
+ i=i+1
+ done
+}
+
+# Change directory and put directory on front of stack
+cd()
+{
+ typeset dir=
+ integer n=0 type=4 i
+ case $1 in
+ -|-1|2) # cd -
+ n=_push_top type=1
+ ;;
+ -[1-9]|-[1-9][0-9]) # cd -n
+ n=_push_top+${1#-}-1 type=2
+ ;;
+
+ 1) # keep present directory
+ echo "$PWD"
+ return
+ ;;
+
+ [2-9]|[1-9][0-9]) # cd n
+ n=_push_top+${1}-2 type=2
+ ;;
+
+ *)
+ if let "_push_top <= 0"; then
+ type=3 n=_push_max
+ fi
+ ;;
+ esac
+
+ if let "type < 3"; then
+ if let "n >= _push_max"; then
+ echo cd: Directory stack not that deep
+ return 1
+ else
+ eval dir=\${_push_stack_$n}
+ fi
+ fi
+
+ case $dir in
+ ~*) dir=$HOME${dir#\~} ;;
+ esac
+
+ cd2 ${dir:-$@} > /dev/null || return 1
+ dir=${OLDPWD#$HOME/}
+ case $dir in
+ $HOME) dir=\~ ;;
+ /*) ;;
+ *) dir=\~/$dir ;;
+ esac
+
+ case $type in
+ 1) # swap first two elements
+ eval _push_stack_$_push_top=\$dir ;;
+
+ 2|3) # put $dir on top and shift down by one until top
+ i=_push_top
+ unset _dirlist
+ while let "i < $_push_max" ; do
+ eval _dirlist=\"\$_dirlist \$_push_stack_$i\"
+ i=i+1
+ done
+
+ i=_push_top
+ for dir in "$dir" ${_dirlist} ; do
+ let "i > n" && break
+ eval _push_stack_$i=\$dir
+ i=i+1
+ done
+ ;;
+ 4) # push name
+ _push_top=_push_top-1;
+ eval _push_stack_$_push_top=\$dir
+ ;;
+ esac
+
+ echo "$PWD"
+
+}
+
+# Menu-driven change directory command
+function mcd
+{
+ dirs
+ echo -n "Select by number or enter a name: "
+ read
+ cd $REPLY
+}
+
+
+# Emulate ksh cd substitution
+cd2()
+{
+ case "$#" in
+ 0) builtin cd "$HOME" ;;
+ 1) builtin cd "$1" ;;
+ 2) newDir=$(echo $PWD | sed -e "s:$1:$2:g")
+ case "$newDir" in
+ $PWD) echo "bash:: cd: bad substitution" >&2 ; return 1 ;;
+ *) builtin cd "$newDir" ;;
+ esac ;;
+ *) echo "bash: cd: wrong arg count" 1>&2 ; return 1 ;;
+ esac
+}
diff --git a/examples/functions/dirname b/examples/functions/dirname
new file mode 100644
index 0000000..ccb8c84
--- /dev/null
+++ b/examples/functions/dirname
@@ -0,0 +1,21 @@
+# Date: Fri, 11 Oct 91 11:22:36 edt
+# From: friedman@gnu.ai.mit.edu
+# To: bfox@gnu.ai.mit.edu
+
+# A replacement for dirname(1). This one appears less often on some
+# systems I use than basename(1), and I really depend on it for some
+# things. Usage: dirname [path]
+function dirname ()
+{
+ local dir="$1"
+ local tdir="${dir%/}"
+
+ # Strip trailing '/' characters from dir (unusual that this should
+ # ever occur, but dirname(1) seems to deal with it.)
+ while [ "${tdir}" != "${dir}" ]; do
+ tdir="${dir}"
+ dir="${tdir%/}"
+ done
+
+ echo "${dir%/*}"
+}
diff --git a/examples/functions/emptydir b/examples/functions/emptydir
new file mode 100644
index 0000000..412af5b
--- /dev/null
+++ b/examples/functions/emptydir
@@ -0,0 +1,28 @@
+#! /bin/bash
+#
+#Derived from:
+#
+#From: damercer@mmm.com (Dan Mercer)
+#Newsgroups: comp.unix.admin,comp.unix.shell,comp.unix.programmer,comp.sys.sun.admin
+#Subject: Re: Command to find out if a directory is empty
+#Date: 17 Aug 2000 14:35:56 GMT
+#Message-ID: <8ngt8c$fmr$1@magnum.mmm.com>
+
+# usage: emptydir [dirname] ; default dirname is "."
+
+emptydir()
+{
+ typeset file dir=${1:-.}
+ [[ -d $dir ]] || {
+ echo "$FUNCNAME: $dir is not a directory" >&2
+ return 2
+ }
+ for file in $dir/.* $dir/*
+ do
+ case ${file#$dir/} in
+ .|..) ;;
+ \*) [[ -e $file ]];let $?;return;;
+ *) return 1;;
+ esac
+ done
+}
diff --git a/examples/functions/exitstat b/examples/functions/exitstat
new file mode 100644
index 0000000..f49ebf5
--- /dev/null
+++ b/examples/functions/exitstat
@@ -0,0 +1,22 @@
+# Contributed by Noah Friedman and Roland McGrath.
+
+# To be run by the PROMPT_COMMAND variable, so that one can see what
+# the exit status of processes are.
+
+function check_exit_status ()
+{
+ local status="$?"
+ local signal=""
+
+ if [ ${status} -ne 0 ] && [ ${status} != 128 ]; then
+ # If process exited by a signal, determine name of signal.
+ if [ ${status} -gt 128 ]; then
+ signal="$(builtin kill -l $((${status} - 128)) 2>/dev/null)"
+ if [ "$signal" ]; then signal="($signal)"; fi
+ fi
+ echo "[Exit ${status} ${signal}]" 1>&2
+ fi
+ return 0
+}
+
+PROMPT_COMMAND=check_exit_status
diff --git a/examples/functions/external b/examples/functions/external
new file mode 100644
index 0000000..c2e52cd
--- /dev/null
+++ b/examples/functions/external
@@ -0,0 +1,50 @@
+# Contributed by Noah Friedman.
+
+# To avoid using a function in bash, you can use the `builtin' or
+# `command' builtins, but neither guarantees that you use an external
+# program instead of a bash builtin if there's a builtin by that name. So
+# this function can be used like `command' except that it guarantees the
+# program is external by first disabling any builtin by that name. After
+# the command is done executing, the state of the builtin is restored.
+function external ()
+{
+ local state=""
+ local exit_status
+
+ if builtin_p "$1"; then
+ state="builtin"
+ enable -n "$1"
+ fi
+
+ command "$@"
+ exit_status=$?
+
+ if [ "$state" = "builtin" ]; then
+ enable "$1"
+ fi
+
+ return ${exit_status}
+}
+
+# What is does is tell you if a particular keyword is currently enabled as
+# a shell builtin. It does NOT tell you if invoking that keyword will
+# necessarily run the builtin. For that, do something like
+#
+# test "$(builtin type -type [keyword])" = "builtin"
+#
+# Note also, that disabling a builtin with "enable -n" will make builtin_p
+# return false, since the builtin is no longer available.
+function builtin_p ()
+{
+ local word
+
+ set $(builtin type -all -type "$1")
+
+ for word in "$@" ; do
+ if [ "${word}" = "builtin" ]; then
+ return 0
+ fi
+ done
+
+ return 1
+}
diff --git a/examples/functions/fact b/examples/functions/fact
new file mode 100644
index 0000000..97efd49
--- /dev/null
+++ b/examples/functions/fact
@@ -0,0 +1,13 @@
+# Who said shells can't use recursion? Here is a factorial function.
+# You call it with a number as an argument, and it returns the factorial
+# of that number.
+
+fact ()
+{
+ local num=$1;
+ if [ "$num" = 1 ] ; then
+ echo 1
+ return ;
+ fi;
+ echo $(( $num * $(fact $(( $num - 1 )) ) ))
+}
diff --git a/examples/functions/fstty b/examples/functions/fstty
new file mode 100644
index 0000000..a770d84
--- /dev/null
+++ b/examples/functions/fstty
@@ -0,0 +1,59 @@
+#
+# A function that works as a front end for both stty and the `bind'
+# builtin, so the tty driver and readline see the same changes
+#
+
+#
+# Convert between the stty ^H control character form and the readline \C-H
+# form
+#
+cvt()
+{
+ echo "$@" | cat -v | sed 's/\^/\\C-/'
+}
+
+#
+# stty front-end. Parses the argument list and creates two command strings,
+# one for stty, another for bind.
+#
+fstty()
+{
+ local cmd="" bargs=""
+ local e
+
+ while [ $# -gt 0 ]
+ do
+ case "$1" in
+ -a) cmd="$cmd everything"
+ ;;
+ erase) shift;
+ e=$(cvt "$1")
+ cmd="$cmd erase $1"
+ bargs="$bargs '\"$e\": backward-delete-char'"
+ ;;
+ kill) shift
+ e=$(cvt "$1")
+ cmd="$cmd kill $1"
+ bargs="$bargs '\"$e\": unix-line-discard'"
+ ;;
+ werase) shift;
+ e=$(cvt "$1")
+ cmd="$cmd erase $1"
+ bargs="$bargs '\"$e\": backward-kill-word'"
+ ;;
+ lnext) shift;
+ e=$(cvt "$1")
+ cmd="$cmd erase $1"
+ bargs="$bargs '\"$e\": quoted-insert'"
+ ;;
+ *) cmd="$cmd $1"
+ ;;
+ esac
+ shift
+ done
+
+ command stty $cmd
+ if [ -n "$bargs" ]; then
+ builtin bind $bargs
+ fi
+}
diff --git a/examples/functions/func b/examples/functions/func
new file mode 100644
index 0000000..710f643
--- /dev/null
+++ b/examples/functions/func
@@ -0,0 +1,27 @@
+#
+# func -- print out definitions for functions named by arguments
+#
+# usage: func name [name ...]
+#
+# Chet Ramey
+# chet@ins.CWRU.Edu
+func()
+{
+ local status=0
+
+ if [ $# -eq 0 ] ; then
+ echo "usage: func name [name...]" 1>&2
+ return 1
+ fi
+
+ for f
+ do
+ if [ "$(builtin type -type $f)" != "function" ] ; then
+ echo "func: $f: not a function" 1>&2
+ status=1 # one failed
+ continue
+ fi
+ builtin type $f | sed 1d
+ done
+ return $status
+}
diff --git a/examples/functions/gethtml b/examples/functions/gethtml
new file mode 100644
index 0000000..2eec1d8
--- /dev/null
+++ b/examples/functions/gethtml
@@ -0,0 +1,35 @@
+#
+# get_html -- get a web page from a remote server
+#
+# Original Author: Jeff Korn <jlk@cs.princeton.edu>
+# Modified for bash by Chet Ramey <chet@po.cwru.edu>
+#
+# Example: get_html cnswww.cns.cwru.edu /~chet/ | more
+
+get_html()
+{
+ local host port
+
+ (($# < 2)) && {
+ echo "usage: $FUNCNAME hostname path [port]" >&2
+ return 1
+ }
+
+ host="$1"
+ port="${3:-80}"
+
+ exec 3<> /dev/tcp/$host/$port || {
+ echo "$FUNCNAME: $host/$port: cannot connect" >&2
+ exit 1
+ }
+
+ echo -e "GET $2 HTTP/1.0\n" >&3
+
+ cat <&3
+
+ exec 3<&-
+
+ return 0
+}
+
+get_html "$@"
diff --git a/examples/functions/getoptx.bash b/examples/functions/getoptx.bash
new file mode 100644
index 0000000..d402c7d
--- /dev/null
+++ b/examples/functions/getoptx.bash
@@ -0,0 +1,301 @@
+#From: "Grigoriy Strokin" <grg@philol.msu.ru>
+#Newsgroups: comp.unix.shell
+#Subject: BASH: getopt function that parses long-named options
+#Date: Mon, 22 Dec 1997 20:35:18 +0300
+
+#Hi, I have written a BASH function named getoptex, that is like bash builtin
+#"getopts", but does parse long-named options and optional arguments. It only
+#uses builtin bash commands, so it is very fast. In order to use it in your
+#bash scripts, include a command ". getopt.sh" (<dot> getopt.sh) to the file
+#containing your script, and that will define functions getopt, getoptex, and
+#optlistex (the file getopt.sh with its detailed description is listed
+#below).
+
+#*** file getopt.sh ***
+
+#! /bin/bash
+#
+# getopt.sh:
+# functions like getopts but do long-named options parsing
+# and support optional arguments
+#
+# Version 1.0 1997 by Grigoriy Strokin (grg@philol.msu.ru), Public Domain
+# Date created: December 21, 1997
+# Date modified: December 21, 1997
+#
+# IMPORTANT FEATURES
+#
+# 1) Parses both short and long-named options
+# 2) Supports optional arguments
+# 3) Only uses bash builtins, thus no calls to external
+# utilities such as expr or sed is done. Therefore,
+# parsing speed is high enough
+#
+#
+# DESCRIPTION
+#
+# FUNCTION getopt
+# Usage: getopt OPTLIST {"$@"|ALTERNATIVE_PARAMETERS}
+#
+# like getopts, but parse options with both required and optional arguments,
+# Options with optional arguments must have "." instead of ":" after them.
+# Furthemore, a variable name to place option name cannot be specified
+# and is always placed in OPTOPT variable
+#
+# This function is provided for compatibility with getopts()
+# OPTLIST style, and it actually calls getoptex (see bellow)
+#
+# NOTE that a list of parameters is required and must be either "$@",
+# if processing command line arguments, or some alternative parameters.
+#
+# FUNCTION getoptex
+# Usage: getoptex OPTION_LIST {"$@"|ALTERNATIVE_PARAMETERS}
+#
+# like getopts, but parse long-named options.
+#
+# Both getopt and getoptex return 0 if an option has been parsed,
+# and 1 if all options are already parsed or an error occured
+#
+# Both getopt and getoptex set or test the following variables:
+#
+# OPTERR -- tested for whether error messages must be given for invalid
+options
+#
+# OPTOPT -- set to the name of an option parsed,
+# or to "?" if no more options or error
+# OPTARG -- set to the option argument, if any;
+# unset if ther is no argument;
+# on error, set to the erroneous option name
+#
+# OPTIND -- Initialized to 1.
+# Then set to the number of the next parameter to be parsed
+# when getopt or getoptex will be called next time.
+# When all options are parsed, contains a number of
+# the first non-option argument.
+#
+#
+# OPTOFS -- If a parameter number $OPTIND containg an option parsed
+# does not contain any more options, OPTOFS is unset;
+# otherwise, OPTOFS is set to such a number of "?" signs
+# which is equal to the number of options parsed
+#
+# You might not set variables OPTIND and OPTOFS yourself
+# unless you want to parse a list of parameters more than once.
+# Otherwise, you whould unset OPTIND (or set it to 1)
+# and unset OPTOFS each time you want to parse a new parameters
+list
+#
+# Option list format is DIFFERENT from one for getopts or getopt.
+getopts-style
+# option list can be converted to getoptex-style using a function optlistex
+# (see bellow)
+#
+# DESCRIPTION of option list used with getoptex:
+# Option names are separated by whitespace. Options consiting of
+# more than one character are treated as long-named (--option)
+#
+# Special characters can appear at the and of option names specifying
+# whether an argument is required (default is ";"):
+# ";" (default) -- no argument
+# ":" -- required argument
+# "," -- optional argument
+#
+# For example, an option list "a b c help version f: file: separator."
+# defines the following options:
+# -a, -b, -c, --help, --version -- no argument
+# -f, --file -- argument required
+# --separator -- optional argument
+#
+# FUNCTION optlistex
+# Usage new_style_optlist=`optlistex OLD_STYLE_OPTLIST`
+#
+# Converts getopts-style option list in a format suitable for use with getoptex
+# Namely, it inserts spaces after each option name.
+#
+#
+# HOW TO USE
+#
+# In order o use in your bash scripts the functions described,
+# include a command ". getopt.sh" to the file containing the script,
+# which will define functions getopt, getoptex, and optlistex
+#
+# EXAMPLES
+#
+# See files 'getopt1' and 'getopt2' that contain sample scripts that use
+# getopt and getoptex functions respectively
+#
+#
+# Please send your comments to grg@philol.msu.ru
+
+function getoptex()
+{
+ let $# || return 1
+ local optlist="${1#;}"
+ let OPTIND || OPTIND=1
+ [ $OPTIND -lt $# ] || return 1
+ shift $OPTIND
+ if [ "$1" != "-" ] && [ "$1" != "${1#-}" ]
+ then OPTIND=$[OPTIND+1]; if [ "$1" != "--" ]
+ then
+ local o
+ o="-${1#-$OPTOFS}"
+ for opt in ${optlist#;}
+ do
+ OPTOPT="${opt%[;.:]}"
+ unset OPTARG
+ local opttype="${opt##*[^;:.]}"
+ [ -z "$opttype" ] && opttype=";"
+ if [ ${#OPTOPT} -gt 1 ]
+ then # long-named option
+ case $o in
+ "--$OPTOPT")
+ if [ "$opttype" != ":" ]; then return 0; fi
+ OPTARG="$2"
+ if [ -z "$OPTARG" ];
+ then # error: must have an agrument
+ let OPTERR && echo "$0: error: $OPTOPT must have an argument" >&2
+ OPTARG="$OPTOPT";
+ OPTOPT="?"
+ return 1;
+ fi
+ OPTIND=$[OPTIND+1] # skip option's argument
+ return 0
+ ;;
+ "--$OPTOPT="*)
+ if [ "$opttype" = ";" ];
+ then # error: must not have arguments
+ let OPTERR && echo "$0: error: $OPTOPT must not have arguments" >&2
+ OPTARG="$OPTOPT"
+ OPTOPT="?"
+ return 1
+ fi
+ OPTARG=${o#"--$OPTOPT="}
+ return 0
+ ;;
+ esac
+ else # short-named option
+ case "$o" in
+ "-$OPTOPT")
+ unset OPTOFS
+ [ "$opttype" != ":" ] && return 0
+ OPTARG="$2"
+ if [ -z "$OPTARG" ]
+ then
+ echo "$0: error: -$OPTOPT must have an argument" >&2
+ OPTARG="$OPTOPT"
+ OPTOPT="?"
+ return 1
+ fi
+ OPTIND=$[OPTIND+1] # skip option's argument
+ return 0
+ ;;
+ "-$OPTOPT"*)
+ if [ $opttype = ";" ]
+ then # an option with no argument is in a chain of options
+ OPTOFS="$OPTOFS?" # move to the next option in the chain
+ OPTIND=$[OPTIND-1] # the chain still has other options
+ return 0
+ else
+ unset OPTOFS
+ OPTARG="${o#-$OPTOPT}"
+ return 0
+ fi
+ ;;
+ esac
+ fi
+ done
+ echo "$0: error: invalid option: $o"
+ fi; fi
+ OPTOPT="?"
+ unset OPTARG
+ return 1
+}
+function optlistex
+{
+ local l="$1"
+ local m # mask
+ local r # to store result
+ while [ ${#m} -lt $[${#l}-1] ]; do m="$m?"; done # create a "???..." mask
+ while [ -n "$l" ]
+ do
+ r="${r:+"$r "}${l%$m}" # append the first character of $l to $r
+ l="${l#?}" # cut the first charecter from $l
+ m="${m#?}" # cut one "?" sign from m
+ if [ -n "${l%%[^:.;]*}" ]
+ then # a special character (";", ".", or ":") was found
+ r="$r${l%$m}" # append it to $r
+ l="${l#?}" # cut the special character from l
+ m="${m#?}" # cut one more "?" sign
+ fi
+ done
+ echo $r
+}
+function getopt()
+{
+ local optlist=`optlistex "$1"`
+ shift
+ getoptex "$optlist" "$@"
+ return $?
+}
+
+#**************************************
+# cut here
+#**************************************
+#*** (end of getopt.sh) ***
+
+
+#*** file getopt1 ***
+
+#! /bin/bash
+# getopt1:
+# Sample script using the function getopt
+#
+# Type something like "getopt1 -ab -d 10 -e20 text1 text2"
+# on the command line to see how it works
+#
+# See getopt.sh for more information
+#. getopt.sh
+#echo Using getopt to parse arguments:
+#while getopt "abcd:e." "$@"
+#do
+# echo "Option <$OPTOPT> ${OPTARG:+has an arg <$OPTARG>}"
+#done
+#shift $[OPTIND-1]
+#for arg in "$@"
+#do
+# echo "Non option argument <$arg>"
+#done
+#
+#**************************************
+# cut here
+#**************************************
+#*** (end of getopt1) ***
+#
+#
+#*** file getopt2 ***
+#
+#! /bin/bash
+# getopt2:
+# Sample script using the function getoptex
+#
+# Type something like "getopt2 -ab -d 10 -e20 --opt1 --opt4=100 text1 text2"
+# to see how it works
+#
+# See getopt.sh for more information
+. getopt.sh
+#echo Using getoptex to parse arguments:
+#while getoptex "a; b; c; d: e. opt1 opt2 opt3 opt4: opt5." "$@"
+#do
+# echo "Option <$OPTOPT> ${OPTARG:+has an arg <$OPTARG>}"
+#done
+#shift $[OPTIND-1]
+#for arg in "$@"
+#do
+# echo "Non option argument <$arg>"
+#done
+#
+#**************************************
+# cut here
+#**************************************
+#*** (end of getopt2) ***
+
diff --git a/examples/functions/inetaddr b/examples/functions/inetaddr
new file mode 100644
index 0000000..f3e228f
--- /dev/null
+++ b/examples/functions/inetaddr
@@ -0,0 +1,60 @@
+#
+# inet2hex - Internet address conversion, dotted-decimal to hex
+#
+inet2hex ()
+{
+ local IFS
+
+ IFS=.
+ set -- $1
+
+ if (( $# != 4 )); then
+ echo "inet2hex: incorrect input format: $1" >&2
+ echo "inet2hex: usage: inet2hex XX.XX.XX.XX" >&2
+ return 2
+ fi
+
+ printf "0x%02x%02x%02x%02x\n" $1 $2 $3 $4
+}
+
+#
+# hex2inet - Internet address conversion, hex to dotted-decimal
+#
+hex2inet ()
+{
+ local x1 x2 x3 x4
+ local rev
+
+ OPTIND=1
+ while getopts "r" o
+ do
+ case "$o" in
+ r) rev=true;;
+ *) echo "hex2inet: usage: hex2inet [-r] [0x]XXXXXXXX" >&2 ; exit 2;;
+ esac
+ done
+ shift $(( $OPTIND - 1 ))
+
+ case "$1" in
+ 0x*) h=${1#??} ;;
+ *) h=$1 ;;
+ esac
+
+ if (( ${#h} != 8 )); then
+ echo "hex2inet: $h not in inet format" >&2
+ echo "hex2inet: usage: hex2inet [0x]XXXXXXXX" >&2
+ return 2
+ fi
+
+ x1=$(( 0x${h:0:2} ))
+ x2=$(( 0x${h:2:2} ))
+ x3=$(( 0x${h:4:2} ))
+ x4=$(( 0x${h:6:2} ))
+
+ if [ -z "$rev" ] ; then
+ printf "%d.%d.%d.%d\n" $x1 $x2 $x3 $x4
+ else
+ printf "%d.%d.%d.%d\n" $x4 $x3 $x2 $x1
+ fi
+ return 0
+}
diff --git a/examples/functions/inpath b/examples/functions/inpath
new file mode 100644
index 0000000..cb4c93d
--- /dev/null
+++ b/examples/functions/inpath
@@ -0,0 +1,14 @@
+inpath()
+{
+ local PROG
+ path=$(echo $PATH | sed 's/^:/.:/
+ s/::/:.:/g
+ s/:$/:./
+ s/:/ /g')
+
+ for x in $path
+ do
+ [ -x $x/$1 ] && { PROG=$x/$1; break; }
+ done
+ [ -n "$PROG" ]
+}
diff --git a/examples/functions/isnum.bash b/examples/functions/isnum.bash
new file mode 100644
index 0000000..b733965
--- /dev/null
+++ b/examples/functions/isnum.bash
@@ -0,0 +1,52 @@
+#From: jrmartin@rainey.blueneptune.com (James R. Martin)
+#Newsgroups: comp.unix.shell
+#Subject: Re: testing user input on numeric or character value
+#Date: 26 Nov 1997 01:28:43 GMT
+
+# isnum returns True if its argument is a valid number,
+# and False (retval=1) if it is any other string.
+# The first pattern requires a digit before the decimal
+# point, and the second after the decimal point.
+
+# BASH NOTE: make sure you have executed `shopt -s extglob' before
+# trying to use this function, or it will not work
+
+isnum() # string
+{
+ case $1 in
+ ?([-+])+([0-9])?(.)*([0-9])?([Ee]?([-+])+([0-9])) )
+ return 0;;
+ ?([-+])*([0-9])?(.)+([0-9])?([Ee]?([-+])+([0-9])) )
+ return 0;;
+ *) return 1;;
+ esac
+}
+
+isnum2() # string
+{
+ case $1 in
+ ?([-+])+([[:digit:]])?(.)*([[:digit:]])?([Ee]?([-+])+([[:digit:]])) )
+ return 0;;
+ ?([-+])*([[:digit:]])?(.)+([[:digit:]])?([Ee]?([-+])+([[:digit:]])) )
+ return 0;;
+ *) return 1;;
+ esac
+}
+
+isint() # string
+{
+ case $1 in
+ ?([-+])+([0-9]) )
+ return 0;;
+ *) return 1;;
+ esac
+}
+
+isint2() # string
+{
+ case $1 in
+ ?([-+])+([[:digit:]]) )
+ return 0;;
+ *) return 1;;
+ esac
+}
diff --git a/examples/functions/isnum2 b/examples/functions/isnum2
new file mode 100644
index 0000000..e2e7a5f
--- /dev/null
+++ b/examples/functions/isnum2
@@ -0,0 +1,22 @@
+isnum2()
+{
+ case "$1" in
+ '[-+]' | '') return 1;; # empty or bare `-' or `+'
+ [-+]*[!0-9]*) return 1;; # non-digit with leading sign
+ [-+]*) return 0;; # OK
+ *[!0-9]*) return 1;; # non-digit
+ *) return 0;; # OK
+ esac
+}
+
+# this one handles floating point
+isnum3()
+{
+ case "$1" in
+ '') return 1;; # empty
+ *[!0-9.+-]*) return 1;; # non-digit, +, -, or .
+ *?[-+]*) return 1;; # sign as second or later char
+ *.*.*) return 1;; # multiple decimal points
+ *) return 0;; # OK
+ esac
+}
diff --git a/examples/functions/isvalidip b/examples/functions/isvalidip
new file mode 100644
index 0000000..0b2dafe
--- /dev/null
+++ b/examples/functions/isvalidip
@@ -0,0 +1,14 @@
+# Thanks to Chris F. A. Johnson <c.f.a.johnson@rogers.com> for this one
+is_validip()
+{
+ case "$*" in
+ ""|*[!0-9.]*|*[!0-9]) return 1 ;;
+ esac
+
+ local IFS=.
+ set -- $*
+
+ [ $# -eq 4 ] &&
+ [ ${1:-666} -le 255 ] && [ ${2:-666} -le 255 ] &&
+ [ ${3:-666} -le 255 ] && [ ${4:-666} -le 254 ]
+}
diff --git a/examples/functions/jdate.bash b/examples/functions/jdate.bash
new file mode 100644
index 0000000..9488ed9
--- /dev/null
+++ b/examples/functions/jdate.bash
@@ -0,0 +1,78 @@
+#From: damatex@CAM.ORG (Mario Boudreault)
+#Newsgroups: comp.unix.shell
+#Subject: JULIAN DATE CONVERSION SUB
+#Date: 4 Aug 1995 10:23:28 -0400
+#Message-ID: <3vtah0$jb3@ocean.CAM.ORG>
+
+#For those using shells and who want to convert dates to a julian number
+#here is a shell script (wihtout validation) that can be used as a base
+#program for your shell scripts.
+
+#Special thanks to Ed Ferguson@ti.com who sent me the algorithm to compute
+#that date.
+
+#
+# MODIFIED BY CHET RAMEY TO CONVERT TO bash v2 SYNTAX
+#
+
+# cnvdate - Conversion de dates en julienne et vice et versa...
+#
+# Par : Mario Boudreault Damatex Inc Montreal, Canada
+# Date: 2 Aout 1995
+# Rev.: 2 Aout 1995
+#
+# Usage:
+# cvdate [-j] YYYMMDD pour convertir en nbre de jours
+# cvdate -d {julian number} pour convertir en AAAAMMJJ
+#
+
+jul_date()
+{
+ #
+ # Separe ANNEE, MOIS et JOUR...
+ #
+ YEAR=`echo $DATE | awk ' { print substr($0,1,4) } '`
+ MONTH=`echo $DATE | awk ' { print substr($0,5,2) } '`
+ DAY=`echo $DATE | awk ' { print substr($0,7,2) } '`
+ #
+ # Execute la formule magique...
+ #
+ A=$(( $DAY - 32075 + 1461 * ( $YEAR + 4800 - ( 14 - $MONTH ) / 12 ) \
+ / 4 + 367 * ( $MONTH - 2 + ( 14 - $MONTH ) / 12 * 12 ) / 12 - \
+ 3 * ( ( $YEAR + 4900 - ( 14 - $MONTH ) / 12 ) / 100 ) / 4 ))
+ echo $A
+}
+
+day_date()
+{
+ TEMP1=$(( $DATE + 68569 ))
+ TEMP2=$(( 4 * $TEMP1 / 146097 ))
+ TEMP1=$(( $TEMP1 - ( 146097 * $TEMP2 + 3 ) / 4 ))
+ Y=$(( 4000 * ( $TEMP1 + 1 ) / 1461001 ))
+ TEMP1=$(( $TEMP1 - 1461 * $Y / 4 + 31 ))
+ M=$(( 80 * $TEMP1 / 2447 ))
+ D=$(( $TEMP1 - 2447 * $M / 80 ))
+ TEMP1=$(( $M / 11 ))
+ M=$(( $M + 2 - 12 * $TEMP1 ))
+ Y=$(( 100 * ( $TEMP2 - 49 ) + $Y + $TEMP1 ))
+ M=`echo $M | awk ' { M=$0 ; if ( length($0) == 1 ) M="0"$0 } END { print M } '`
+ D=`echo $D | awk ' { D=$0 ; if ( length($0) == 1 ) D="0"$0 } END { print D } '`
+ echo $Y$M$D
+}
+
+# main()
+
+if [ $# -eq 1 ]; then
+ DATE=$1
+ jul_date
+elif [ "$1" = '-j' ]; then
+ DATE=$2
+ jul_date
+elif [ "$1" = '-d' ]; then
+ DATE=$2
+ day_date
+fi
+#
+# Termine
+#
+exit 0
diff --git a/examples/functions/jj.bash b/examples/functions/jj.bash
new file mode 100644
index 0000000..212c9ce
--- /dev/null
+++ b/examples/functions/jj.bash
@@ -0,0 +1,12 @@
+jj ()
+{
+ p=$(jobs $1);
+ echo $p
+
+ case "$p" in
+ [*) echo matches '[*'
+ ;;
+ *) echo not a match\?
+ ;;
+ esac
+}
diff --git a/examples/functions/keep b/examples/functions/keep
new file mode 100644
index 0000000..4433b35
--- /dev/null
+++ b/examples/functions/keep
@@ -0,0 +1,62 @@
+# From: Seth Chaiklin <psykseth@aau.dk>
+# To: chet@ins.CWRU.Edu
+# Subject: bash functions (sorta)
+
+#
+# keep:
+# usage: keep program
+# declare the a program should be "kept". i.e. try to fg a stopped one
+# and only when that fails start a fresh program.
+#
+
+keep()
+{
+ case $# in
+ 1|2) ;;
+ *) echo "usage: keep [alias] program" 1>&2 ; return 1;;
+ esac
+
+ # progname
+ pn=${1##*/}
+
+ # set up an alias for the kept program
+ if [ $# = 1 ]; then
+ alias "$pn=fg $1 2>/dev/null || $1"
+ else
+ alias "$1=fg $2 2>/dev/null || $2"
+ fi
+}
+
+#
+# unkeep:
+# usage: unkeep program
+# unset the alias set up by the keep function
+#
+
+unkeep()
+{
+ if [ $# != 1 ]; then
+ echo "usage: unkeep program"
+ return 2
+ fi
+
+ # unset the alias for the kept program
+ unalias "${1##*/}"
+}
+
+#
+# kept:
+# lists all kept programs in 'alias: program' form
+#
+
+kept()
+{
+ alias | grep "fg.*2>" | sed "s/alias \(.*\)='fg.*||\(.*\)'$/\1:\2/"
+}
+
+
+# some things that should be kept
+#keep /usr/local/bin/emacs
+#keep e ${EDITOR:-/usr/local/bin/emacs}
+#keep edit ${EDITOR:-/usr/local/bin/emacs}
+#keep /usr/local/bin/emm
diff --git a/examples/functions/ksh-cd b/examples/functions/ksh-cd
new file mode 100644
index 0000000..801a490
--- /dev/null
+++ b/examples/functions/ksh-cd
@@ -0,0 +1,35 @@
+#
+# ksh-like `cd': cd [-LP] [dir [change]]
+#
+cd()
+{
+ OPTIND=1
+ while getopts "LP" opt
+ do
+ case $opt in
+ L|P) CDOPTS="$CDOPTS -$opt" ;;
+ *) echo "$FUNCNAME: usage: $FUNCNAME [-LP] [dir] [change]" >&2
+ return 2;;
+ esac
+ done
+
+ shift $(( $OPTIND - 1 ))
+
+ case $# in
+ 0) builtin cd $CDOPTS "$HOME" ;;
+ 1) builtin cd $CDOPTS "$@" ;;
+ 2) old="$1" new="$2"
+ case "$PWD" in
+ *$old*) ;;
+ *) echo "${0##*/}: $FUNCNAME: bad substitution" >&2 ; return 1 ;;
+ esac
+
+ dir=${PWD//$old/$new}
+
+ builtin cd $CDOPTS "$dir" && echo "$PWD"
+
+ ;;
+ *) echo "${0##*/}: $FUNCNAME: usage: $FUNCNAME [-LP] [dir] [change]" >&2
+ return 2 ;;
+ esac
+}
diff --git a/examples/functions/ksh-compat-test b/examples/functions/ksh-compat-test
new file mode 100644
index 0000000..feee965
--- /dev/null
+++ b/examples/functions/ksh-compat-test
@@ -0,0 +1,40 @@
+#
+# replacements for test/[ that do arithmetic expansion on the operands to
+# the arithmetic operators, like ksh.
+#
+function test()
+{
+ local -i n1 n3
+ case "$#" in
+ 3) case "$2" in
+ -lt|-gt|-eq|-ne|-le|-ge) n1=$(( $1 ))
+ n3=$(( $3 ))
+ builtin test "$n1" $2 "$n3"
+ return $?;;
+ *) builtin test "$@" ;;
+ esac;;
+ *) builtin test "$@" ;;
+ esac
+}
+
+function [()
+{
+ local -i n1 n3
+ case "$#" in
+ 4) case "$2" in
+ -lt|-gt|-eq|-ne|-le|-ge) n1=$(( $1 ))
+ n3=$(( $3 ))
+ builtin [ "$n1" $2 "$n3" ]
+ return $?;;
+ *) builtin [ "$@" ;;
+ esac;;
+ *) builtin [ "$@" ;;
+ esac
+}
+
+q=7
+
+[ q -lt 10 ]
+echo $?
+[ $q -lt 10 ]
+echo $?
diff --git a/examples/functions/kshenv b/examples/functions/kshenv
new file mode 100644
index 0000000..7594f2d
--- /dev/null
+++ b/examples/functions/kshenv
@@ -0,0 +1,228 @@
+#
+# .kshenv -- functions and aliases to provide the beginnings of a ksh
+# environment for bash.
+#
+# Chet Ramey
+# chet@ins.CWRU.Edu
+#
+#
+# These are definitions for the ksh compiled-in `exported aliases'. There
+# are others, but we already have substitutes for them: "history", "type",
+# and "hash".
+#
+alias r="fc -s"
+alias functions="typeset -f"
+alias integer="typeset -i"
+alias nohup="nohup "
+alias command="command "
+alias stop="kill -s STOP"
+alias redirect="command exec"
+alias hist="fc"
+
+#
+# An almost-ksh compatible `whence' command. This is as hairy as it is
+# because of the desire to exactly mimic ksh (whose behavior was determined
+# empirically).
+#
+# This depends somewhat on knowing the format of the output of the bash
+# `builtin type' command.
+#
+
+whence()
+{
+ local vflag pflag fflag defarg c
+ local path
+
+ vflag= aflag= pflag= fflag=
+ path=
+ if [ "$#" = "0" ] ; then
+ echo "whence: usage: whence [-afpv] name..." >&2
+ return 2
+ fi
+
+ OPTIND=1
+ while getopts "avfp" c
+ do
+ case "$c" in
+ a) defarg=-a ;;
+ f) fflag=1 ;; # no-op
+ p) pflag=1 ;;
+ v) vflag=1 ;;
+ ?) echo "whence: $1: unknown option" >&2
+ echo "whence: usage: whence [-afpv] name..." >&2
+ return 2 ;;
+ esac
+ done
+
+ shift $(( $OPTIND - 1 ))
+
+ if [ "$#" = "0" ] ; then
+ echo "whence: usage: whence [-afpv] name..." >&2
+ return 2
+ fi
+
+ for cmd
+ do
+ if [ "$vflag" ] ; then
+ if [ -z "$defarg" ]; then
+ builtin type $cmd | sed 1q
+ else
+ if builtin type $defarg -t $cmd | grep 'function$' >/dev/null 2>&1; then
+ # HAIRY awk script to suppress
+ # printing of function body -- could
+ # do it with sed, but I don't have
+ # that kind of time
+ builtin type $defarg $cmd | awk '
+BEGIN {printit = 1;}
+$1 == "'$cmd'" && $2 == "()" {printit=0; next; }
+/^}$/ { if (printit == 0) printit=1 ; else print $0; next ; }
+/.*/ { if (printit) print $0; }'
+ else
+ builtin type $defarg $cmd
+ fi
+ fi
+ else
+ path=$(builtin type $defarg -p $cmd)
+ if [ "$path" ] ; then
+ echo $path
+ else
+ case "$cmd" in
+ /*) echo "" ;;
+ *) case "$(builtin type -t $cmd)" in
+ "") echo "" ;;
+ *) echo "$cmd" ;;
+ esac
+ ;;
+ esac
+ fi
+ fi
+ done
+ return 0
+}
+
+#
+# For real ksh homeboy fanatics, redefine the `type' builtin with a ksh
+# version.
+#
+#type()
+#{
+# whence -v "$*"
+#}
+
+#
+# ksh-like `cd': cd [-LP] [dir [change]]
+#
+cd()
+{
+ OPTIND=1
+ while getopts "LP" opt
+ do
+ case $opt in
+ L|P) CDOPTS="$CDOPTS -$opt" ;;
+ *) echo "$FUNCNAME: usage: $FUNCNAME [-LP] [dir] [change]" >&2
+ return 2;;
+ esac
+ done
+
+ shift $(( $OPTIND - 1 ))
+
+ case $# in
+ 0) builtin cd $CDOPTS "$HOME" ;;
+ 1) builtin cd $CDOPTS "$@" ;;
+ 2) old="$1" new="$2"
+ case "$PWD" in
+ *$old*) ;;
+ *) echo "${0##*/}: $FUNCNAME: bad substitution" >&2 ; return 1 ;;
+ esac
+
+ dir=${PWD//$old/$new}
+
+ builtin cd $CDOPTS "$dir" && echo "$PWD"
+
+ ;;
+ *) echo "${0##*/}: $FUNCNAME: usage: $FUNCNAME [-LP] [dir] [change]" >&2
+ return 2 ;;
+ esac
+}
+
+#
+# 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
+}
+
+# substring function
+# this function should be equivalent to the substring built-in which was
+# eliminated after the 06/29/84 version
+substring ()
+{
+ local lpat flag str #local variables
+ set -f
+ case $1 in
+ -l|-L)
+ flag=$1
+ lpat=$2
+ shift 2
+ ;;
+ esac
+ # test for too few or too many arguments
+ if [ x"$1" = x ] || [ $# -gt 2 ]; then
+ print -u2 'substring: bad argument count'
+ return 1
+ fi
+ str=$1
+ if [ x"$flag" = x-l ]; then #substring -l lpat
+ str=${str#$lpat}
+ elif [ x"$flag" = x-L ]; then
+ str=${str##$lpat} #substring -L lpat
+ fi
+
+ if [ x"$2" != x ]; then
+ echo ${str%$2}
+ else
+ echo $str
+ fi
+
+ return 0
+}
diff --git a/examples/functions/login b/examples/functions/login
new file mode 100644
index 0000000..3d59683
--- /dev/null
+++ b/examples/functions/login
@@ -0,0 +1,11 @@
+# replace the `login' and `newgrp' builtins in old bourne shells
+
+login()
+{
+ exec login "$@"
+}
+
+newgrp()
+{
+ exec newgrp "$@"
+}
diff --git a/examples/functions/lowercase b/examples/functions/lowercase
new file mode 100644
index 0000000..3cf6bde
--- /dev/null
+++ b/examples/functions/lowercase
@@ -0,0 +1,27 @@
+#! /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
+
+lowercase()
+{
+ for file; do
+ [ -f "$file" ] || continue
+ 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 "lowercase: $file -> $newname"
+ else
+ echo "lowercase: $file not changed."
+ fi
+ done
+}
diff --git a/examples/functions/manpage b/examples/functions/manpage
new file mode 100644
index 0000000..60f9aed
--- /dev/null
+++ b/examples/functions/manpage
@@ -0,0 +1,129 @@
+# Written from scratch by Tom Tromey (tromey@cns.caltech.edu)
+#
+# manpage -- find and print a manual page.
+# usage: manpage section name [printing]
+#
+function manpage ()
+{
+ local i h cmd zot sec
+ local num="$1"
+ local page="$2"
+ local printing="$3"
+ local mp
+
+ mp="${MANPATH:-/usr/man}"
+ if [ "$#" -lt 2 ]; then return 1; fi # should print usage
+ if [ "$num" != "" ]; then
+ sec="${num%%[a-zA-Z]*}"
+ else
+ sec='[168234571lnpo]'
+ num="$sec"
+ fi
+ for i in $(echo "$mp" | tr : ' '); do
+ if [ ! -d "$i" ]; then continue; fi
+ file="$i"/man"$sec"/"$page"."$num"*
+ set $file
+ file="$1"
+ if [ -f "$file" ]; then
+ zot=$(sed 1q "$file")
+ cmd=${MANROFF:-"nroff -man - | col | cat -s"}
+ h=${zot##"'"'\"'}
+ if [ "$h" != "$zot" ]; then
+ while [ "$h" != "" ]; do
+ case "$h" in
+ *e) cmd="${MANEQN:-neqn} | $cmd";;
+ *r) cmd="refer | $cmd";;
+ *t) cmd="tbl | $cmd";;
+ *v) cmd="vgrind | $cmd";;
+ *) ;; # should print error
+ esac
+ h=${h%?}
+ done
+ fi
+ if [ "$printing" != "" ]; then
+ (cd "$i"; eval "$cmd") < "$file" | ${PAGER:-more}
+ else
+ (cd "$i"; eval "$cmd") < "$file" > /tmp/manpage-$$
+ ${PAGER:-more} /tmp/manpage-$$
+ rm -f /tmp/manpage-$$
+ fi
+ break
+ fi
+ done
+}
+
+function whatis_internal ()
+{
+ local j
+ for j in $(echo "$MANPATH" | tr : ' '); do
+ if [ -f "$j/whatis" ]; then
+ eval $2 -i -e "$1" $j/whatis
+ fi
+ done
+}
+
+function whatis ()
+{
+ local name=$(basename "$1")
+ whatis_internal "$name" "grep -w"
+}
+
+function apropos ()
+{
+ whatis_internal "$1" "grep -F"
+}
+
+# Note: "-" and "-t" together not supported. This man could be
+# made a lot better, but it does everything I want.
+function man ()
+{
+ local PAGER printing mpath MANROFF num
+ mpath="${MANPATH:-/usr/man}"
+ while true; do
+ case "$1" in
+ -) PAGER=cat
+ printing= ;;
+ -t)
+ MANROFF=${TROFF:-"ptroff -man -t"}
+ PAGER="${TCAT:-lpr}"
+ printing=yes ;;
+ -M)
+ mpath="$2"
+ shift;;
+ *) break;;
+ esac
+ shift
+ done
+ local MANPATH="$mpath"
+ case "$1" in
+ -f | -k)
+ local g a
+ if [ "$1" = "-f" ]; then
+ g="grep -w"
+ a=$(basename "$2")
+ else
+ g="grep -F"
+ a="$2"
+ fi
+ whatis_internal "$a" "$g"
+ ;;
+ [0-9npol] | [0-9][a-z]* | new | public | old | local)
+ if [ "$1" = "new" ]; then
+ num=n
+ elif [ "$1" = "public" ]; then
+ num=p
+ elif [ "$1" = "old" ]; then
+ num=o
+ elif [ "$1" = "local" ]; then
+ num=l
+ else
+ num="$1"
+ fi
+ shift
+ manpage "$num" "$1" "$printing"
+ ;;
+ *)
+ manpage "$num" "$1" "$printing"
+ ;;
+ esac
+}
diff --git a/examples/functions/mhfold b/examples/functions/mhfold
new file mode 100644
index 0000000..3c0c743
--- /dev/null
+++ b/examples/functions/mhfold
@@ -0,0 +1,16 @@
+# To: chet@ins.CWRU.Edu
+# Subject: Bash functions
+# From: Sandeep Mehta <sxm@philabs.Philips.Com>
+
+# print MH folders, useful only because folders(1) doesn't print
+# mod date/times
+
+mhfold()
+{
+ list=`folders | awk '{if (1 < NR) print $1}'`
+ /bin/ls -lag ~/Mail > /tmp/fold$$
+ for i in $list; do
+ grep $i /tmp/fold$$
+ done
+ /bin/rm -f /tmp/fold$$
+}
diff --git a/examples/functions/notify.bash b/examples/functions/notify.bash
new file mode 100644
index 0000000..dafbac5
--- /dev/null
+++ b/examples/functions/notify.bash
@@ -0,0 +1,58 @@
+trap _notify CHLD
+NOTIFY_ALL=false
+unset NOTIFY_LIST
+unalias false
+
+false()
+{
+ return 1
+}
+
+_notify ()
+{
+ local i j
+ local newlist=
+
+ if $NOTIFY_ALL
+ then
+ return # let bash take care of this itself
+ elif [ -z "$NOTIFY_LIST" ]; then
+ return
+ else
+ set -- $NOTIFY_LIST
+ for i in "$@"
+ do
+ j=$(jobs -n %$i)
+ if [ -n "$j" ]; then
+ echo "$j"
+ jobs -n %$i >/dev/null
+ else
+ newlist="newlist $i"
+ fi
+ done
+ NOTIFY_LIST="$newlist"
+ fi
+}
+
+notify ()
+{
+ local i j
+
+ if [ $# -eq 0 ]; then
+ NOTIFY_ALL=:
+ set -b
+ return
+ else
+ for i in "$@"
+ do
+ # turn a valid job spec into a job number
+ j=$(jobs $i)
+ case "$j" in
+ [*) j=${j%%]*}
+ j=${j#[}
+ NOTIFY_LIST="$NOTIFY_LIST $j"
+ ;;
+ esac
+ done
+ fi
+}
diff --git a/examples/functions/pathfuncs b/examples/functions/pathfuncs
new file mode 100644
index 0000000..56fdca3
--- /dev/null
+++ b/examples/functions/pathfuncs
@@ -0,0 +1,45 @@
+#From: "Simon J. Gerraty" <sjg@zen.void.oz.au>
+#Message-Id: <199510091130.VAA01188@zen.void.oz.au>
+#Subject: Re: a shell idea?
+#Date: Mon, 09 Oct 1995 21:30:20 +1000
+
+
+# NAME:
+# add_path.sh - add dir to path
+#
+# DESCRIPTION:
+# These functions originated in /etc/profile and ksh.kshrc, but
+# are more useful in a separate file.
+#
+# SEE ALSO:
+# /etc/profile
+#
+# AUTHOR:
+# Simon J. Gerraty <sjg@zen.void.oz.au>
+
+# @(#)Copyright (c) 1991 Simon J. Gerraty
+#
+# This file is provided in the hope that it will
+# be of use. There is absolutely NO WARRANTY.
+# Permission to copy, redistribute or otherwise
+# use this file is hereby granted provided that
+# the above copyright notice and this notice are
+# left intact.
+
+# is $1 missing from $2 (or PATH) ?
+no_path() {
+ eval "case :\$${2-PATH}: in *:$1:*) return 1;; *) return 0;; esac"
+}
+# if $1 exists and is not in path, append it
+add_path () {
+ [ -d ${1:-.} ] && no_path $* && eval ${2:-PATH}="\$${2:-PATH}:$1"
+}
+# if $1 exists and is not in path, prepend it
+pre_path () {
+ [ -d ${1:-.} ] && no_path $* && eval ${2:-PATH}="$1:\$${2:-PATH}"
+}
+# if $1 is in path, remove it
+del_path () {
+ no_path $* || eval ${2:-PATH}=`eval echo :'$'${2:-PATH}: |
+ sed -e "s;:$1:;:;g" -e "s;^:;;" -e "s;:\$;;"`
+}
diff --git a/examples/functions/recurse b/examples/functions/recurse
new file mode 100644
index 0000000..f69cd50
--- /dev/null
+++ b/examples/functions/recurse
@@ -0,0 +1,63 @@
+#!/bin/bash
+
+#From: kaz@ashi.footprints.net (Kaz Kylheku)
+#Newsgroups: comp.os.linux.misc
+#Subject: Re: bash question: subdirectories
+#Message-ID: <slrn8a0gu9.v5n.kaz@ashi.FootPrints.net>
+#Date: Tue, 08 Feb 2000 16:24:35 GMT
+
+#Actually it can be made to. That is to say, it is possible to code a recursive
+#descender function in the bash language. Here is an example.
+#
+#What is nice about this is that you can embed the function into your shell
+#script. The function changes the current working directory as it descends.
+#So it can handle arbitrarily deep paths. Whereas paths generated by the
+#find command can cause a problem when they get too long; the kernel has a
+#hard limit on the length of the string passed to the open() and other
+#system calls.
+
+#There are races; what if the directory tree is blown away during the traversal?
+#The function won't be able to crawl back up using the .. link and will just
+#bail.
+
+# Recursive Directory Traverser
+# Author: Kaz Kylheku
+# Date: Feb 27, 1999
+# Copyright 1999
+
+# Function parameter usage:
+# $1 directory to search
+# $2 pattern to search for
+# $3 command to execute
+# $4 secret argument for passing down path
+
+function recurse
+{
+ local file
+ local path
+
+ if [ "$4" = "" ] ; then
+ path="${1%/}/"
+ else
+ path="$4$1/"
+ fi
+
+ if cd "$1" ; then
+ for file in $2; do
+ if [ -f "$file" ] || [ -d "$file" ]; then
+ eval "$3"
+ fi
+ done
+ for file in .* * ; do
+ if [ "$file" = "." ] || [ "$file" = ".." ] ; then
+ continue
+ fi
+ if [ -d "$file" ] && [ ! -L "$file" ]; then
+ recurse "$file" "$2" "$3" "$path"
+ fi
+ done
+ cd ..
+ fi
+}
+
+recurse "$1" "$2" 'echo "$path$file"'
diff --git a/examples/functions/repeat2 b/examples/functions/repeat2
new file mode 100644
index 0000000..2e2dc7a
--- /dev/null
+++ b/examples/functions/repeat2
@@ -0,0 +1,43 @@
+# To: chet@ins.CWRU.Edu
+# Subject: Bash functions
+# From: Sandeep Mehta <sxm@philabs.Philips.Com>
+
+##########################################
+#
+# repeat - clone of C shell builtin `repeat'
+#
+# usage: repeat <count> <command>
+#
+# It has been tested inside other functions and in conditionals like
+# if [ "`repeat <count> <command>`" ]; then COMMANDS [ else COMMANDS ] fi
+# Please send me fixes/enhancements.
+#
+# Sandeep Mehta <sxm@philabs.Philips.Com>
+##########################################
+repeat()
+{
+ local rcount=$1
+
+ if [ $# -le 1 ] || [ -z "$rcount" ]; then
+ echo "usage: repeat <count> <command>" 1>&2
+ return 2
+ fi
+
+ shift
+
+ local acmd=("$@")
+
+ if [ $rcount -le 0 ]; then
+ echo "count must be greater than 0"
+ echo "usage: repeat <count> <command>" 1>&2
+ return 2
+ fi
+
+ st=0
+ while [ $rcount -gt 0 ]; do
+ eval "${acmd[@]}"
+ st=$?
+ rcount=$((rcount - 1))
+ done
+ return $st
+}
diff --git a/examples/functions/repeat3 b/examples/functions/repeat3
new file mode 100644
index 0000000..65048bf
--- /dev/null
+++ b/examples/functions/repeat3
@@ -0,0 +1,12 @@
+# From psamuels@jake.niar.twsu.edu (Peter Samuelson)
+# posted to usenet, Message-ID: <6rtp8j$2a0$1@jake.niar.twsu.edu>
+
+repeat ()
+{
+ local i max; # note that you can use \$i in the command string
+ max=$1; shift;
+
+ i=1; while ((i <= max)); do
+ eval "$@"; ((i = i + 1));
+ done;
+}
diff --git a/examples/functions/seq b/examples/functions/seq
new file mode 100644
index 0000000..87c8a2c
--- /dev/null
+++ b/examples/functions/seq
@@ -0,0 +1,29 @@
+# Generate a sequence from m to n, m defaults to 1.
+
+seq ()
+{
+ declare -i lo hi i # makes local
+ local _SEQ
+
+ case $# in
+ 1) seq 1 "$1" ; return $? ;;
+ 2) lo=$1 hi=$2
+ i=$lo _SEQ=""
+ while let "i <= hi"; do
+ _SEQ="${_SEQ}$i "
+ let i+=1
+ done
+ echo "${_SEQ# }"
+ return 0 ;;
+ *) echo seq: usage: seq [low] high 1>&2 ; return 2 ;;
+ esac
+}
+
+# like the APL `iota' function (or at least how I remember it :-)
+iota()
+{
+ case $# in
+ 1) seq 1 "$1"; return $?;;
+ *) echo "iota: usage: iota high" 1>&2; return 2;;
+ esac
+}
diff --git a/examples/functions/seq2 b/examples/functions/seq2
new file mode 100644
index 0000000..c3ad95c
--- /dev/null
+++ b/examples/functions/seq2
@@ -0,0 +1,37 @@
+# Generate a sequence from m to n, m defaults to 1.
+
+seq ()
+{
+ declare -i lo hi i # makes local
+ local _SEQ INIT COMPARE STEP
+
+ case "$1" in
+ -r) INIT='i=$hi _SEQ=""' COMPARE='let "i >= $lo"' STEP='let i-=1' ; shift ;;
+ *) INIT='i=$lo _SEQ=""' COMPARE='let "i <= $hi"' STEP='let i+=1' ;;
+ esac
+
+ case $# in
+ 1) lo=1 hi="$1" ;;
+ 2) lo=$1 hi=$2 ;;
+ *) echo seq: usage: seq [-r] [low] high 1>&2 ; return 2 ;;
+ esac
+
+ # equivalent to the as-yet-unimplemented
+ # for (( "$INIT" ; "$COMPARE" ; "$STEP" )); do _SEQ="${_SEQ}$i "; done
+ eval "$INIT"
+ while eval "$COMPARE"; do
+ _SEQ="${_SEQ}$i "
+ eval "$STEP"
+ done
+ echo "${_SEQ# }"
+ return 0
+}
+
+# like the APL `iota' function (or at least how I remember it :-)
+iota()
+{
+ case $# in
+ 1) seq 1 "$1"; return $?;;
+ *) echo "iota: usage: iota high" 1>&2; return 2;;
+ esac
+}
diff --git a/examples/functions/shcat b/examples/functions/shcat
new file mode 100644
index 0000000..c5d3d63
--- /dev/null
+++ b/examples/functions/shcat
@@ -0,0 +1,7 @@
+shcat()
+{
+ while read -r line
+ do
+ echo "$line"
+ done
+}
diff --git a/examples/functions/shcat2 b/examples/functions/shcat2
new file mode 100644
index 0000000..6fe90f4
--- /dev/null
+++ b/examples/functions/shcat2
@@ -0,0 +1,19 @@
+shcat()
+{
+ while read -r line
+ do
+ echo "$line"
+ done
+}
+
+shcat2()
+{
+ while [ $# -ge 1 ]; do
+ case "$1" in
+ -) shcat ;;
+ *) shcat < "$1" ;;
+ esac
+ shift
+ done
+ exit 0
+}
diff --git a/examples/functions/sort-pos-params b/examples/functions/sort-pos-params
new file mode 100644
index 0000000..0052b46
--- /dev/null
+++ b/examples/functions/sort-pos-params
@@ -0,0 +1,50 @@
+# Sort the positional paramters.
+# Make sure the positional parameters are passed as arguments to the function.
+# If -u is the first arg, remove duplicate array members.
+sort_posparams()
+{
+ local -a R
+ local u
+
+ case "$1" in
+ -u) u=-u ; shift ;;
+ esac
+
+ # if you want the case of no positional parameters to return success,
+ # remove the error message and return 0
+ if [ $# -eq 0 ]; then
+ echo "$FUNCNAME: argument expected" >&2
+ return 1
+ fi
+
+ # make R a copy of the positional parameters
+ R=( "${@}" )
+
+ # sort R.
+ R=( $( printf "%s\n" "${R[@]}" | sort $u) )
+
+ printf "%s\n" "${R[@]}"
+ return 0
+}
+
+# will print everything on separate lines
+set -- 3 1 4 1 5 9 2 6 5 3 2
+sort_posparams "$@"
+
+# sets without preserving quoted parameters
+set -- $( sort_posparams "$@" )
+echo "$@"
+echo $#
+
+# sets preserving quoted parameters, beware pos params with embedded newlines
+set -- 'a b' 'a c' 'x z'
+
+oifs=$IFS
+IFS=$'\n'
+set -- $( sort_posparams "$@" )
+IFS="$oifs"
+
+echo "$@"
+echo $#
+
+sort_posparams
diff --git a/examples/functions/substr b/examples/functions/substr
new file mode 100644
index 0000000..a80b3b4
--- /dev/null
+++ b/examples/functions/substr
@@ -0,0 +1,79 @@
+#
+# substr -- a function to emulate the ancient ksh builtin
+#
+
+#
+# -l == shortest from left
+# -L == longest from left
+# -r == shortest from right (the default)
+# -R == longest from right
+
+substr()
+{
+ local flag pat str
+ local usage="usage: substr -lLrR pat string or substr string pat"
+
+ case "$1" in
+ -l | -L | -r | -R)
+ flag="$1"
+ pat="$2"
+ shift 2
+ ;;
+ -*)
+ echo "substr: unknown option: $1"
+ echo "$usage"
+ return 1
+ ;;
+ *)
+ flag="-r"
+ pat="$2"
+ ;;
+ esac
+
+ if [ "$#" -eq 0 ] || [ "$#" -gt 2 ] ; then
+ echo "substr: bad argument count"
+ return 2
+ fi
+
+ str="$1"
+
+ #
+ # We don't want -f, but we don't want to turn it back on if
+ # we didn't have it already
+ #
+ case "$-" in
+ "*f*")
+ ;;
+ *)
+ fng=1
+ set -f
+ ;;
+ esac
+
+ case "$flag" in
+ -l)
+ str="${str#$pat}" # substr -l pat string
+ ;;
+ -L)
+ str="${str##$pat}" # substr -L pat string
+ ;;
+ -r)
+ str="${str%$pat}" # substr -r pat string
+ ;;
+ -R)
+ str="${str%%$pat}" # substr -R pat string
+ ;;
+ *)
+ str="${str%$2}" # substr string pat
+ ;;
+ esac
+
+ echo "$str"
+
+ #
+ # If we had file name generation when we started, re-enable it
+ #
+ if [ "$fng" = "1" ] ; then
+ set +f
+ fi
+}
diff --git a/examples/functions/substr2 b/examples/functions/substr2
new file mode 100644
index 0000000..2bb8d36
--- /dev/null
+++ b/examples/functions/substr2
@@ -0,0 +1,81 @@
+#
+# substr -- a function to emulate the ancient ksh builtin
+#
+
+# -l == remove shortest from left
+# -L == remove longest from left
+# -r == remove shortest from right (the default)
+# -R == remove longest from right
+
+substr()
+{
+ local flag pat str
+ local usage="usage: substr -lLrR pat string or substr string pat"
+ local options="l:L:r:R:"
+
+ OPTIND=1
+ while getopts "$options" c
+ do
+ case "$c" in
+ l | L | r | R)
+ flag="-$c"
+ pat="$OPTARG"
+ ;;
+ '?')
+ echo "$usage"
+ return 1
+ ;;
+ esac
+ done
+
+ if [ "$OPTIND" -gt 1 ] ; then
+ shift $[ $OPTIND -1 ]
+ fi
+
+ if [ "$#" -eq 0 ] || [ "$#" -gt 2 ] ; then
+ echo "substr: bad argument count"
+ return 2
+ fi
+
+ str="$1"
+
+ #
+ # We don't want -f, but we don't want to turn it back on if
+ # we didn't have it already
+ #
+ case "$-" in
+ "*f*")
+ ;;
+ *)
+ fng=1
+ set -f
+ ;;
+ esac
+
+ case "$flag" in
+ -l)
+ str="${str#$pat}" # substr -l pat string
+ ;;
+ -L)
+ str="${str##$pat}" # substr -L pat string
+ ;;
+ -r)
+ str="${str%$pat}" # substr -r pat string
+ ;;
+ -R)
+ str="${str%%$pat}" # substr -R pat string
+ ;;
+ *)
+ str="${str%$2}" # substr string pat
+ ;;
+ esac
+
+ echo "$str"
+
+ #
+ # If we had file name generation when we started, re-enable it
+ #
+ if [ "$fng" = "1" ] ; then
+ set +f
+ fi
+}
diff --git a/examples/functions/term b/examples/functions/term
new file mode 100644
index 0000000..fbe99f1
--- /dev/null
+++ b/examples/functions/term
@@ -0,0 +1,35 @@
+#
+# term -- a shell function to set the terminal type interactively or not.
+#
+
+term()
+{
+ local t
+
+ if [ $# != 0 ] ; then
+ eval $(tset -sQ $1)
+ else # interactive
+ if [ -z "$TERM" ] ; then
+ TERM="unknown"
+ fi
+
+ case "$TERM" in
+ network|dialup|unknown|lat)
+ TERM=unknown
+ ;;
+ *)
+ eval $(tset -sQ)
+ ;;
+ esac
+
+ while [ "$TERM" = "unknown" ] ; do
+ echo -n "Terminal type: "
+ read t
+ if [ -n "$t" ] ; then
+ eval $(tset -sQ $t)
+ fi
+ done
+ fi
+}
+
+
diff --git a/examples/functions/whatis b/examples/functions/whatis
new file mode 100644
index 0000000..56c5a58
--- /dev/null
+++ b/examples/functions/whatis
@@ -0,0 +1,52 @@
+#
+# whatis -- and implementation of the 10th Edition Unix sh builtin `whatis'
+# command.
+#
+# usage: whatis arg [...]
+#
+# For each argument, whatis prints the associated value as a parameter,
+# builtin, function, alias, or executable file as appropriate. In each
+# case, the value is printed in a form which would yield the same value
+# if typed as input to the shell itself.
+#
+
+whatis()
+{
+ local wusage='usage: whatis arg [arg...]'
+ local fail=0
+
+ if [ $# -eq 0 ] ; then
+ echo "$wusage"
+ return 1
+ fi
+
+ for arg
+ do
+ case $(builtin type -type $arg 2>/dev/null) in
+ "alias")
+ builtin alias "$arg"
+ ;;
+ "function")
+ builtin type "$arg" | sed 1d
+ ;;
+ "builtin")
+ echo builtin "$arg"
+ ;;
+ "file")
+ builtin type -path "$arg"
+ ;;
+ *)
+ # OK, we could have a variable, or we could have nada
+ if [ "$(eval echo \${$arg+set})" = "set" ] ; then
+ # It is a variable, and it is set
+ echo -n "$arg="
+ eval echo '\"'\$$arg'\"'
+ else
+ echo whatis: $arg: not found
+ fail=1
+ fi
+ ;;
+ esac
+ done
+ return $fail
+}
diff --git a/examples/functions/whence b/examples/functions/whence
new file mode 100644
index 0000000..70b2322
--- /dev/null
+++ b/examples/functions/whence
@@ -0,0 +1,59 @@
+#
+# An almost-ksh compatible `whence' command. This is as hairy as it is
+# because of the desire to exactly mimic ksh.
+#
+# This depends somewhat on knowing the format of the output of the bash
+# `builtin type' command.
+#
+# Chet Ramey
+# chet@ins.CWRU.Edu
+#
+whence()
+{
+ local vflag= path=
+
+ if [ "$#" = "0" ] ; then
+ echo "whence: argument expected"
+ return 1
+ fi
+ case "$1" in
+ -v) vflag=1
+ shift 1
+ ;;
+ -*) echo "whence: bad option: $1"
+ return 1
+ ;;
+ *) ;;
+ esac
+
+ if [ "$#" = "0" ] ; then
+ echo "whence: bad argument count"
+ return 1
+ fi
+
+ for cmd
+ do
+ if [ "$vflag" ] ; then
+ echo $(builtin type $cmd | sed 1q)
+ else
+ path=$(builtin type -path $cmd)
+ if [ "$path" ] ; then
+ echo $path
+ else
+ case "$cmd" in
+ /*) if [ -x "$cmd" ]; then
+ echo "$cmd"
+ fi
+ ;;
+ *) case "$(builtin type -type $cmd)" in
+ "") ;;
+ *) echo "$cmd"
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ fi
+ done
+ return 0
+}
diff --git a/examples/functions/which b/examples/functions/which
new file mode 100644
index 0000000..ca33703
--- /dev/null
+++ b/examples/functions/which
@@ -0,0 +1,44 @@
+#
+# which - emulation of `which' as it appears in FreeBSD
+#
+# usage: which [-as] command [command...]
+#
+
+which()
+{
+ local aflag sflag ES a opt
+
+ OPTIND=1
+ while builtin getopts as opt ; do
+ case "$opt" in
+ a) aflag=-a ;;
+ s) sflag=1 ;;
+ ?) echo "which: usage: which [-as] command [command ...]" >&2
+ exit 2 ;;
+ esac
+ done
+
+ (( $OPTIND > 1 )) && shift $(( $OPTIND - 1 ))
+
+ # without command arguments, exit with status 1
+ ES=1
+
+ # exit status is 0 if all commands are found, 1 if any are not found
+ for command; do
+ # if $command is a function, make sure we add -a so type
+ # will look in $PATH after finding the function
+ a=$aflag
+ case "$(builtin type -t $command)" in
+ "function") a=-a;;
+ esac
+
+ if [ -n "$sflag" ]; then
+ builtin type -p $a $command >/dev/null 2>&1
+ else
+ builtin type -p $a $command
+ fi
+ ES=$?
+ done
+
+ return $ES
+}
diff --git a/examples/functions/xalias.bash b/examples/functions/xalias.bash
new file mode 100644
index 0000000..88a00dc
--- /dev/null
+++ b/examples/functions/xalias.bash
@@ -0,0 +1,22 @@
+# xalias - convert csh alias commands to bash functions
+# from Mohit Aron <aron@cs.rice.edu>
+# posted to usenet as <4i5p17$bnu@larry.rice.edu>
+function xalias ()
+{
+ if [ "x$2" = "x" ]
+ then
+ declare -f $1
+ else
+ case $2 in
+ *[#\!]*)
+ comm=$(echo $2 | sed 's/\\!\*/\"$\@\"/g
+ s/\\!:\([1-9]\)/\"$\1\"/g
+ s/#/\\#/g')
+ ;;
+ *)
+ comm="$2 \"\$@\"" ;;
+ esac
+
+ eval function $1 \(\) "{" command "$comm" "; }"
+ fi
+}
diff --git a/examples/functions/xfind.bash b/examples/functions/xfind.bash
new file mode 100644
index 0000000..6d29038
--- /dev/null
+++ b/examples/functions/xfind.bash
@@ -0,0 +1,52 @@
+#! /bin/bash
+#From: kaz@cafe.net (Kaz Kylheku)
+#Newsgroups: comp.unix.shell
+#Subject: Why not roll your own @#$% find! (was: splitting directory off from filename)
+#Message-ID: <6n1117$tp1@espresso.cafe.net>
+#Date: Fri, 26 Jun 1998 20:47:34 GMT
+
+# $1 = dirname, $2 = pattern, optional $3 = action
+xfind()
+{
+ local x
+ local dir="$1"
+
+ # descend into specified directory
+
+ builtin cd -L "$1" || {
+ echo "${FUNCNAME}: cannot change dir to $1" >&2
+ return 1
+ }
+
+ #
+ # default action is to print the filename
+ #
+ if [ -n "$3" ]; then
+ action="$3"
+ else
+ action='printf -- "%s\n"'
+ fi
+
+ # process ordinary files that match pattern
+
+ for x in $2 ; do
+ if [ -f "$x" ] ; then
+ eval "$action" "$x"
+ fi
+ done
+
+ # now descend into subdirectories, avoiding symbolic links
+ # and directories that start with a period.
+
+ for x in * ; do
+ if [ -d "$x" ] && [ ! -L "$x" ] ; then
+ $FUNCNAME "$x" "$2" "$action"
+ fi
+ done
+
+ # finally, pop back up
+
+ builtin cd -L ..
+}
+
+#xfind "$@"