commit bash-20060316 snapshot

This commit is contained in:
Chet Ramey
2011-12-07 09:05:27 -05:00
parent 97be3d8ed9
commit 28157acd2d
1546 changed files with 713954 additions and 55608 deletions
+822
View File
@@ -0,0 +1,822 @@
<table border=1>
<tr>
<th>Path</th>
<th>Description</th>
<th>X-Ref</th>
</tr>
<tr>
<td>./bashdb</td>
<td>Deprecated sample implementation of a bash debugger</td>
</tr>
<tr>
</tr>
<tr>
<td>./complete</td>
<td>Shell completion code</td>
</tr>
<tr>
</tr>
<tr>
<td>./functions</td>
<td>Example functions</td>
</tr>
<tr>
<td>./functions/array-stuff</td>
<td>Various array functions (ashift, array_sort, reverse).</td>
</tr>
<tr>
<td>./functions/array-to-string</td>
<td>Convert an array to a string.</td>
</tr>
<tr>
<td>./functions/autoload</td>
<td>An almost ksh-compatible 'autoload' (no lazy load).</td>
<td>ksh</td>
</tr>
<tr>
<td>./functions/autoload.v2</td>
<td>An almost ksh-compatible 'autoload' (no lazy load).</td>
<td>ksh</td>
</tr>
<tr>
<td>./functions/autoload.v3</td>
<td>A more ksh-compatible 'autoload' (with lazy load).</td>
<td>ksh</td>
</tr>
<tr>
<td>./functions/basename</td>
<td>A replacement for basename(1).</td>
<td>basename</td>
</tr>
<tr>
<td>./functions/basename2</td>
<td>Fast basename(1) and dirname(1) functions for BASH/SH.</td>
<td>basename, dirname</td>
</tr>
<tr>
<td>./functions/coproc.bash</td>
<td>Start, control, and end coprocesses.</td>
</tr>
<tr>
<td>./functions/coshell.bash</td>
<td>Control shell coprocesses (see coprocess.bash).</td>
</tr>
<tr>
<td>./functions/coshell.README</td>
<td>README for coshell and coproc.</td>
</tr>
<tr>
<td>./functions/csh-compat</td>
<td>A C-shell compatibility package.</td>
<td>csh</td>
</tr>
<tr>
<td>./functions/dirfuncs</td>
<td>Directory manipulation functions from the book 'The Korn Shell'.</td>
</tr>
<tr>
<td>./functions/dirname</td>
<td>A replacement for dirname(1).</td>
<td>dirname</td>
</tr>
<tr>
<td>./functions/emptydir</td>
<td>Find out if a directory is empty.</td>
</tr>
<tr>
<td>./functions/exitstat</td>
<td>Display the exit status of processes.</td>
</tr>
<tr>
<td>./functions/external</td>
<td>Like 'command' but FORCES use of external command.</td>
</tr>
<tr>
<td>./functions/fact</td>
<td>Recursive factorial function.</td>
</tr>
<tr>
<td>./functions/fstty</td>
<td>Front end to sync TERM changes to both stty(1) and readline 'bind'.</td>
<td>stty.bash</td>
</tr>
<tr>
<td>./functions/func</td>
<td>Print out definitions for functions named by arguments.</td>
</tr>
<tr>
<td>./functions/gethtml</td>
<td>Get a web page from a remote server (wget(1) in bash!).</td>
</tr>
<tr>
<td>./functions/getoptx.bash</td>
<td>getopt function that parses long-named options.</td>
</tr>
<tr>
<td>./functions/inetaddr</td>
<td>Internet address conversion (inet2hex & hex2inet).</td>
</tr>
<tr>
<td>./functions/inpath</td>
<td>Return zero if the argument is in the path and executable.</td>
<td>inpath</td>
</tr>
<tr>
<td>./functions/isnum.bash</td>
<td>Test user input on numeric or character value.</td>
</tr>
<tr>
<td>./functions/isnum2</td>
<td>Test user input on numeric values, with floating point.</td>
</tr>
<tr>
<td>./functions/isvalidip</td>
<td>Test user input for valid IP Addresses.</td>
</tr>
<tr>
<td>./functions/jdate.bash</td>
<td>Julian date conversion.</td>
</tr>
<tr>
<td>./functions/jj.bash</td>
<td>Look for running jobs.</td>
</tr>
<tr>
<td>./functions/keep</td>
<td>Try to keep some programs in the forground and running.</td>
</tr>
<tr>
<td>./functions/ksh-cd</td>
<td>ksh-like 'cd': cd [-LP] [dir [change]].</td>
<td>ksh</td>
</tr>
<tr>
<td>./functions/ksh-compat-test</td>
<td>ksh-like arithmetic test replacements.</td>
<td>ksh</td>
</tr>
<tr>
<td>./functions/kshenv</td>
<td>Functions and aliases to provide the beginnings of a ksh environment for bash.</td>
<td>ksh</td>
</tr>
<tr>
<td>./functions/login</td>
<td>Replace the 'login' and 'newgrp' builtins in old Bourne shells.</td>
</tr>
<tr>
<td>./functions/lowercase</td>
<td>Rename files to lower case.</td>
<td>rename lower</td>
</tr>
<tr>
<td>./functions/manpage</td>
<td>Find and print a manual page.</td>
<td>fman</td>
</tr>
<tr>
<td>./functions/mhfold</td>
<td>Print MH folders, useful only because folders(1) doesn't print mod date/times.</td>
</tr>
<tr>
<td>./functions/notify.bash</td>
<td>Notify when jobs change status.</td>
</tr>
<tr>
<td>./functions/pathfuncs</td>
<td>Path related functions (no_path, add_path, pre-path, del_path).</td>
<td>path</td>
</tr>
<tr>
<td>./functions/README</td>
<td>README</td>
</tr>
<tr>
<td>./functions/recurse</td>
<td>Recursive directory traverser.</td>
</tr>
<tr>
<td>./functions/repeat2</td>
<td>A clone of C shell builtin 'repeat'.</td>
<td>repeat, csh</td>
</tr>
<tr>
<td>./functions/repeat3</td>
<td>A clone of C shell builtin 'repeat'.</td>
<td>repeat, csh</td>
</tr>
<tr>
<td>./functions/seq</td>
<td>Generate a sequence from m to n, m defaults to 1.</td>
</tr>
<tr>
<td>./functions/seq2</td>
<td>Generate a sequence from m to n, m defaults to 1.</td>
</tr>
<tr>
<td>./functions/shcat</td>
<td>Readline-based pager.</td>
<td>cat, readline pager</td>
</tr>
<tr>
<td>./functions/shcat2</td>
<td>Readline-based pagers.</td>
<td>cat, readline pager</td>
</tr>
<tr>
<td>./functions/sort-pos-params</td>
<td>Sort the positional parameters.</td>
</tr>
<tr>
<td>./functions/substr</td>
<td>A function to emulate the ancient ksh builtin.</td>
<td>ksh</td>
</tr>
<tr>
<td>./functions/substr2</td>
<td>A function to emulate the ancient ksh builtin.</td>
<td>ksh</td>
</tr>
<tr>
<td>./functions/term</td>
<td>A shell function to set the terminal type interactively or not.</td>
</tr>
<tr>
<td>./functions/whatis</td>
<td>An implementation of the 10th Edition Unix sh builtin 'whatis(1)' command.</td>
</tr>
<tr>
<td>./functions/whence</td>
<td>An almost-ksh compatible 'whence(1)' command.</td>
</tr>
<tr>
<td>./functions/which</td>
<td>An emulation of 'which(1)' as it appears in FreeBSD.</td>
</tr>
<tr>
<td>./functions/xalias.bash</td>
<td>Convert csh alias commands to bash functions.</td>
<td>csh, aliasconv</td>
</tr>
<tr>
<td>./functions/xfind.bash</td>
<td>A 'find(1)' clone.</td>
</tr>
<tr>
</tr>
<tr>
<td>./loadables/</td>
<td>Example loadable replacements</td>
</tr>
<tr>
<td>./loadables/basename.c</td>
<td>Return non-directory portion of pathname.</td>
<td>basename</td>
</tr>
<tr>
<td>./loadables/cat.c</td>
<td>cat(1) replacement with no options - the way cat was intended.</td>
<td>cat, readline pager</td>
</tr>
<tr>
<td>./loadables/cut.c</td>
<td>cut(1) replacement.</td>
</tr>
<tr>
<td>./loadables/dirname.c</td>
<td>Return directory portion of pathname.</td>
<td>dirname</td>
</tr>
<tr>
<td>./loadables/finfo.c</td>
<td>Print file info.</td>
</tr>
<tr>
<td>./loadables/getconf.c</td>
<td>POSIX.2 getconf utility.</td>
</tr>
<tr>
<td>./loadables/getconf.h</td>
<td>Replacement definitions for ones the system doesn't provide.</td>
</tr>
<tr>
<td>./loadables/head.c</td>
<td>Copy first part of files.</td>
</tr>
<tr>
<td>./loadables/hello.c</td>
<td>Obligatory "Hello World" / sample loadable.</td>
</tr>
<tr>
<td>./loadables/id.c</td>
<td>POSIX.2 user identity.</td>
</tr>
<tr>
<td>./loadables/ln.c</td>
<td>Make links.</td>
</tr>
<tr>
<td>./loadables/logname.c</td>
<td>Print login name of current user.</td>
</tr>
<tr>
<td>./loadables/Makefile.in</td>
<td>Simple makefile for the sample loadable builtins.</td>
</tr>
<tr>
<td>./loadables/mkdir.c</td>
<td>Make directories.</td>
</tr>
<tr>
<td>./loadables/necho.c</td>
<td>echo without options or argument interpretation.</td>
</tr>
<tr>
<td>./loadables/pathchk.c</td>
<td>Check pathnames for validity and portability.</td>
</tr>
<tr>
<td>./loadables/print.c</td>
<td>Loadable ksh-93 style print builtin.</td>
</tr>
<tr>
<td>./loadables/printenv.c</td>
<td>Minimal builtin clone of BSD printenv(1).</td>
</tr>
<tr>
<td>./loadables/push.c</td>
<td>Anyone remember TOPS-20?</td>
</tr>
<tr>
<td>./loadables/README</td>
<td>README</td>
</tr>
<tr>
<td>./loadables/realpath.c</td>
<td>Canonicalize pathnames, resolving symlinks.</td>
</tr>
<tr>
<td>./loadables/rmdir.c</td>
<td>Remove directory.</td>
</tr>
<tr>
<td>./loadables/sleep.c</td>
<td>sleep for fractions of a second.</td>
</tr>
<tr>
<td>./loadables/strftime.c</td>
<td>Loadable builtin interface to strftime(3).</td>
</tr>
<tr>
<td>./loadables/sync.c</td>
<td>Sync the disks by forcing pending filesystem writes to complete.</td>
</tr>
<tr>
<td>./loadables/tee.c</td>
<td>Duplicate standard input.</td>
</tr>
<tr>
<td>./loadables/template.c</td>
<td>Example template for loadable builtin.</td>
</tr>
<tr>
<td>./loadables/truefalse.c</td>
<td>True and false builtins.</td>
</tr>
<tr>
<td>./loadables/tty.c</td>
<td>Return terminal name.</td>
</tr>
<tr>
<td>./loadables/uname.c</td>
<td>Print system information.</td>
</tr>
<tr>
<td>./loadables/unlink.c</td>
<td>Remove a directory entry.</td>
</tr>
<tr>
<td>./loadables/whoami.c</td>
<td>Print out username of current user.</td>
</tr>
<tr>
</tr>
<tr>
<td>./loadables/perl/</td>
<td>Illustrate how to build a Perl interpreter into bash.</td>
</tr>
<tr>
</tr>
<tr>
<td>./misc</td>
<td>Miscellaneous</td>
</tr>
<tr>
<td>./misc/aliasconv.bash</td>
<td>Convert csh aliases to bash aliases and functions.</td>
<td>csh, xalias</td>
</tr>
<tr>
<td>./misc/aliasconv.sh</td>
<td>Convert csh aliases to bash aliases and functions.</td>
<td>csh, xalias</td>
</tr>
<tr>
<td>./misc/cshtobash</td>
<td>Convert csh aliases, environment variables, and variables to bash equivalents.</td>
<td>csh, xalias</td>
</tr>
<tr>
<td>./misc/README</td>
<td>README</td>
</tr>
<tr>
<td>./misc/suncmd.termcap</td>
<td>SunView TERMCAP string.</td>
</tr>
<tr>
</tr>
<tr>
<td>./obashdb</td>
<td>Modified version of the Korn Shell debugger from Bill Rosenblatt's 'Learning the Korn Shell'.</td>
</tr>
<tr>
</tr>
<tr>
<td>./scripts.noah</td>
<td>Noah Friedman's collection of scripts (updated to bash v2 syntax by Chet Ramey)</td>
</tr>
<tr>
<td>./scripts.noah/aref.bash</td>
<td>Pseudo-arrays and substring indexing examples.</td>
</tr>
<tr>
<td>./scripts.noah/bash.sub.bash</td>
<td>Library functions used by require.bash.</td>
</tr>
<tr>
<td>./scripts.noah/bash_version.bash</td>
<td>A function to slice up $BASH_VERSION.</td>
</tr>
<tr>
<td>./scripts.noah/meta.bash</td>
<td>Enable and disable eight-bit readline input.</td>
</tr>
<tr>
<td>./scripts.noah/mktmp.bash</td>
<td>Make a temporary file with a unique name.</td>
</tr>
<tr>
<td>./scripts.noah/number.bash</td>
<td>A fun hack to translate numerals into English.</td>
</tr>
<tr>
<td>./scripts.noah/PERMISSION</td>
<td>Permissions to use the scripts in this directory.</td>
</tr>
<tr>
<td>./scripts.noah/prompt.bash</td>
<td>A way to set PS1 to some predefined strings.</td>
</tr>
<tr>
<td>./scripts.noah/README</td>
<td>README</td>
</tr>
<tr>
<td>./scripts.noah/remap_keys.bash</td>
<td>A front end to 'bind' to redo readline bindings.</td>
</tr>
<tr>
<td>./scripts.noah/require.bash</td>
<td>Lisp-like require/provide library functions for bash.</td>
</tr>
<tr>
<td>./scripts.noah/send_mail.bash</td>
<td>Replacement SMTP client written in bash.</td>
</tr>
<tr>
<td>./scripts.noah/shcat.bash</td>
<td>Bash replacement for 'cat(1)'.</td>
<td>cat</td>
</tr>
<tr>
<td>./scripts.noah/source.bash</td>
<td>Replacement for source that uses current directory.</td>
</tr>
<tr>
<td>./scripts.noah/string.bash</td>
<td>The string(3) functions at the shell level.</td>
</tr>
<tr>
<td>./scripts.noah/stty.bash</td>
<td>Front-end to stty(1) that changes readline bindings too.</td>
<td>fstty</td>
</tr>
<tr>
<td>./scripts.noah/y_or_n_p.bash</td>
<td>Prompt for a yes/no/quit answer.</td>
<td>ask</td>
</tr>
<tr>
</tr>
<tr>
<td>./scripts.v2</td>
<td>John DuBois' ksh script collection (converted to bash v2 syntax by Chet Ramey).</td>
</tr>
<tr>
<td>./scripts.v2/arc2tarz</td>
<td>Convert an "arc" archive to a compressed tar archive.</td>
</tr>
<tr>
<td>./scripts.v2/bashrand</td>
<td>Random number generator with upper and lower bounds and optional seed.</td>
<td>random</td>
</tr>
<tr>
<td>./scripts.v2/cal2day.bash</td>
<td>Convert a day number to a name.</td>
</tr>
<tr>
<td>./scripts.v2/cdhist.bash</td>
<td>cd replacement with a directory stack added.</td>
</tr>
<tr>
<td>./scripts.v2/corename</td>
<td>Tell what produced a core file.</td>
</tr>
<tr>
<td>./scripts.v2/fman</td>
<td>Fast man(1) replacement.</td>
<td>manpage</td>
</tr>
<tr>
<td>./scripts.v2/frcp</td>
<td>Copy files using ftp(1) but with rcp-type command line syntax.</td>
</tr>
<tr>
<td>./scripts.v2/lowercase</td>
<td>Change filenames to lower case.</td>
<td>rename lower</td>
</tr>
<tr>
<td>./scripts.v2/ncp</td>
<td>A nicer front end for cp(1) (has -i, etc.).</td>
</tr>
<tr>
<td>./scripts.v2/newext</td>
<td>Change the extension of a group of files.</td>
<td>rename</td>
</tr>
<tr>
<td>./scripts.v2/nmv</td>
<td>A nicer front end for mv(1) (has -i, etc.).</td>
<td>rename</td>
</tr>
<tr>
<td>./scripts.v2/pages</td>
<td>Print specified pages from files.</td>
</tr>
<tr>
<td>./scripts.v2/PERMISSION</td>
<td>Permissions to use the scripts in this directory.</td>
</tr>
<tr>
<td>./scripts.v2/pf</td>
<td>A pager front end that handles compressed files.</td>
</tr>
<tr>
<td>./scripts.v2/pmtop</td>
<td>Poor man's 'top(1)' for SunOS 4.x and BSD/OS.</td>
</tr>
<tr>
<td>./scripts.v2/README</td>
<td>README</td>
</tr>
<tr>
<td>./scripts.v2/ren</td>
<td>Rename files by changing parts of filenames that match a pattern.</td>
<td>rename</td>
</tr>
<tr>
<td>./scripts.v2/rename</td>
<td>Change the names of files that match a pattern.</td>
<td>rename</td>
</tr>
<tr>
<td>./scripts.v2/repeat</td>
<td>Execute a command multiple times.</td>
<td>repeat</td>
</tr>
<tr>
<td>./scripts.v2/shprof</td>
<td>Line profiler for bash scripts.</td>
</tr>
<tr>
<td>./scripts.v2/untar</td>
<td>Unarchive a (possibly compressed) tarfile into a directory.</td>
</tr>
<tr>
<td>./scripts.v2/uudec</td>
<td>Carefully uudecode(1) multiple files.</td>
</tr>
<tr>
<td>./scripts.v2/uuenc</td>
<td>uuencode(1) multiple files.</td>
</tr>
<tr>
<td>./scripts.v2/vtree</td>
<td>Print a visual display of a directory tree.</td>
<td>tree</td>
</tr>
<tr>
<td>./scripts.v2/where</td>
<td>Show where commands that match a pattern are.</td>
</tr>
<tr>
</tr>
<tr>
<td>./scripts</td>
<td>Example scripts</td>
</tr>
<tr>
<td>./scripts/adventure.sh</td>
<td>Text adventure game in bash!</td>
</tr>
<tr>
<td>./scripts/bcsh.sh</td>
<td>Bourne shell cshell-emulator.</td>
<td>csh</td>
</tr>
<tr>
<td>./scripts/cat.sh</td>
<td>Readline-based pager.</td>
<td>cat, readline pager</td>
</tr>
<tr>
<td>./scripts/center</td>
<td>Center - center a group of lines.</td>
</tr>
<tr>
<td>./scripts/dd-ex.sh</td>
<td>Line editor using only /bin/sh, /bin/dd and /bin/rm.</td>
</tr>
<tr>
<td>./scripts/fixfiles.bash</td>
<td>Recurse a tree and fix files containing various "bad" chars.</td>
</tr>
<tr>
<td>./scripts/hanoi.bash</td>
<td>The inevitable Towers of Hanoi in bash.</td>
</tr>
<tr>
<td>./scripts/inpath</td>
<td>Search $PATH for a file the same name as $1; return TRUE if found.</td>
<td>inpath</td>
</tr>
<tr>
<td>./scripts/krand.bash</td>
<td>Produces a random number within integer limits.</td>
<td>random</td>
</tr>
<tr>
<td>./scripts/line-input.bash</td>
<td>Line input routine for GNU Bourne-Again Shell plus terminal-control primitives.</td>
</tr>
<tr>
<td>./scripts/nohup.bash</td>
<td>bash version of 'nohup' command.</td>
</tr>
<tr>
<td>./scripts/precedence</td>
<td>Test relative precedences for '&&' and '||' operators.</td>
</tr>
<tr>
<td>./scripts/randomcard.bash</td>
<td>Print a random card from a card deck.</td>
<td>random</td>
</tr>
<tr>
<td>./scripts/README</td>
<td>README</td>
</tr>
<tr>
<td>./scripts/scrollbar</td>
<td>Display scrolling text.</td>
</tr>
<tr>
<td>./scripts/scrollbar2</td>
<td>Display scrolling text.</td>
</tr>
<tr>
<td>./scripts/self-repro</td>
<td>A self-reproducing script (careful!)</td>
</tr>
<tr>
<td>./scripts/showperm.bash</td>
<td>Convert ls(1) symbolic permissions into octal mode.</td>
</tr>
<tr>
<td>./scripts/shprompt</td>
<td>Display a prompt and get an answer satisfying certain criteria.</td>
<td>ask</td>
</tr>
<tr>
<td>./scripts/spin.bash</td>
<td>Display a 'spinning wheel' to show progress.</td>
</tr>
<tr>
<td>./scripts/timeout</td>
<td>Give rsh(1) a shorter timeout.</td>
</tr>
<tr>
<td>./scripts/vtree2</td>
<td>Display a tree printout of dir in 1k blocks.</td>
<td>tree</td>
</tr>
<tr>
<td>./scripts/vtree3</td>
<td>Display a graphical tree printout of dir.</td>
<td>tree</td>
</tr>
<tr>
<td>./scripts/vtree3a</td>
<td>Display a graphical tree printout of dir.</td>
<td>tree</td>
</tr>
<tr>
<td>./scripts/websrv.sh</td>
<td>A web server in bash!</td>
</tr>
<tr>
<td>./scripts/xterm_title</td>
<td>Print the contents of the xterm title bar.</td>
</tr>
<tr>
<td>./scripts/zprintf</td>
<td>Emulate printf (obsolete since it's now a bash builtin).</td>
</tr>
<tr>
</tr>
<tr>
<td>./startup-files</td>
<td>Example Start-up files.</td>
</tr>
<tr>
<td>./startup-files/Bash_aliases</td>
<td>Some useful aliases (Fox).</td>
</tr>
<tr>
<td>./startup-files/Bash_profile</td>
<td>Sample startup file for bash login shells (Fox).</td>
</tr>
<tr>
<td>./startup-files/bash-profile</td>
<td>Sample startup file for bash login shells (Ramey).</td>
</tr>
<tr>
<td>./startup-files/bashrc</td>
<td>Sample Bourne Again SHell init file (Ramey).</td>
</tr>
<tr>
<td>./startup-files/Bashrc.bfox</td>
<td>Sample Bourne Again SHell init file (Fox).</td>
</tr>
<tr>
<td>./startup-files/README</td>
<td>README</td>
</tr>
<tr>
</tr>
<tr>
<td>./startup-files/apple</td>
<td>Example Start-up files for Mac OS X.</td>
</tr>
<tr>
<td>./startup-files/apple/aliases</td>
<td>Sample aliases for Mac OS X.</td>
</tr>
<tr>
<td>./startup-files/apple/bash.defaults</td>
<td>Sample User preferences file.</td>
</tr>
<tr>
<td>./startup-files/apple/environment</td>
<td>Sample Bourne Again Shell environment file.</td>
</tr>
<tr>
<td>./startup-files/apple/login</td>
<td>Sample login wrapper.</td>
</tr>
<tr>
<td>./startup-files/apple/logout</td>
<td>Sample logout wrapper.</td>
</tr>
<tr>
<td>./startup-files/apple/rc</td>
<td>Sample Bourne Again Shell config file.</td>
</tr>
<tr>
<td>./startup-files/apple/README</td>
<td>README</td>
</tr>
</table>
+198
View File
@@ -0,0 +1,198 @@
Path Description X-Ref
./bashdb Deprecated sample implementation of a bash debugger
./complete Shell completion code
./functions Example functions
./functions/array-stuff Various array functions (ashift, array_sort, reverse).
./functions/array-to-string Convert an array to a string.
./functions/autoload An almost ksh-compatible 'autoload' (no lazy load). ksh
./functions/autoload.v2 An almost ksh-compatible 'autoload' (no lazy load). ksh
./functions/autoload.v3 A more ksh-compatible 'autoload' (with lazy load). ksh
./functions/basename A replacement for basename(1). basename
./functions/basename2 Fast basename(1) and dirname(1) functions for BASH/SH. basename, dirname
./functions/coproc.bash Start, control, and end coprocesses.
./functions/coshell.bash Control shell coprocesses (see coprocess.bash).
./functions/coshell.README README for coshell and coproc.
./functions/csh-compat A C-shell compatibility package. csh
./functions/dirfuncs Directory manipulation functions from the book 'The Korn Shell'.
./functions/dirname A replacement for dirname(1). dirname
./functions/emptydir Find out if a directory is empty.
./functions/exitstat Display the exit status of processes.
./functions/external Like 'command' but FORCES use of external command.
./functions/fact Recursive factorial function.
./functions/fstty Front end to sync TERM changes to both stty(1) and readline 'bind'. stty.bash
./functions/func Print out definitions for functions named by arguments.
./functions/gethtml Get a web page from a remote server (wget(1) in bash!).
./functions/getoptx.bash getopt function that parses long-named options.
./functions/inetaddr Internet address conversion (inet2hex & hex2inet).
./functions/inpath Return zero if the argument is in the path and executable. inpath
./functions/isnum.bash Test user input on numeric or character value.
./functions/isnum2 Test user input on numeric values, with floating point.
./functions/isvalidip Test user input for valid IP Addresses.
./functions/jdate.bash Julian date conversion.
./functions/jj.bash Look for running jobs.
./functions/keep Try to keep some programs in the forground and running.
./functions/ksh-cd ksh-like 'cd': cd [-LP] [dir [change]]. ksh
./functions/ksh-compat-test ksh-like arithmetic test replacements. ksh
./functions/kshenv Functions and aliases to provide the beginnings of a ksh environment for bash. ksh
./functions/login Replace the 'login' and 'newgrp' builtins in old Bourne shells.
./functions/lowercase Rename files to lower case. rename lower
./functions/manpage Find and print a manual page. fman
./functions/mhfold Print MH folders, useful only because folders(1) doesn't print mod date/times.
./functions/notify.bash Notify when jobs change status.
./functions/pathfuncs Path related functions (no_path, add_path, pre-path, del_path). path
./functions/README README
./functions/recurse Recursive directory traverser.
./functions/repeat2 A clone of C shell builtin 'repeat'. repeat, csh
./functions/repeat3 A clone of C shell builtin 'repeat'. repeat, csh
./functions/seq Generate a sequence from m to n, m defaults to 1.
./functions/seq2 Generate a sequence from m to n, m defaults to 1.
./functions/shcat Readline-based pager. cat, readline pager
./functions/shcat2 Readline-based pagers. cat, readline pager
./functions/sort-pos-params Sort the positional parameters.
./functions/substr A function to emulate the ancient ksh builtin. ksh
./functions/substr2 A function to emulate the ancient ksh builtin. ksh
./functions/term A shell function to set the terminal type interactively or not.
./functions/whatis An implementation of the 10th Edition Unix sh builtin 'whatis(1)' command.
./functions/whence An almost-ksh compatible 'whence(1)' command.
./functions/which An emulation of 'which(1)' as it appears in FreeBSD.
./functions/xalias.bash Convert csh alias commands to bash functions. csh, aliasconv
./functions/xfind.bash A 'find(1)' clone.
./loadables/ Example loadable replacements
./loadables/basename.c Return non-directory portion of pathname. basename
./loadables/cat.c cat(1) replacement with no options - the way cat was intended. cat, readline pager
./loadables/cut.c cut(1) replacement.
./loadables/dirname.c Return directory portion of pathname. dirname
./loadables/finfo.c Print file info.
./loadables/getconf.c POSIX.2 getconf utility.
./loadables/getconf.h Replacement definitions for ones the system doesn't provide.
./loadables/head.c Copy first part of files.
./loadables/hello.c Obligatory "Hello World" / sample loadable.
./loadables/id.c POSIX.2 user identity.
./loadables/ln.c Make links.
./loadables/logname.c Print login name of current user.
./loadables/Makefile.in Simple makefile for the sample loadable builtins.
./loadables/mkdir.c Make directories.
./loadables/necho.c echo without options or argument interpretation.
./loadables/pathchk.c Check pathnames for validity and portability.
./loadables/print.c Loadable ksh-93 style print builtin.
./loadables/printenv.c Minimal builtin clone of BSD printenv(1).
./loadables/push.c Anyone remember TOPS-20?
./loadables/README README
./loadables/realpath.c Canonicalize pathnames, resolving symlinks.
./loadables/rmdir.c Remove directory.
./loadables/sleep.c sleep for fractions of a second.
./loadables/strftime.c Loadable builtin interface to strftime(3).
./loadables/sync.c Sync the disks by forcing pending filesystem writes to complete.
./loadables/tee.c Duplicate standard input.
./loadables/template.c Example template for loadable builtin.
./loadables/truefalse.c True and false builtins.
./loadables/tty.c Return terminal name.
./loadables/uname.c Print system information.
./loadables/unlink.c Remove a directory entry.
./loadables/whoami.c Print out username of current user.
./loadables/perl/ Illustrate how to build a Perl interpreter into bash.
./misc Miscellaneous
./misc/aliasconv.bash Convert csh aliases to bash aliases and functions. csh, xalias
./misc/aliasconv.sh Convert csh aliases to bash aliases and functions. csh, xalias
./misc/cshtobash Convert csh aliases, environment variables, and variables to bash equivalents. csh, xalias
./misc/README README
./misc/suncmd.termcap SunView TERMCAP string.
./obashdb Modified version of the Korn Shell debugger from Bill Rosenblatt's 'Learning the Korn Shell'.
./scripts.noah Noah Friedman's collection of scripts (updated to bash v2 syntax by Chet Ramey)
./scripts.noah/aref.bash Pseudo-arrays and substring indexing examples.
./scripts.noah/bash.sub.bash Library functions used by require.bash.
./scripts.noah/bash_version.bash A function to slice up $BASH_VERSION.
./scripts.noah/meta.bash Enable and disable eight-bit readline input.
./scripts.noah/mktmp.bash Make a temporary file with a unique name.
./scripts.noah/number.bash A fun hack to translate numerals into English.
./scripts.noah/PERMISSION Permissions to use the scripts in this directory.
./scripts.noah/prompt.bash A way to set PS1 to some predefined strings.
./scripts.noah/README README
./scripts.noah/remap_keys.bash A front end to 'bind' to redo readline bindings.
./scripts.noah/require.bash Lisp-like require/provide library functions for bash.
./scripts.noah/send_mail.bash Replacement SMTP client written in bash.
./scripts.noah/shcat.bash Bash replacement for 'cat(1)'. cat
./scripts.noah/source.bash Replacement for source that uses current directory.
./scripts.noah/string.bash The string(3) functions at the shell level.
./scripts.noah/stty.bash Front-end to stty(1) that changes readline bindings too. fstty
./scripts.noah/y_or_n_p.bash Prompt for a yes/no/quit answer. ask
./scripts.v2 John DuBois' ksh script collection (converted to bash v2 syntax by Chet Ramey).
./scripts.v2/arc2tarz Convert an "arc" archive to a compressed tar archive.
./scripts.v2/bashrand Random number generator with upper and lower bounds and optional seed. random
./scripts.v2/cal2day.bash Convert a day number to a name.
./scripts.v2/cdhist.bash cd replacement with a directory stack added.
./scripts.v2/corename Tell what produced a core file.
./scripts.v2/fman Fast man(1) replacement. manpage
./scripts.v2/frcp Copy files using ftp(1) but with rcp-type command line syntax.
./scripts.v2/lowercase Change filenames to lower case. rename lower
./scripts.v2/ncp A nicer front end for cp(1) (has -i, etc.).
./scripts.v2/newext Change the extension of a group of files. rename
./scripts.v2/nmv A nicer front end for mv(1) (has -i, etc.). rename
./scripts.v2/pages Print specified pages from files.
./scripts.v2/PERMISSION Permissions to use the scripts in this directory.
./scripts.v2/pf A pager front end that handles compressed files.
./scripts.v2/pmtop Poor man's 'top(1)' for SunOS 4.x and BSD/OS.
./scripts.v2/README README
./scripts.v2/ren Rename files by changing parts of filenames that match a pattern. rename
./scripts.v2/rename Change the names of files that match a pattern. rename
./scripts.v2/repeat Execute a command multiple times. repeat
./scripts.v2/shprof Line profiler for bash scripts.
./scripts.v2/untar Unarchive a (possibly compressed) tarfile into a directory.
./scripts.v2/uudec Carefully uudecode(1) multiple files.
./scripts.v2/uuenc uuencode(1) multiple files.
./scripts.v2/vtree Print a visual display of a directory tree. tree
./scripts.v2/where Show where commands that match a pattern are.
./scripts Example scripts
./scripts/adventure.sh Text adventure game in bash!
./scripts/bcsh.sh Bourne shell cshell-emulator. csh
./scripts/cat.sh Readline-based pager. cat, readline pager
./scripts/center Center - center a group of lines.
./scripts/dd-ex.sh Line editor using only /bin/sh, /bin/dd and /bin/rm.
./scripts/fixfiles.bash Recurse a tree and fix files containing various "bad" chars.
./scripts/hanoi.bash The inevitable Towers of Hanoi in bash.
./scripts/inpath Search $PATH for a file the same name as $1; return TRUE if found. inpath
./scripts/krand.bash Produces a random number within integer limits. random
./scripts/line-input.bash Line input routine for GNU Bourne-Again Shell plus terminal-control primitives.
./scripts/nohup.bash bash version of 'nohup' command.
./scripts/precedence Test relative precedences for '&&' and '||' operators.
./scripts/randomcard.bash Print a random card from a card deck. random
./scripts/README README
./scripts/scrollbar Display scrolling text.
./scripts/scrollbar2 Display scrolling text.
./scripts/self-repro A self-reproducing script (careful!)
./scripts/showperm.bash Convert ls(1) symbolic permissions into octal mode.
./scripts/shprompt Display a prompt and get an answer satisfying certain criteria. ask
./scripts/spin.bash Display a 'spinning wheel' to show progress.
./scripts/timeout Give rsh(1) a shorter timeout.
./scripts/vtree2 Display a tree printout of dir in 1k blocks. tree
./scripts/vtree3 Display a graphical tree printout of dir. tree
./scripts/vtree3a Display a graphical tree printout of dir. tree
./scripts/websrv.sh A web server in bash!
./scripts/xterm_title Print the contents of the xterm title bar.
./scripts/zprintf Emulate printf (obsolete since it's now a bash builtin).
./startup-files Example Start-up files.
./startup-files/Bash_aliases Some useful aliases (Fox).
./startup-files/Bash_profile Sample startup file for bash login shells (Fox).
./startup-files/bash-profile Sample startup file for bash login shells (Ramey).
./startup-files/bashrc Sample Bourne Again SHell init file (Ramey).
./startup-files/Bashrc.bfox Sample Bourne Again SHell init file (Fox).
./startup-files/README README
./startup-files/apple Example Start-up files for Mac OS X.
./startup-files/apple/aliases Sample aliases for Mac OS X.
./startup-files/apple/bash.defaults Sample User preferences file.
./startup-files/apple/environment Sample Bourne Again Shell environment file.
./startup-files/apple/login Sample login wrapper.
./startup-files/apple/logout Sample logout wrapper.
./startup-files/apple/rc Sample Bourne Again Shell config file.
./startup-files/apple/README README
+27
View File
@@ -0,0 +1,27 @@
From mikel@ora.com Tue Aug 1 12:13:20 1995
Flags: 10
Return-Path: mikel@ora.com
Received: from ruby.ora.com (ruby.ora.com [198.112.208.25]) by odin.INS.CWRU.Edu with ESMTP (8.6.12+cwru/CWRU-2.1-ins)
id MAA01565; Tue, 1 Aug 1995 12:13:18 -0400 (from mikel@ora.com for <chet@odin.INS.CWRU.Edu>)
Received: (from fax@localhost) by ruby.ora.com (8.6.12/8.6.11) with UUCP id MAA23251; Tue, 1 Aug 1995 12:07:51 -0400
Received: by los.ora.com (4.1/Spike-2.1)
id AA00672; Tue, 1 Aug 95 08:57:32 EDT
Date: Tue, 1 Aug 95 08:57:32 EDT
From: mikel@ora.com (Michael Loukides)
Message-Id: <9508011257.AA00672@los.ora.com>
Subject: Re: Ksh debugger from Rosenblatt's book [for bash]
To: Chet Ramey <chet@odin.INS.CWRU.Edu>
Cc: cmarie@ora.com, cam@iinet.com.au, brosenblatt@tm.com
In-Reply-To: Chet Ramey <chet@odin.INS.CWRU.Edu>, Mon, 31 Jul 1995 16:22:48 -0400
I've modified a (modified) version of Bill Rosenblatt's ksh debugger
to work with bash-2.0. Does ORA have any problem with me distributing
it with bash-2.0?
That's great!
Go ahead and circulate it; in fact, we should probably grab it and
stick it in our ftp archive, and put a reference to it in the book.
(Too late to actually discuss the thing, at least for this edition).
-------
+3
View File
@@ -0,0 +1,3 @@
This is a sample implementation of a bash debugger. It is not the same
as the project available from http://bashdb.sourceforge.net, and has been
deprecated in favor of that implementation.
+581
View File
@@ -0,0 +1,581 @@
#! /bin/bash
# bashdb - Bash shell debugger
#
# Adapted from an idea in O'Reilly's `Learning the Korn Shell'
# Copyright (C) 1993-1994 O'Reilly and Associates, Inc.
# Copyright (C) 1998, 1999, 2001 Gary V. Vaughan <gvv@techie.com>>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# NOTE:
#
# This program requires bash 2.x.
# If bash 2.x is installed as "bash2", you can invoke bashdb like this:
#
# DEBUG_SHELL=/bin/bash2 /bin/bash2 bashdb script.sh
# TODO:
#
# break [regexp]
# cond [break] [condition]
# tbreak [regexp|+lines]
# restart
# Variable watchpoints
# Instrument `source' and `.' files in $_potbelliedpig
# be cleverer about lines we allow breakpoints to be set on
# break [function_name]
echo 'Bash Debugger version 1.2.4'
export _dbname=${0##*/}
if test $# -lt 1; then
echo "$_dbname: Usage: $_dbname filename" >&2
exit 1
fi
_guineapig=$1
if test ! -r $1; then
echo "$_dbname: Cannot read file '$_guineapig'." >&2
exit 1
fi
shift
__debug=${TMPDIR-/tmp}/bashdb.$$
sed -e '/^# bashdb - Bash shell debugger/,/^# -- DO NOT DELETE THIS LINE -- /d' "$0" > $__debug
cat $_guineapig >> $__debug
exec ${DEBUG_SHELL-bash} $__debug $_guineapig "$@"
exit 1
# -- DO NOT DELETE THIS LINE -- The program depends on it
#bashdb preamble
# $1 name of the original guinea pig script
__debug=$0
_guineapig=$1
__steptrap_calls=0
shift
shopt -s extglob # turn on extglob so we can parse the debugger funcs
function _steptrap
{
local i=0
_curline=$1
if (( ++__steptrap_calls > 1 && $_curline == 1 )); then
return
fi
if [ -n "$_disps" ]; then
while (( $i < ${#_disps[@]} ))
do
if [ -n "${_disps[$i]}" ]; then
_msg "${_disps[$i]}: \c"
eval _msg ${_disps[$i]}
fi
let i=$i+1
done
fi
if (( $_trace )); then
_showline $_curline
fi
if (( $_steps >= 0 )); then
let _steps="$_steps - 1"
fi
if _at_linenumbp ; then
_msg "Reached breakpoint at line $_curline"
_showline $_curline
_cmdloop
elif [ -n "$_brcond" ] && eval $_brcond; then
_msg "Break condition $_brcond true at line $_curline"
_showline $_curline
_cmdloop
elif (( $_steps == 0 )); then
# Assuming a real script will have the "#! /bin/sh" at line 1,
# assume that when $_curline == 1 we are inside backticks.
if (( ! $_trace )); then
_msg "Stopped at line $_curline"
_showline $_curline
fi
_cmdloop
fi
}
function _setbp
{
local i f line _x
if [ -z "$1" ]; then
_listbp
return
fi
eval "$_seteglob"
if [[ $1 == *(\+)[1-9]*([0-9]) ]]; then
case $1 in
+*)
# normalize argument, then double it (+2 -> +2 + 2 = 4)
_x=${1##*([!1-9])} # cut off non-numeric prefix
_x=${x%%*([!0-9])} # cut off non-numeric suffix
f=$(( $1 + $_x ))
;;
*)
f=$(( $1 ))
;;
esac
# find the next valid line
line="${_lines[$f]}"
while _invalidbreakp $f
do
(( f++ ))
line="${_lines[$f]}"
done
if (( $f != $1 ))
then
_msg "Line $1 is not a valid breakpoint"
fi
if [ -n "${_lines[$f]}" ]; then
_linebp[$1]=$1;
_msg "Breakpoint set at line $f"
else
_msg "Breakpoints can only be set on executable lines"
fi
else
_msg "Please specify a numeric line number"
fi
eval "$_resteglob"
}
function _listbp
{
local i
if [ -n "$_linebp" ]; then
_msg "Breakpoints:"
for i in ${_linebp[*]}; do
_showline $i
done
else
_msg "No breakpoints have been set"
fi
}
function _clearbp
{
local i
if [ -z "$1" ]; then
read -e -p "Delete all breakpoints? "
case $REPLY in
[yY]*)
unset _linebp[*]
_msg "All breakpoints have been cleared"
;;
esac
return 0
fi
eval "$_seteglob"
if [[ $1 == [1-9]*([0-9]) ]]; then
unset _linebp[$1]
_msg "Breakpoint cleared at line $1"
else
_msg "Please specify a numeric line number"
fi
eval "$_resteglob"
}
function _setbc
{
if (( $# > 0 )); then
_brcond=$@
_msg "Break when true: $_brcond"
else
_brcond=
_msg "Break condition cleared"
fi
}
function _setdisp
{
if [ -z "$1" ]; then
_listdisp
else
_disps[${#_disps[@]}]="$1"
if (( ${#_disps[@]} < 10 ))
then
_msg " ${#_disps[@]}: $1"
else
_msg "${#_disps[@]}: $1"
fi
fi
}
function _listdisp
{
local i=0 j
if [ -n "$_disps" ]; then
while (( $i < ${#_disps[@]} ))
do
let j=$i+1
if (( ${#_disps[@]} < 10 ))
then
_msg " $j: ${_disps[$i]}"
else
_msg "$j: ${_disps[$i]}"
fi
let i=$j
done
else
_msg "No displays have been set"
fi
}
function _cleardisp
{
if (( $# < 1 )) ; then
read -e -p "Delete all display expressions? "
case $REPLY in
[Yy]*)
unset _disps[*]
_msg "All breakpoints have been cleared"
;;
esac
return 0
fi
eval "$_seteglob"
if [[ $1 == [1-9]*([0-9]) ]]; then
unset _disps[$1]
_msg "Display $i has been cleared"
else
_listdisp
_msg "Please specify a numeric display number"
fi
eval "$_resteglob"
}
# usage _ftrace -u funcname [funcname...]
function _ftrace
{
local _opt=-t _tmsg="enabled" _func
if [[ $1 == -u ]]; then
_opt=+t
_tmsg="disabled"
shift
fi
for _func; do
declare -f $_opt $_func
_msg "Tracing $_tmsg for function $_func"
done
}
function _cmdloop
{
local cmd args
while read -e -p "bashdb> " cmd args; do
test -n "$cmd" && history -s "$cmd $args" # save on history list
test -n "$cmd" || { set $_lastcmd; cmd=$1; shift; args=$*; }
if [ -n "$cmd" ]
then
case $cmd in
b|br|bre|brea|break)
_setbp $args
_lastcmd="break $args"
;;
co|con)
_msg "ambiguous command: '$cmd', condition, continue?"
;;
cond|condi|condit|conditi|conditio|condition)
_setbc $args
_lastcmd="condition $args"
;;
c|cont|conti|contin|continu|continue)
_lastcmd="continue"
return
;;
d)
_msg "ambiguous command: '$cmd', delete, display?"
;;
de|del|dele|delet|delete)
_clearbp $args
_lastcmd="delete $args"
;;
di|dis|disp|displ|displa|display)
_setdisp $args
_lastcmd="display $args"
;;
f|ft|ftr|ftra|ftrace)
_ftrace $args
_lastcmd="ftrace $args"
;;
\?|h|he|hel|help)
_menu
_lastcmd="help"
;;
l|li|lis|list)
_displayscript $args
# _lastcmd is set in the _displayscript function
;;
p|pr|pri|prin|print)
_examine $args
_lastcmd="print $args"
;;
q|qu|qui|quit)
exit
;;
s|st|ste|step|n|ne|nex|next)
let _steps=${args:-1}
_lastcmd="next $args"
return
;;
t|tr|tra|trac|trace)
_xtrace
;;
u|un|und|undi|undis|undisp|undispl|undispla|undisplay)
_cleardisp $args
_lastcmd="undisplay $args"
;;
!*)
eval ${cmd#!} $args
_lastcmd="$cmd $args"
;;
*)
_msg "Invalid command: '$cmd'"
;;
esac
fi
done
}
function _at_linenumbp
{
[[ -n ${_linebp[$_curline]} ]]
}
function _invalidbreakp
{
local line=${_lines[$1]}
# XXX - should use shell patterns
if test -z "$line" \
|| expr "$line" : '[ \t]*#.*' > /dev/null \
|| expr "$line" : '[ \t]*;;[ \t]*$' > /dev/null \
|| expr "$line" : '[ \t]*[^)]*)[ \t]*$' > /dev/null \
|| expr "$line" : '[ \t]*;;[ \t]*#.**$' > /dev/null \
|| expr "$line" : '[ \t]*[^)]*)[ \t]*;;[ \t]*$' > /dev/null \
|| expr "$line" : '[ \t]*[^)]*)[ \t]*;;*[ \t]*#.*$' > /dev/null
then
return 0
fi
return 1
}
function _examine
{
if [ -n "$*" ]; then
_msg "$args: \c"
eval _msg $args
else
_msg "Nothing to print"
fi
}
function _displayscript
{
local i j start end bp cl
if (( $# == 1 )); then # list 5 lines on either side of $1
if [ $1 = "%" ]; then
let start=1
let end=${#_lines[@]}
else
let start=$1-5
let end=$1+5
fi
elif (( $# > 1 )); then # list between start and end
if [ $1 = "^" ]; then
let start=1
else
let start=$1
fi
if [ $2 = "\$" ]; then
let end=${#_lines[@]}
else
let end=$2
fi
else # list 5 lines on either side of current line
let start=$_curline-5
let end=$_curline+5
fi
# normalize start and end
if (( $start < 1 )); then
start=1
fi
if (( $end > ${#_lines[@]} )); then
end=${#_lines[@]}
fi
cl=$(( $end - $start ))
if (( $cl > ${LINES-24} )); then
pager=${PAGER-more}
else
pager=cat
fi
i=$start
( while (( $i <= $end )); do
_showline $i
let i=$i+1
done ) 2>&1 | $pager
# calculate the next block of lines
start=$(( $end + 1 ))
end=$(( $start + 11 ))
if (( $end > ${#_lines[@]} ))
then
end=${#_lines[@]}
fi
_lastcmd="list $start $end"
}
function _xtrace
{
let _trace="! $_trace"
if (( $_trace )); then
_msg "Execution trace on"
else
_msg "Execution trace off"
fi
}
function _msg
{
echo -e "$@" >&2
}
function _showline
{
local i=0 bp=' ' line=$1 cl=' '
if [[ -n ${_linebp[$line]} ]]; then
bp='*'
fi
if (( $_curline == $line )); then
cl=">"
fi
if (( $line < 100 )); then
_msg "${_guineapig/*\//}:$line $bp $cl${_lines[$line]}"
elif (( $line < 10 )); then
_msg "${_guineapig/*\//}:$line $bp $cl${_lines[$line]}"
elif (( $line > 0 )); then
_msg "${_guineapig/*\//}:$line $bp $cl${_lines[$line]}"
fi
}
function _cleanup
{
rm -f $__debug $_potbelliedpig 2> /dev/null
}
function _menu
{
_msg 'bashdb commands:
break N set breakpoint at line N
break list breakpoints & break condition
condition foo set break condition to foo
condition clear break condition
delete N clear breakpoint at line N
delete clear all breakpoints
display EXP evaluate and display EXP for each debug step
display show a list of display expressions
undisplay N remove display expression N
list N M display all lines of script between N and M
list N display 5 lines of script either side of line N
list display 5 lines if script either side of current line
continue continue execution upto next breakpoint
next [N] execute [N] statements (default 1)
print expr prints the value of an expression
trace toggle execution trace on/off
ftrace [-u] func make the debugger step into function FUNC
(-u turns off tracing FUNC)
help print this menu
! string passes string to a shell
quit quit'
}
shopt -u extglob
HISTFILE=~/.bashdb_history
set -o history
set +H
# strings to save and restore the setting of `extglob' in debugger functions
# that need it
_seteglob='local __eopt=-u ; shopt -q extglob && __eopt=-s ; shopt -s extglob'
_resteglob='shopt $__eopt extglob'
_linebp=()
let _trace=0
let _i=1
# Be careful about quoted newlines
_potbelliedpig=${TMPDIR-/tmp}/${_guineapig/*\//}.$$
sed 's,\\$,\\\\,' $_guineapig > $_potbelliedpig
_msg "Reading source from file: $_guineapig"
while read; do
_lines[$_i]=$REPLY
let _i=$_i+1
done < $_potbelliedpig
trap _cleanup EXIT
# Assuming a real script will have the "#! /bin/sh" at line 1,
# don't stop at line 1 on the first run
let _steps=1
LINENO=-1
trap '_steptrap $LINENO' DEBUG
+177
View File
@@ -0,0 +1,177 @@
;;; bashdb.el --- Grand Unified Debugger mode for running bashdb
;; Copyright (C) 2000, 2001 Masatake YAMATO
;; Author: Masatake YAMATO <jet@gyve.org>
;; This program is free software; you can redistribute it and/or modify it
;; under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2 of the License, or
;; (at your option) any later version.
;; This program is distributed in the hope that it will be useful, but
;; WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program; if not, write to the Free Software Foundation,
;; Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
;; Commentary:
;; This program may run on Emacs 21.0.91 and XEmacs 21.1.
;;
;; Put
;; (autoload 'bashdb "bashdb" "Run bashdb" t nil)
;; to your .emacs.
;; M-x bashdb
;; Run bashdb (like this): bashdb target.sh
;;
;; About bashdb:
;; You can get bashdb from
;; http://www.oranda.demon.co.uk/development.html
;;
;; bashdb.el is based on perldb in gud.el in XEmacs 21.1.
;; Revision:
;; $Revision: 1.6 $
;; $Log: bashdb.el,v $
;; Revision 1.6 2001/01/06 12:18:06 masata-y
;; Write note about XEmacs.
;;
;;
;;; Code:
(require 'gud)
;; User customizable variable
(defcustom gud-bashdb-command-name "bashdb"
"File name for executing Bashdb."
:type 'string
:group 'gud)
;; History of argument lists passed to bashdb.
(defvar gud-bashdb-history nil)
(defun gud-bashdb-massage-args (file args)
(if xemacsp
(cons (file-name-nondirectory file) args)
args))
;; There's no guarantee that Emacs will hand the filter the entire
;; marker at once; it could be broken up across several strings. We
;; might even receive a big chunk with several markers in it. If we
;; receive a chunk of text which looks like it might contain the
;; beginning of a marker, we save it here between calls to the
;; filter.
(if xemacsp
(defvar gud-bashdb-marker-acc ""))
(defun gud-bashdb-marker-acc ()
(if xemacsp
gud-bashdb-marker-acc
gud-marker-acc))
(defun gud-bashdb-marker-acc-quote ()
(if xemacsp
'gud-bashdb-marker-acc
'gud-marker-acc))
(defun gud-bashdb-marker-filter (string)
(save-match-data
(set (gud-bashdb-marker-acc-quote)
(concat (gud-bashdb-marker-acc) string))
(let ((output ""))
;; Process all the complete markers in this chunk.
(while (string-match "^\\([^:\n]+\\):\\([0-9]+\\)[ *]*>.*\n"
(gud-bashdb-marker-acc))
(setq
;; Extract the frame position from the marker.
gud-last-frame (cons
(substring (gud-bashdb-marker-acc)
(match-beginning 1)
(match-end 1))
(string-to-int
(substring (gud-bashdb-marker-acc)
(match-beginning 2)
(match-end 2))))
;; Append any text before the marker to the output we're going
;; to return - we don't include the marker in this text.
output (concat output
(substring (gud-bashdb-marker-acc) 0 (match-beginning 0))))
;; Set the accumulator to the remaining text.
(set
(gud-bashdb-marker-acc-quote) (substring
(gud-bashdb-marker-acc) (match-end 0))))
;; Does the remaining text look like it might end with the
;; beginning of another marker? If it does, then keep it in
;; (gud-bashdb-marker-acc) until we receive the rest of it. Since we
;; know the full marker regexp above failed, it's pretty simple to
;; test for marker starts.
(if (string-match "^\\([^:\n]+\\):\\([0-9]+\\)[ *]*>" (gud-bashdb-marker-acc))
(progn
;; Everything before the potential marker start can be output.
(setq output (concat output (substring (gud-bashdb-marker-acc)
0 (match-beginning 0))))
;; Everything after, we save, to combine with later input.
(set (gud-bashdb-marker-acc-quote)
(substring (gud-bashdb-marker-acc) (match-beginning 0))))
(setq output (concat output (gud-bashdb-marker-acc)))
(set (gud-bashdb-marker-acc-quote) ""))
output)))
(defun gud-bashdb-find-file (f)
(find-file-noselect f))
;;;###autoload
(defun bashdb (command-line)
"Run bashdb on program FILE in buffer *gud-FILE*.
The directory containing FILE becomes the initial working directory
and source-file directory for your debugger."
(interactive
(if xemacsp
(list (read-from-minibuffer "Run bashdb (like this): "
(if (consp gud-bashdb-history)
(car gud-bashdb-history)
(format "%s " gud-bashdb-command-name))
nil nil
'(gud-bashdb-history . 1)))
(list (gud-query-cmdline 'bashdb))
))
(if xemacsp
(progn
(gud-overload-functions '((gud-massage-args . gud-bashdb-massage-args)
(gud-marker-filter . gud-bashdb-marker-filter)
(gud-find-file . gud-bashdb-find-file)))
(gud-common-init command-line gud-bashdb-command-name))
(gud-common-init command-line 'gud-bashdb-massage-args
'gud-bashdb-marker-filter 'gud-bashdb-find-file)
(set (make-local-variable 'gud-minor-mode) 'bashdb))
;; Unsupported commands
;; condition foo set break condition to foo
;; condition clear break condition
;; display EXP evaluate and display EXP for each debug step
;; display show a list of display expressions
;; undisplay N remove display expression N
;; ! string passes string to a shell
;; quit quit
(gud-def gud-break "break %l" "\C-b" "Set breakpoint at current line.")
(gud-def gud-list-break "break" "b" "List breakpoints & break condition.")
(gud-def gud-remove "delete %l" "\C-d" "Remove breakpoint at current line")
(gud-def gud-remove-all "delete" "d" "Clear all breakpoints")
(gud-def gud-cont "continue" "\C-r" "Continue with display.")
(gud-def gud-next "next" "\C-n" "Step one line (skip functions).")
(gud-def gud-print "print %e" "\C-p" "Evaluate bash expression at point.")
(gud-def gud-help "help" "h" "Show all commands.")
(gud-def gud-trace "trace" "t" "Toggle execution trace on/off")
(setq comint-prompt-regexp "^bashdb> ")
(setq paragraph-start comint-prompt-regexp)
(run-hooks 'bashdb-mode-hook))
(provide 'bashdb)
;; bashdb.el ends here
@@ -0,0 +1,561 @@
#! /bin/bash
# bashdb - Bash shell debugger
#
# Adapted from an idea in O'Reilly's `Learning the Korn Shell'
# Copyright (C) 1993-1994 O'Reilly and Associates, Inc.
# Copyright (C) 1998, 1999, 2001 Gary V. Vaughan <gvv@techie.com>>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# NOTE:
#
# This program requires bash 2.x.
# If bash 2.x is installed as "bash2", you can invoke bashdb like this:
#
# DEBUG_SHELL=/bin/bash2 /bin/bash2 bashdb script.sh
# TODO:
#
# break [regexp]
# cond [break] [condition]
# tbreak [regexp|+lines]
# restart
# Variable watchpoints
# Output colourization
# History with csh ^ substitution? Or write a readline frontend?
# Instrument shell functions with the _steptrap in $_potbelliedpig
# Instrument `source' and `.' files in $_potbelliedpig
# be cleverer about lines we allow breakpoints to be set on
# break [function_name]
echo 'Bash Debugger version 1.2.4'
export _dbname=$(echo "X$0"|sed -e 's,^X,,' -e 's,^.*/,,')
if test $# -lt 1; then
echo "$_dbname: Usage: $_dbname <filename>" >&2
exit 1
fi
_guineapig=$1
if test ! -r $1; then
echo "$_dbname: Cannot read file '$_guineapig'." >&2
exit 1
fi
shift
__debug=${TMPDIR-/tmp}/bashdb.$$
sed -e '/^# bashdb - Bash shell debugger/,/^# -- DO NOT DELETE THIS LINE -- /d' "$0" > $__debug
cat $_guineapig >> $__debug
exec ${DEBUG_SHELL-bash} $__debug $_guineapig "$@"
exit 1
# -- DO NOT DELETE THIS LINE -- The program depends on it
#bashdb preamble
# $1 name of the original guinea pig script
__debug=$0
_guineapig=$1
shift
function _steptrap
{
local i=0
_curline=$1
if [ -n "$_disps" ]
then
while (( $i < ${#_disps[@]} ))
do
if [ -n "${_disps[$i]}" ]
then
_msg "${_disps[$i]}: \c"
eval _msg ${_disps[$i]}
fi
let i=$i+1
done
fi
if (( $_trace )); then
_showline $_curline
fi
if (( $_steps >= 0 )); then
let _steps="$_steps - 1"
fi
if _at_linenumbp ; then
_msg "Reached breakpoint at line $_curline"
_showline $_curline
_cmdloop
elif [ -n "$_brcond" ] && eval $_brcond; then
_msg "Break condition $_brcond true at line $_curline"
_showline $_curline
_cmdloop
elif (( $_steps == 0 && $_curline > 1)); then
# Assuming a real script will have the "#! /bin/sh" at line 1,
# assume that when $_curline == 1 we are inside backticks.
if (( ! $_trace )); then
_msg "Stopped at line $_curline"
_showline $_curline
fi
_cmdloop
fi
}
function _setbp
{
local i f line
if [ -z "$1" ]
then
_listbp
elif [ $(echo $1 | grep '^\+*[1-9][0-9]*') ]
then
case $1 in
+*)
let f="$1 + `expr $1 : '+*\([1-9][0-9]*\)'`"
;;
*)
let f=$1
;;
esac
# find the next valid line
line="${_lines[$f]}"
while _invalidbreakp $f
do
let f="$f + 1"
line="${_lines[$f]}"
done
if (( $f != $1 ))
then
_msg "Line $1 is not a valid breakpoint"
fi
if [ -n "${_lines[$f]}" ]
then
_linebp=($(echo $( (for i in ${_linebp[*]} $1; do
echo $i; done) | sort -n) ))
_msg "Breakpoint set at line $f"
else
_msg "Breakpoints can only be set on executable lines"
fi
else
_msg "Please specify a numeric line number"
fi
}
function _listbp
{
local i
if [ -n "$_linebp" ]
then
_msg "Breakpoints:"
for i in ${_linebp[*]}; do
_showline $i
done
else
_msg "No breakpoints have been set"
fi
}
function _clearbp
{
local i
if [ -z "$1" ]; then
read -e -p "Delete all breakpoints? "
case $REPLY in
y*)
unset _linebp[*]
_msg "All breakpoints have been cleared"
;;
esac
elif [ $(echo $1 | grep '^[0-9]*') ]; then
_linebp=($(echo $(for i in ${_linebp[*]}; do
if (( $1 != $i )); then echo $1; fi; done) ))
_msg "Breakpoint cleared at line $1"
else
_msg "Please specify a numeric line number"
fi
}
function _setbc
{
if [ -n "$*" ]
then
_brcond=$args
_msg "Break when true: $_brcond"
else
_brcond=
_msg "Break condition cleared"
fi
}
function _setdisp
{
if [ -z "$1" ]
then
_listdisp
else
_disps[${#_disps[@]}]="$1"
if (( ${#_disps[@]} < 10 ))
then
_msg " ${#_disps[@]}: $1"
else
_msg "${#_disps[@]}: $1"
fi
fi
}
function _listdisp
{
local i=0 j
if [ -n "$_disps" ]
then
while (( $i < ${#_disps[@]} ))
do
let j=$i+1
if (( ${#_disps[@]} < 10 ))
then
_msg " $j: ${_disps[$i]}"
else
_msg "$j: ${_disps[$i]}"
fi
let i=$j
done
else
_msg "No displays have been set"
fi
}
function _cleardisp
{
if (( $# < 1 ))
then
read -e -p "Delete all display expressions? "
case $REPLY in
y*)
unset _disps[*]
_msg "All breakpoints have been cleared"
;;
esac
elif [ $(echo $1 | grep '^[0-9]*') ]
then
unset _disps[$1]
_msg "Display $i has been cleared"
else
_listdisp
_msg "Please specify a numeric display number"
fi
}
function _cmdloop
{
local cmd args
while read -e -p "bashdb> " cmd args; do
test -n "$cmd" || { set $_lastcmd; cmd=$1; shift; args=$*; }
if [ -n "$cmd" ]
then
case $cmd in
b|br|bre|brea|break)
_setbp $args
_lastcmd="break $args"
;;
co|con)
_msg "ambiguous command: '$cmd', condition, continue?"
;;
cond|condi|condit|conditi|conditio|condition)
_setbc $args
_lastcmd="condition $args"
;;
c|cont|conti|contin|continu|continue)
_lastcmd="continue"
return
;;
d)
_msg "ambiguous command: '$cmd', delete, display?"
;;
de|del|dele|delet|delete)
_clearbp $args
_lastcmd="delete $args"
;;
di|dis|disp|displ|displa|display)
_setdisp $args
_lastcmd="display $args"
;;
\?|h|he|hel|help)
_menu
_lastcmd="help"
;;
l|li|lis|list)
_displayscript $args
# _lastcmd is set in the _displayscript function
;;
p|pr|pri|prin|print)
_examine $args
_lastcmd="print $args"
;;
q|qu|qui|quit)
exit
;;
s|st|ste|step|n|ne|nex|next)
let _steps=${args:-1}
_lastcmd="next $args"
return
;;
t|tr|tra|trac|trace)
_xtrace
;;
u|un|und|undi|undis|undisp|undispl|undispla|undisplay)
_cleardisp $args
_lastcmd="undisplay $args"
;;
!*)
eval ${cmd#!} $args
_lastcmd="$cmd $args"
;;
*)
_msg "Invalid command: '$cmd'"
;;
esac
fi
done
}
function _at_linenumbp
{
local i=0
if [ "$_linebp" ]
then
while (( $i < ${#_linebp[@]} )); do
if (( ${_linebp[$i]} == $_curline )); then
return 0
fi
let i=$i+1
done
fi
return 1
}
function _invalidbreakp
{
local line=${_lines[$1]}
if test -z "$line" \
|| expr "$line" : '[ \t]*#.*' > /dev/null \
|| expr "$line" : '[ \t]*;;[ \t]*$' > /dev/null \
|| expr "$line" : '[ \t]*[^)]*)[ \t]*$' > /dev/null \
|| expr "$line" : '[ \t]*;;[ \t]*#.**$' > /dev/null \
|| expr "$line" : '[ \t]*[^)]*)[ \t]*;;[ \t]*$' > /dev/null \
|| expr "$line" : '[ \t]*[^)]*)[ \t]*;;*[ \t]*#.*$' > /dev/null
then
return 0
fi
return 1
}
function _examine
{
if [ -n "$*" ]
then
_msg "$args: \c"
eval _msg $args
else
_msg "Nothing to print"
fi
}
function _displayscript
{
local i j start end bp cl
if (( $# == 1 ))
then
if test $1 = "%"
then
let start=1
let end=${#_lines[@]}
else
let start=$1-5
let end=$1+5
fi
elif (( $# > 1 ))
then
if test $1 = "^"
then
let start=1
else
let start=$1
fi
if test $2 = "\$"
then
let end=${#_lines[@]}
else
let end=$2
fi
else
let start=$_curline-5
let end=$_curline+5
fi
if (( $start < 1 ))
then
start=1
fi
if (( $end > ${#_lines[@]} ))
then
end=${#_lines[@]}
fi
let cl=$end-$start
if (( $cl > ${LINES-24} ))
then
pager=${PAGER-more}
else
pager=cat
fi
i=$start
( while (( $i <= $end )); do
_showline $i
let i=$i+1
done ) 2>&1 | $pager
# calculate the next block of lines
let start=$end+1
let end=$start+11
if (( $end > ${#_lines[@]} ))
then
end=${#_lines[@]}
fi
_lastcmd="list $start $end"
}
function _xtrace
{
let _trace="! $_trace"
if (( $_trace )); then
_msg "Execution trace on"
else
_msg "Execution trace off"
fi
}
function _msg
{
echo -e "$@" >&2
}
function _showline
{
local i=0 bp=' ' line=$1
while (( $i < ${#_linebp[@]} ))
do
if [ ${_linebp[$i]} ] && (( ${_linebp[$i]} == $line ))
then
bp='*'
fi
let i=$i+1
done
if (( $_curline == $line )); then
cl=">"
else
cl=" "
fi
if (( $line < 100 )); then
_msg "$_guineapig:$line $bp $cl${_lines[$line]}"
elif (( $line < 10 )); then
_msg "$_guineapig:$line $bp $cl${_lines[$line]}"
elif (( $line > 0 )); then
_msg "$_guineapig:$line $bp $cl${_lines[$line]}"
fi
}
function _cleanup
{
rm -f $__debug $_potbelliedpig 2> /dev/null
}
function _menu
{
_msg 'bashdb commands:
break N set breakpoint at line N
break list breakpoints & break condition
condition foo set break condition to foo
condition clear break condition
delete N clear breakpoint at line N
delete clear all breakpoints
display EXP evaluate and display EXP for each debug step
display show a list of display expressions
undisplay N remove display expression N
list N M display all lines of script between N and M
list N display 5 lines of script either side of line N
list display 5 lines if script either side of current line
continue continue execution upto next breakpoint
next [N] execute [N] statements (default 1)
print expr prints the value of an expression
trace toggle execution trace on/off
help print this menu
! string passes string to a shell
quit quit'
}
_linebp=
let _trace=0
let _i=1
# Be careful about quoted newlines
_potbelliedpig=${TMPDIR-/tmp}/$_guineapig.$$
sed 's,\\$,\\\\,' $_guineapig > $_potbelliedpig
_msg "Reading source from file: $_guineapig"
while read; do
_lines[$_i]=$REPLY
let _i=$_i+1
done < $_potbelliedpig
trap _cleanup EXIT
# Assuming a real script will have the "#! /bin/sh" at line 1,
# don't stop at line 1 on the first run
let _steps=2
LINENO=-2
trap '_steptrap $LINENO' DEBUG
:
Binary file not shown.
@@ -0,0 +1,495 @@
#
# Completion examples
#
#
# This encapsulates the default bash completion code
# call with the word to be completed as $1
#
# Since programmable completion does not use the bash default completions
# or the readline default of filename completion when the compspec does
# not generate any matches, this may be used as a `last resort' in a
# completion function to mimic the default bash completion behavior.
#
_bash_def_completion ()
{
local h t
COMPREPLY=()
# command substitution
if [[ "$1" == \$\(* ]]; then
t=${1#??}
COMPREPLY=( $(compgen -c -P '$(' $t) )
fi
# variables with a leading `${'
if [ ${#COMPREPLY[@]} -eq 0 ] && [[ "$1" == \$\{* ]]; then
t=${1#??}
COMPREPLY=( $(compgen -v -P '${' -S '}' $t) )
fi
# variables with a leading `$'
if [ ${#COMPREPLY[@]} -eq 0 ] && [[ "$1" == \$* ]]; then
t=${1#?}
COMPREPLY=( $(compgen -v -P '$' $t ) )
fi
# username expansion
if [ ${#COMPREPLY[@]} -eq 0 ] && [[ "$1" == ~* ]] && [[ "$1" != */* ]]; then
t=${1#?}
COMPREPLY=( $( compgen -u -P '~' $t ) )
fi
# hostname
if [ ${#COMPREPLY[@]} -eq 0 ] && [[ "$1" == *@* ]]; then
h=${1%%@*}
t=${1#*@}
COMPREPLY=( $( compgen -A hostname -P "${h}@" $t ) )
fi
# glob pattern
if [ ${#COMPREPLY[@]} -eq 0 ]; then
# sh-style glob pattern
if [[ $1 == *[*?[]* ]]; then
COMPREPLY=( $( compgen -G "$1" ) )
# ksh-style extended glob pattern - must be complete
elif shopt -q extglob && [[ $1 == *[?*+\!@]\(*\)* ]]; then
COMPREPLY=( $( compgen -G "$1" ) )
fi
fi
# final default is filename completion
if [ ${#COMPREPLY[@]} -eq 0 ]; then
COMPREPLY=( $(compgen -f "$1" ) )
fi
}
#
# Return 1 if $1 appears to contain a redirection operator. Handles backslash
# quoting (barely).
#
_redir_op()
{
case "$1" in
*\\'[\<\>]'*) return 1;;
*[\<\>]*) return 0;;
*) return 1;;
esac
}
# _redir_test tests the current word ($1) and the previous word ($2) for
# redirection operators and does filename completion on the current word
# if either one contains a redirection operator
_redir_test()
{
if _redir_op "$1" ; then
COMPREPLY=( $( compgen -f "$1" ) )
return 0
elif _redir_op "$2" ; then
COMPREPLY=( $( compgen -f "$1" ) )
return 0
fi
return 1
}
# optional, but without this you can't use extended glob patterns
shopt -s extglob
#
# Easy ones for the shell builtins
#
# nothing for: alias, break, continue, dirs, echo, eval, exit, getopts,
# let, logout, popd, printf, pwd, return, shift, suspend, test, times,
# umask
#
complete -f -- . source
complete -A enabled builtin
complete -d cd
# this isn't exactly right yet -- needs to skip shell functions and
# do $PATH lookup (or do compgen -c and filter out matches that also
# appear in compgen -A function)
complete -c command
# could add -S '=', but that currently screws up because readline appends
# a space unconditionally
complete -v export local readonly
complete -A helptopic help # currently same as builtins
complete -d pushd
complete -A shopt shopt
complete -c type
complete -a unalias
complete -v unset
#
# Job control builtins: fg, bg, disown, kill, wait
# kill not done yet
#
complete -A stopped -P '%' bg
complete -j -P '%' fg jobs disown
# this is not quite right at this point
_wait_func ()
{
local cur
cur=${COMP_WORDS[COMP_CWORD]}
case "$cur" in
%*) COMPREPLY=( $(compgen -A running -P '%' ${cur#?} ) ) ;;
[0-9]*) COMPREPLY=( $(jobs -p | grep ^${cur}) ) ;;
*) COMPREPLY=( $(compgen -A running -P '%') $(jobs -p) )
;;
esac
}
complete -F _wait_func wait
#
# more complicated things, several as yet unimplemented
#
#complete -F _bind_func bind
_declare_func()
{
local cur prev nflag opts
cur=${COMP_WORDS[COMP_CWORD]}
prev=${COMP_WORDS[COMP_CWORD-1]}
COMPREPLY=()
if (( $COMP_CWORD <= 1 )) || [[ $cur == '-' ]]; then
COMPREPLY=(-a -f -F -i -p -r -t -x)
return 0;
fi
if [[ $cur == '+' ]]; then
COMPREPLY=(+i +t +x)
return 0;
fi
if [[ $prev == '-p' ]]; then
COMPREPLY=( $(compgen -v $cur) )
return 0;
fi
return 1
}
complete -F _declare_func declare typeset
_enable_func()
{
local cur prev nflag opts
cur=${COMP_WORDS[COMP_CWORD]}
prev=${COMP_WORDS[COMP_CWORD-1]}
COMPREPLY=()
if (( $COMP_CWORD <= 1 )) || [[ $cur == '-' ]]; then
COMPREPLY=(-a -d -f -n -p -s)
return 0;
fi
if [[ $prev == '-f' ]]; then
COMPREPLY=( $( compgen -f $cur ) )
return 0;
fi
for opts in "${COMP_WORDS[@]}" ; do
if [[ $opts == -*n* ]]; then nflag=1; fi
done
if [ -z "$nflag" ] ; then
COMPREPLY=( $( compgen -A enabled $cur ) )
else
COMPREPLY=( $( compgen -A disabled $cur ) )
fi
return 0;
}
complete -F _enable_func enable
_exec_func()
{
local cur prev
cur=${COMP_WORDS[COMP_CWORD]}
prev=${COMP_WORDS[COMP_CWORD-1]}
if (( $COMP_CWORD <= 1 )) || [[ $cur == '-' ]]; then
COMPREPLY=(-a -c -l)
return 0;
fi
if [[ $prev != -*a* ]]; then
COMPREPLY=( $( compgen -c $cur ) )
return 0
fi
return 1;
}
complete -F _exec_func exec
_fc_func()
{
local cur prev
cur=${COMP_WORDS[COMP_CWORD]}
prev=${COMP_WORDS[COMP_CWORD-1]}
if (( $COMP_CWORD <= 1 )) || [[ $cur == '-' ]]; then
COMPREPLY=(-e -n -l -r -s)
return 0;
fi
if [[ $prev == -*e ]]; then
COMPREPLY=( $(compgen -c $cur) )
return 0
fi
return 1
}
complete -F _fc_func fc
_hash_func()
{
local cur prev
cur=${COMP_WORDS[COMP_CWORD]}
prev=${COMP_WORDS[COMP_CWORD-1]}
if (( $COMP_CWORD <= 1 )) || [[ $cur == '-' ]]; then
COMPREPLY=(-p -r -t)
return 0;
fi
if [[ $prev == '-p' ]]; then
COMPREPLY=( $( compgen -f $cur ) )
return 0;
fi
COMPREPLY=( $( compgen -c $cur ) )
return 0
}
complete -F _hash_func hash
_history_func()
{
local cur prev
cur=${COMP_WORDS[COMP_CWORD]}
prev=${COMP_WORDS[COMP_CWORD-1]}
COMPREPLY=()
if (( $COMP_CWORD <= 1 )) || [[ $cur == '-' ]]; then
COMPREPLY=(-a -c -d -n -r -w -p -s)
return 0;
fi
if [[ $prev == -[anrw] ]]; then
COMPREPLY=( $( compgen -f $cur ) )
fi
return 0
}
complete -F _history_func history
#complete -F _read_func read
_set_func ()
{
local cur prev
cur=${COMP_WORDS[COMP_CWORD]}
prev=${COMP_WORDS[COMP_CWORD-1]}
COMPREPLY=()
_redir_test "$cur" "$prev" && return 0;
if (( $COMP_CWORD <= 1 )) || [[ $cur == '-' ]]; then
COMPREPLY=(-a -b -e -f -k -m -n -o -p -t -u -v -x -B -C -H -P --)
return 0;
fi
if [[ $cur == '+' ]]; then
COMPREPLY=(+a +b +e +f +k +m +n +o +p +t +u +v +x +B +C +H +P)
return 0;
fi
if [[ $prev == [+-]o ]]; then
COMPREPLY=( $(compgen -A setopt $cur) )
return 0;
fi
return 1;
}
complete -F _set_func set
_trap_func ()
{
local cur
cur=${COMP_WORDS[COMP_CWORD]}
if (( $COMP_CWORD <= 1 )) || [[ $cur == '-' ]]; then
COMPREPLY=(-l -p)
return 0;
fi
COMPREPLY=( $( compgen -A signal ${cur}) )
return 0
}
complete -F _trap_func trap
#
# meta-completion (completion for complete/compgen)
#
_complete_meta_func()
{
local cur prev cmd
COMPREPLY=()
cmd=$1
cur=${COMP_WORDS[COMP_CWORD]}
prev=${COMP_WORDS[COMP_CWORD-1]}
_redir_test "$cur" "$prev" && return 0;
if (( $COMP_CWORD <= 1 )) || [[ "$cur" == '-' ]]; then
case "$cmd" in
complete) COMPREPLY=(-a -b -c -d -e -f -j -k -s -v -u -r -p -A -G -W -P -S -X -F -C);;
compgen) COMPREPLY=(-a -b -c -d -e -f -j -k -s -v -u -A -G -W -P -S -X -F -C);;
esac
return 0
fi
if [[ $prev == -A ]]; then
COMPREPLY=(alias arrayvar binding builtin command directory \
disabled enabled export file 'function' helptopic hostname job keyword \
running service setopt shopt signal stopped variable)
return 0
elif [[ $prev == -F ]]; then
COMPREPLY=( $( compgen -A function $cur ) )
elif [[ $prev == -C ]]; then
COMPREPLY=( $( compgen -c $cur ) )
else
COMPREPLY=( $( compgen -c $cur ) )
fi
return 0
}
complete -F _complete_meta_func complete compgen
#
# some completions for shell reserved words
#
#complete -c -k time do if then else elif '{'
#
# external commands
#
complete -e printenv
complete -c nohup exec nice eval trace truss strace sotruss gdb
_make_targets ()
{
local mdef makef gcmd cur prev i
COMPREPLY=()
cur=${COMP_WORDS[COMP_CWORD]}
prev=${COMP_WORDS[COMP_CWORD-1]}
# if prev argument is -f, return possible filename completions.
# we could be a little smarter here and return matches against
# `makefile Makefile *.mk', whatever exists
case "$prev" in
-*f) COMPREPLY=( $(compgen -f $cur ) ); return 0;;
esac
# if we want an option, return the possible posix options
case "$cur" in
-) COMPREPLY=(-e -f -i -k -n -p -q -r -S -s -t); return 0;;
esac
# make reads `makefile' before `Makefile'
# GNU make reads `GNUmakefile' before all other makefiles, but we
# check that we're completing `gmake' before checking for it
if [ -f GNUmakefile ] && [ ${COMP_WORDS[0]} == gmake ]; then
mdef=GNUmakefile
elif [ -f makefile ]; then
mdef=makefile
elif [ -f Makefile ]; then
mdef=Makefile
else
mdef=*.mk # local convention
fi
# before we scan for targets, see if a makefile name was specified
# with -f
for (( i=0; i < ${#COMP_WORDS[@]}; i++ )); do
if [[ ${COMP_WORDS[i]} == -*f ]]; then
eval makef=${COMP_WORDS[i+1]} # eval for tilde expansion
break
fi
done
[ -z "$makef" ] && makef=$mdef
# if we have a partial word to complete, restrict completions to
# matches of that word
if [ -n "$2" ]; then gcmd='grep "^$2"' ; else gcmd=cat ; fi
# if we don't want to use *.mk, we can take out the cat and use
# test -f $makef and input redirection
COMPREPLY=( $(cat $makef 2>/dev/null | awk 'BEGIN {FS=":"} /^[^.# ][^=]*:/ {print $1}' | tr -s ' ' '\012' | sort -u | eval $gcmd ) )
}
complete -F _make_targets -X '+($*|*.[cho])' make gmake pmake
_umount_func ()
{
COMPREPLY=( $(mount | awk '{print $1}') )
}
complete -F _umount_func umount
_configure_func ()
{
case "$2" in
-*) ;;
*) return ;;
esac
case "$1" in
\~*) eval cmd=$1 ;;
*) cmd="$1" ;;
esac
COMPREPLY=( $("$cmd" --help | awk '{if ($1 ~ /--.*/) print $1}' | grep ^"$2" | sort -u) )
}
complete -F _configure_func configure
complete -W '"${GROUPS[@]}"' newgrp
complete -f chown ln more cat
complete -d mkdir rmdir
complete -f strip
complete -f -X '*.gz' gzip
complete -f -X '*.bz2' bzip2
complete -f -X '*.Z' compress
complete -f -X '!*.+(gz|tgz|Gz)' gunzip gzcat zcat zmore
complete -f -X '!*.Z' uncompress zmore zcat
complete -f -X '!*.bz2' bunzip2 bzcat
complete -f -X '!*.zip' unzip
complete -f -X '!*.+(gif|jpg|jpeg|GIF|JPG|JPEG|bmp)' xv
complete -f -X '!*.pl' perl perl5
complete -A hostname rsh telnet rlogin ftp ping xping host traceroute nslookup
complete -A hostname rxterm rxterm3 rxvt2
complete -u su
complete -g newgrp groupdel groupmod
complete -f -X '!*.+(ps|PS)' gs gv ghostview psselect pswrap
complete -f -X '!*.+(dvi|DVI)' dvips xdvi dviselect dvitype catdvi
complete -f -X '!*.+(pdf|PDF)' acroread4
complete -f -X '!*.texi*' makeinfo texi2dvi texi2html
complete -f -X '!*.+(tex|TEX)' tex latex slitex
complete -f -X '!*.+(mp3|MP3)' mpg123
complete -f -X '!*.+(htm|html)' links w3m lynx
#
# other possibilities, left as exercises
#
#complete -F _find_func find
#complete -F _man_func man
#complete -F _stty_func stty
@@ -0,0 +1,50 @@
# from zsh, just for testing
complete -A stopped -P '%' bg
complete -j -P '%' fg jobs disown
# this is wrong at this point
complete -j -P '%' -W '$(ps -x | tail +2 | cut -c1-5)' wait
complete -c type
complete -a unalias
complete -v getopts read unset
complete -v -S '=' declare export local readonly typeset
complete -f -- . source
complete -A shopt shopt
complete -e printenv
complete -A helptopic help
complete -c nohup exec nice eval
complete -c -k time
complete -A signal trap kill
complete -f chown ln more cat
complete -d mkdir rmdir
complete -f -X '!*.+(gz|tgz)' gunzip gzcat zcat zmore
complete -f -X '!*.Z' uncompress zmore zcat
complete -f gzip
complete -d cd pushd popd
complete -A hostname rsh telnet rlogin ftp
complete -u su
complete -W '"${GROUPS[@]}"' newgrp
complete -g groupdel groupmod
complete -f -X '!*.+(ps|PS)' gs gv ghostview
complete -f -X '!*.dvi' dvips xdvi
complete -f -X '!*.pdf' acroread
complete -f -X '!*.texi*' makeinfo texi2dvi texi2html
complete -c gdb make
complete -p gs
complete -p
complete -r xdvi
complete -r notthere
complete -r
complete
@@ -0,0 +1,31 @@
#Date: Wed, 31 Jan 2001 12:53:56 -0800
#From: Aaron Smith <aaron@mutex.org>
#To: freebsd-ports@freebsd.org
#Subject: useful bash completion function for pkg commands
#Message-ID: <20010131125356.G52003@gelatinous.com>
#hi all. i just wanted to share this bash completion function i wrote that
#completes package names for pkg_info and pkg_delete. i find this a great
#help when dealing with port management. programmed completion requires
#bash-2.04.
_pkg_func ()
{
local cur
cur=${COMP_WORDS[COMP_CWORD]}
if [[ $cur == '-' ]]; then
if [[ ${COMP_WORDS[0]} == 'pkg_info' ]]; then
COMPREPLY=(-a -c -d -D -i -k -r -R -p -L -q -I -m -v -e -l)
return 0;
elif [[ ${COMP_WORDS[0]} == 'pkg_delete' ]]; then
COMPREPLY=(-v -D -d -n -f -p)
return 0;
fi
fi
COMPREPLY=( $(compgen -d /var/db/pkg/$cur | sed sN/var/db/pkg/NNg) )
return 0
}
complete -F _pkg_func pkg_delete pkg_info
@@ -0,0 +1,43 @@
#
# Originally from:
#
#Message-ID: <3B13EC65.179451AE@wanadoo.fr>
#Date: Tue, 29 May 2001 20:37:25 +0200
#From: Manu Rouat <emmanuel.rouat@wanadoo.fr>
#Subject: [bash] Universal command options completion?
#
#
#In the recent versions of bash (after 2.04) programmable
#completion is available. A useful completion function
#is , for a particular command, to enumerate all flags
#that can be used in the command. Now, most GNU unix
#commands have so-called 'long options' for example:
#
#ls --color=always --no-group --size
#
#and these are all listed when you issue a '--help' flag.
#So the idea is to use that, then parse the output of the
#'--help' and reinject this to compgen. The basis of the
#following 'universal' completion funtion was the _configure_func'
#written by Ian McDonnald (or is it Chet Ramey ?)
#A dedicated function will always be better, but this is quite
#convenient. I chose to use 'long options' because they are
#easy to parse and explicit too (it's the point I guess...)
#Lots of room for improvement !
_longopt_func ()
{
case "$2" in
-*) ;;
*) return ;;
esac
case "$1" in
\~*) eval cmd=$1 ;;
*) cmd="$1" ;;
esac
COMPREPLY=( $("$cmd" --help | sed -e '/--/!d' -e 's/.*--\([^ ]*\).*/--\1/'| \
grep ^"$2" |sort -u) )
}
complete -o default -F _longopt_func ldd wget bash id info # some examples that work
@@ -0,0 +1,433 @@
#####
#To: chet@po.cwru.edu, sarahmckenna@lucent.com
#Message-Id: <slrn8mqioc.msb.ian@lovelorn.linuxcare.com>
#Posted-To: comp.unix.shell, gnu.bash.bug
#Subject: bash 2.04 programmable completion examples
#Reply-To: ian@linuxcare.com, ian@caliban.org
#Summary: examples of programmable completion for bash 2.04
#Date: Thu, 13 Jul 2000 00:52:33 -0400 (EDT)
#From: ianmacd@linuxcare.com (Ian Macdonald)
#####
#########################################################################
# Turn on extended globbing
shopt -s extglob
# A lot of the following one-liners were taken directly from the
# completion examples provided with the bash 2.04 source distribution
# Make directory commands see only directories
complete -d cd mkdir rmdir pushd
# Make file commands see only files
complete -f cat less more chown ln strip
complete -f -X '*.gz' gzip
complete -f -X '*.Z' compress
complete -f -X '!*.+(Z|gz|tgz|Gz)' gunzip zcat zmore
complete -f -X '!*.Z' uncompress zmore zcat
complete -f -X '!*.+(gif|jpg|jpeg|GIF|JPG|bmp)' ee xv
complete -f -X '!*.+(ps|PS|ps.gz)' gv
complete -f -X '!*.+(dvi|DVI)' dvips xdvi dviselect dvitype
complete -f -X '!*.+(pdf|PDF)' acroread xpdf
complete -f -X '!*.texi*' makeinfo texi2dvi texi2html
complete -f -X '!*.+(tex|TEX)' tex latex slitex
complete -f -X '!*.+(mp3|MP3)' mpg123
# kill sees only signals
complete -A signal kill -P '%'
# user commands see only users
complete -u finger su usermod userdel passwd
# bg completes with stopped jobs
complete -A stopped -P '%' bg
# other job commands
complete -j -P '%' fg jobs disown
# network commands complete with hostname
complete -A hostname ssh rsh telnet rlogin ftp ping fping host traceroute \
nslookup
# export and others complete with shell variables
complete -v export local readonly unset
# set completes with set options
complete -A setopt set
# shopt completes with shopt options
complete -A shopt shopt
# helptopics
complete -A helptopic help
# unalias completes with aliases
complete -a unalias
# various commands complete with commands
complete -c command type nohup exec nice eval strace gdb
# bind completes with readline bindings (make this more intelligent)
complete -A binding bind
# Now we get to the meat of the file, the functions themselves. Some
# of these are works in progress. Most assume GNU versions of the
# tools in question and may require modifications for use on vanilla
# UNIX systems.
#
# A couple of functions may have non-portable, Linux specific code in
# them, but this will be noted where applicable
# GNU chown(1) completion. This should be expanded to allow the use of
# ':' as well as '.' as the user.group separator.
#
_chown ()
{
local cur prev user group
COMPREPLY=()
cur=${COMP_WORDS[COMP_CWORD]}
prev=${COMP_WORDS[COMP_CWORD-1]}
# do not attempt completion if we're specifying an option
if [ "${cur:0:1}" = "-" ]; then return 0; fi
# first parameter on line or first since an option?
if [ $COMP_CWORD -eq 1 ] || [ "${prev:0:1}" = "-" ]; then
case "$cur" in
[a-zA-Z]*.*)
user=${cur%.*}
group=${cur#*.}
COMPREPLY=( $( awk 'BEGIN {FS=":"} \
{if ($1 ~ /^'$group'/) print $1}' \
/etc/group ) )
for (( i=0; i < ${#COMPREPLY[@]}; i++ )); do
COMPREPLY[i]=$user.${COMPREPLY[i]}
done
return 0
;;
*)
COMPREPLY=( $( compgen -u $cur -S '.' ) )
return 0
;;
esac
else
COMPREPLY=( $( compgen -f $cur ) )
fi
return 0
}
complete -F _chown chown
# umount(8) completion. This relies on the mount point being the third
# space-delimited field in the output of mount(8)
#
_umount ()
{
local cur
COMPREPLY=()
cur=${COMP_WORDS[COMP_CWORD]}
# could rewrite the cut | grep to be a sed command, but this is
# clearer and doesn't result in much overhead
COMPREPLY=( $( mount | cut -d' ' -f 3 | grep ^$cur) )
return 0
}
complete -F _umount umount
# GID completion. This will get a list of all valid group names from
# /etc/group and should work anywhere.
#
_gid_func ()
{
local cur
COMPREPLY=()
cur=${COMP_WORDS[COMP_CWORD]}
COMPREPLY=( $( awk 'BEGIN {FS=":"} {if ($1 ~ /^'$cur'/) print $1}' \
/etc/group ) )
return 0
}
complete -F _gid_func groupdel groupmod
# mount(8) completion. This will pull a list of possible mounts out of
# /etc/fstab, unless the word being completed contains a ':', which
# would indicate the specification of an NFS server. In that case, we
# query the server for a list of all available exports and complete on
# that instead.
#
_mount ()
{ local cur
COMPREPLY=()
cur=${COMP_WORDS[COMP_CWORD]}
case "$cur" in
*:*)
COMPREPLY=( $( /usr/sbin/showmount -e --no-headers ${cur%%:*} |\
grep ^${cur#*:} | awk '{print $1}'))
return 0
;;
*)
COMPREPLY=( $( awk '{if ($2 ~ /\//) print $2}' /etc/fstab | \
grep ^$cur ))
return 0
;;
esac
}
complete -F _mount mount
# Linux rmmod(1) completion. This completes on a list of all currently
# installed kernel modules.
#
_rmmod ()
{
local cur
COMPREPLY=()
cur=${COMP_WORDS[COMP_CWORD]}
COMPREPLY=($( lsmod | awk '{if (NR != 1 && $1 ~ /^'$cur'/) print $1}'))
return 0
}
complete -F _rmmod rmmod
# Linux insmod(1) completion. This completes on a list of all
# available modules for the version of the kernel currently running.
#
_insmod ()
{
local cur modpath
COMPREPLY=()
cur=${COMP_WORDS[COMP_CWORD]}
modpath=/lib/modules/`uname -r`
COMPREPLY=($( ls -R $modpath | sed -ne 's/^\('$cur'.*\)\.o$/\1/p'))
return 0
}
complete -F _insmod insmod depmod modprobe
# man(1) completion. This relies on the security enhanced version of
# GNU locate(1). UNIX variants having non-numeric man page sections
# other than l, m and n should add the appropriate sections to the
# first clause of the case statement.
#
# This is Linux specific, in that 'man <section> <page>' is the
# expected syntax. This allows one to do something like
# 'man 3 str<tab>' to obtain a list of all string handling syscalls on
# the system.
#
_man ()
{
local cur prev
COMPREPLY=()
cur=${COMP_WORDS[COMP_CWORD]}
prev=${COMP_WORDS[COMP_CWORD-1]}
case "$prev" in
[0-9lmn])
COMPREPLY=($( slocate -ql 0 -r '/man/man'$prev'/'$cur | \
sed -ne 's/^.*\/\('$cur'[^.\/]*\)\..*$/\1/p' ))
return 0
;;
*)
COMPREPLY=($( slocate -ql 0 -r '/man/man./'$cur | \
sed -ne 's/^.*\/\('$cur'[^.\/]*\)\..*$/\1/p' ))
return 0
;;
esac
}
complete -F _man man
# Linux killall(1) completion. This wouldn't be much use on, say,
# Solaris, where killall does exactly that: kills ALL processes.
#
# This could be improved. For example, it currently doesn't take
# command line options into account
#
_killall ()
{
local cur prev
COMPREPLY=()
cur=${COMP_WORDS[COMP_CWORD]}
prev=${COMP_WORDS[COMP_CWORD-1]}
case "$prev" in
-[A-Z0-9]*)
# get a list of processes (the first sed evaluation
# takes care of swapped out processes, the second
# takes care of getting the basename of the process)
COMPREPLY=( $( ps ahx | awk '{if ($5 ~ /^'$cur'/) print $5}' | \
sed -e 's#[]\[]##g' -e 's#^.*/##' ))
return 0
;;
esac
# first parameter can be either a signal or a process
if [ $COMP_CWORD -eq 1 ]; then
# standard signal completion is rather braindead, so we need
# to hack around to get what we want here, which is to
# complete on a dash, followed by the signal name minus
# the SIG prefix
COMPREPLY=( $( compgen -A signal SIG${cur#-} ))
for (( i=0; i < ${#COMPREPLY[@]}; i++ )); do
COMPREPLY[i]=-${COMPREPLY[i]#SIG}
done
fi
# get processes, adding to signals if applicable
COMPREPLY=( ${COMPREPLY[*]} $( ps ahx | \
awk '{if ($5 ~ /^'$cur'/) print $5}' | \
sed -e 's#[]\[]##g' -e 's#^.*/##' ))
return 0
}
complete -F _killall killall
# GNU find(1) completion. This makes heavy use of ksh style extended
# globs and contains Linux specific code for completing the parameter
# to the -fstype option.
#
_find ()
{
local cur prev
COMPREPLY=()
cur=${COMP_WORDS[COMP_CWORD]#-}
prev=${COMP_WORDS[COMP_CWORD-1]}
case "$prev" in
-@(max|min)depth)
COMPREPLY=( $( compgen -W '0 1 2 3 4 5 6 7 8 9' ) )
return 0
;;
-?(a)newer|-fls|-fprint?(0|f))
COMPREPLY=( $( compgen -f $cur ) )
return 0
;;
-fstype)
# this is highly non-portable (the option to -d is a tab)
COMPREPLY=( $( cut -d' ' -f 2 /proc/filesystems | grep ^$cur ) )
return 0
;;
-gid)
COMPREPLY=( $( awk 'BEGIN {FS=":"} \
{if ($3 ~ /^'$cur'/) print $3}' /etc/group ) )
return 0
;;
-group)
COMPREPLY=( $( awk 'BEGIN {FS=":"} \
{if ($1 ~ /^'$cur'/) print $1}' /etc/group ) )
return 0
;;
-?(x)type)
COMPREPLY=( $( compgen -W 'b c d p f l s' $cur ) )
return 0
;;
-uid)
COMPREPLY=( $( awk 'BEGIN {FS=":"} \
{if ($3 ~ /^'$cur'/) print $3}' /etc/passwd ) )
return 0
;;
-user)
COMPREPLY=( $( compgen -u $cur ) )
return 0
;;
-[acm]min|-[acm]time|-?(i)?(l)name|-inum|-?(i)path|-?(i)regex| \
-links|-perm|-size|-used|-exec|-ok|-printf)
# do nothing, just wait for a parameter to be given
return 0
;;
esac
# complete using basic options ($cur has had its dash removed here,
# as otherwise compgen will bomb out with an error, since it thinks
# the dash is an option to itself)
COMPREPLY=( $( compgen -W 'daystart depth follow help maxdepth \
mindepth mount noleaf version xdev amin anewer atime \
cmin cnewer ctime empty false fstype gid group ilname \
iname inum ipath iregex links lname mmin mtime name \
newer nouser nogroup perm regex size true type uid \
used user xtype exec fls fprint fprint0 fprintf ok \
print print0 printf prune ls' $cur ) )
# this removes any options from the list of completions that have
# already been specified somewhere on the command line.
COMPREPLY=( $( echo "${COMP_WORDS[@]}-" | \
(while read -d '-' i; do
[ "$i" == "" ] && continue
# flatten array with spaces on either side,
# otherwise we cannot grep on word boundaries of
# first and last word
COMPREPLY=" ${COMPREPLY[@]} "
# remove word from list of completions
COMPREPLY=( ${COMPREPLY/ ${i%% *} / } )
done
echo ${COMPREPLY[@]})
) )
# put dashes back
for (( i=0; i < ${#COMPREPLY[@]}; i++ )); do
COMPREPLY[i]=-${COMPREPLY[i]}
done
return 0
}
complete -F _find find
# Linux ifconfig(8) completion
#
_ifconfig ()
{
local cur
COMPREPLY=()
cur=${COMP_WORDS[COMP_CWORD]}
case "${COMP_WORDS[1]}" in
-|*[0-9]*)
COMPREPLY=( $( compgen -W '-a up down arp promisc allmulti \
metric mtu dstaddr netmask add del \
tunnel irq io_addr mem_start media \
broadcast pointopoint hw multicast \
address txqueuelen' $cur ))
COMPREPLY=( $( echo " ${COMP_WORDS[@]}" | \
(while read -d ' ' i; do
[ "$i" == "" ] && continue
# flatten array with spaces on either side,
# otherwise we cannot grep on word
# boundaries of first and last word
COMPREPLY=" ${COMPREPLY[@]} "
# remove word from list of completions
COMPREPLY=( ${COMPREPLY/ $i / } )
done
echo ${COMPREPLY[@]})
) )
return 0
;;
esac
COMPREPLY=( $( ifconfig -a | sed -ne 's/^\('$cur'[^ ]*\).*$/\1/p' ))
}
complete -F _ifconfig ifconfig
# Linux ipsec(8) completion (for FreeS/WAN). Very basic.
#
_ipsec ()
{
local cur
COMPREPLY=()
cur=${COMP_WORDS[COMP_CWORD]}
COMPREPLY=( $( compgen -W 'auto barf eroute klipsdebug look manual \
pluto ranbits rsasigkey setup showdefaults \
showhostkey spi spigrp tncfg whack' $cur ))
}
complete -F _ipsec ipsec
#########################################################################
@@ -0,0 +1,271 @@
#####
#From: ian@linuxcare.com (Ian Macdonald)
#Newsgroups: comp.unix.shell
#Subject: More bash 2.04 completions
#Date: 12 Aug 2000 09:53:40 GMT
#Organization: Linuxcare, Inc.
#Lines: 274
#Message-ID: <slrn8pa7l2.jgm.ian@lovelorn.linuxcare.com>
#Reply-To: ian@linuxcare.com
#####
# Turn on extended globbing
shopt -s extglob
# cvs(1) completion
#
_cvs ()
{
local cur prev
COMPREPLY=()
cur=${COMP_WORDS[COMP_CWORD]}
prev=${COMP_WORDS[COMP_CWORD-1]}
if [ $COMP_CWORD -eq 1 ] || [ "${prev:0:1}" = "-" ]; then
COMPREPLY=( $( compgen -W 'add admin checkout commit diff \
export history import log rdiff release remove rtag status \
tag update' $cur ))
else
COMPREPLY=( $( compgen -f $cur ))
fi
return 0
}
complete -F _cvs cvs
# rpm(8) completion. This isn't exhaustive yet, but still provides
# quite a lot of functionality.
#
_rpm()
{
dashify()
{
local i
for (( i=0; i < ${#COMPREPLY[@]}; i++ )); do
if [ ${#COMPREPLY[i]} -le 2 ]; then
COMPREPLY[i]=-${COMPREPLY[i]}
else
COMPREPLY[i]=--${COMPREPLY[i]}
fi
done
}
local cur cur_nodash prev
COMPREPLY=()
cur=${COMP_WORDS[COMP_CWORD]}
cur_nodash=${cur#-}
prev=${COMP_WORDS[COMP_CWORD-1]}
if [ $COMP_CWORD = 1 ]; then
# first parameter on line
case "$cur" in
-b*)
COMPREPLY=( $( compgen -W 'ba bb bc bi bl bp bs' \
$cur_nodash ) )
dashify
return 0
;;
-t*)
COMPREPLY=( $( compgen -W 'ta tb tc ti tl tp ts' \
$cur_nodash ) )
dashify
return 0
;;
--*)
COMPREPLY=( $( compgen -W 'help version initdb \
checksig recompile rebuild resign addsign rebuilddb \
showrc setperms setgids' ${cur_nodash#-} ) )
dashify;
return 0
;;
*)
COMPREPLY=( $( compgen -W 'b e F i q t U V' \
$cur_nodash ) )
dashify
return 0
;;
esac
fi
case "${COMP_WORDS[1]}" in
-[iFU]*)
# complete on list of relevant options
COMPREPLY=( $( compgen -W 'percent force test replacepkgs \
replacefiles root excludedocs includedocs noscripts rcfile \
ignorearch dbpath prefix ignoreos nodeps allfiles ftpproxy \
ftpport justdb httpproxy httpport noorder relocate badreloc \
notriggers excludepath ignoresize oldpackage' ${cur_nodash#-} ))
dashify;
# return if $cur is an option
[ "${cur:0:1}" = "-" ] && return 0
# add a list of RPMS to possible completions
COMPREPLY=( ${COMPREPLY[@]} $( compgen -G $cur\*.rpm ) )
return 0
;;
-qp*)
# complete on list of relevant options
COMPREPLY=( $( compgen -W 'scripts root rcfile whatprovides \
whatrequires requires triggeredby ftpport ftpproxy httpproxy \
httpport provides triggers dump changelog dbpath filesbypkg' \
${cur_nodash#-} ) )
dashify;
# return if $cur is an option
[ "${cur:0:1}" = "-" ] && return 0
# add a list of RPMS to possible completions
COMPREPLY=( ${COMPREPLY[@]} $( compgen -G $cur\*.rpm ) )
return 0
;;
-*f)
# standard filename completion
COMPREPLY=( $( compgen -f $cur ) )
return 0
;;
-e)
# complete on list of relevant options
COMPREPLY=( $( compgen -W 'allmatches noscripts notriggers \
nodeps test' ${cur_nodash#-} ) )
dashify;
# return if $cur is an option
[ "${cur:0:1}" = "-" ] && return 0
# complete on basename of installed RPMs
COMPREPLY=( $( rpm -qa | \
sed -ne 's/^\('$cur'.*\)-[0-9a-zA-Z._]\+-[0-9.]\+$/\1/p' ) )
return 0
;;
-qa*)
# complete on list of relevant options
COMPREPLY=( $( compgen -W 'scripts root rcfile whatprovides \
whatrequires requires triggeredby ftpport ftpproxy httpproxy \
httpport provides triggers dump changelog dbpath specfile \
querybynumber last filesbypkg' ${cur_nodash#-} ) )
dashify;
return 0
;;
-q*)
# complete on list of relevant options
COMPREPLY=( $( compgen -W 'scripts root rcfile whatprovides \
whatrequires requires triggeredby ftpport ftpproxy httpproxy \
httpport provides triggers dump changelog dbpath specfile \
querybynumber last filesbypkg' ${cur_nodash#-} ) )
dashify;
# return if $cur is an option
[ "${cur:0:1}" = "-" ] && return 0
# add a list of RPMS to possible completions
COMPREPLY=( ${COMPREPLY[@]} $( rpm -qa | \
sed -ne 's/^\('$cur'.*\)-[0-9a-zA-Z._]\+-[0-9.]\+$/\1/p' ) )
return 0
;;
-[Vy]*)
# complete on list of relevant options
COMPREPLY=( $( compgen -W 'root rcfile dbpath nodeps nofiles \
noscripts nomd5 nopgp' ${cur_nodash#-} ) )
dashify;
# return if $cur is an option
[ "${cur:0:1}" = "-" ] && return 0
# add a list of RPMS to possible completions
COMPREPLY=( ${COMPREPLY[@]} $( rpm -qa | \
sed -ne 's/^\('$cur'.*\)-[0-9a-zA-Z._]\+-[0-9.]\+$/\1/p' ) )
return 0
;;
-b*)
# complete on list of relevant options
COMPREPLY=( $( compgen -W 'short-circuit timecheck clean \
rmsource test sign buildroot target buildarch buildos' \
${cur_nodash#-} ) )
dashify;
# return if $cur is an option
[ "${cur:0:1}" = "-" ] && return 0
# complete on .spec files
COMPREPLY=( $( compgen -G $cur\*.spec ) )
return 0
;;
-t*)
# complete on list of relevant options
COMPREPLY=( $( compgen -W 'short-circuit timecheck clean \
rmsource test sign buildroot target buildarch buildos' \
${cur_nodash#-} ) )
dashify;
# return if $cur is an option
[ "${cur:0:1}" = "-" ] && return 0
# complete on .tar.gz files
COMPREPLY=( $( compgen -G $cur\*.tar.gz ) )
return 0
;;
--re@(build|compile))
# complete on source RPMs
COMPREPLY=( $( compgen -G $cur\*.src.rpm ) )
return 0
;;
--@(checksig|@(re|add)sign))
# complete on RPMs
COMPREPLY=( $( compgen -G $cur\*.rpm ) )
return 0
;;
--set@(perms|gids))
# complete on installed RPMs
COMPREPLY=( ${COMPREPLY[@]} $( rpm -qa | \
sed -ne 's/^\('$cur'.*\)-[0-9a-zA-Z._]\+-[0-9.]\+$/\1/p' ) )
return 0
;;
esac
}
complete -F _rpm rpm
# chsh(1) completion
#
_chsh()
{
local cur prev
COMPREPLY=()
cur=${COMP_WORDS[COMP_CWORD]}
prev=${COMP_WORDS[COMP_CWORD-1]}
if [ "$prev" = "-s" ]; then
COMPREPLY=( $( chsh -l | grep ^$cur ) )
else
COMPREPLY=( $( compgen -u $cur ) )
fi
}
complete -F _chsh chsh
# chkconfig(8) completion
#
_chkconfig()
{
local cur prev
COMPREPLY=()
cur=${COMP_WORDS[COMP_CWORD]}
cur_nodash=${cur#--}
prev=${COMP_WORDS[COMP_CWORD-1]}
if [ $COMP_CWORD -eq 1 ]; then
COMPREPLY=( $( compgen -W 'list add del level' $cur_nodash ) )
for (( i=0; i < ${#COMPREPLY[@]}; i++ )); do
COMPREPLY[i]=--${COMPREPLY[i]}
done
return 0
fi
if [ $COMP_CWORD -eq 4 ]; then
COMPREPLY=( $( compgen -W 'on off reset' $cur ) )
return 0
fi
case "$prev" in
@([1-6]|--@(list|add|del)))
COMPREPLY=( $( compgen -W "`(cd /etc/rc.d/init.d; echo *)`" \
$cur) )
return 0
;;
--level)
COMPREPLY=( $( compgen -W '1 2 3 4 5 6' $cur ) )
return 0
;;
esac
}
complete -F _chkconfig chkconfig
###
@@ -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[@]}"
@@ -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
}
+111
View File
@@ -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
}
@@ -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
}
@@ -0,0 +1,125 @@
#From: Mark Kennedy <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 "$@"
}
+23
View File
@@ -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.
}
@@ -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:-.}"
}
@@ -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 $?
}
@@ -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.
@@ -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 $?
}
@@ -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
}
+142
View File
@@ -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
}
+21
View File
@@ -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%/*}"
}
+28
View File
@@ -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
}
+22
View File
@@ -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
+50
View File
@@ -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
}
+13
View File
@@ -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 )) ) ))
}
+59
View File
@@ -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
}
+27
View File
@@ -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
}
+35
View File
@@ -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 "$@"
@@ -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) ***
+60
View File
@@ -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
}
+14
View File
@@ -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" ]
}
@@ -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
}
+22
View File
@@ -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
}
@@ -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 ]
}
@@ -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
+12
View File
@@ -0,0 +1,12 @@
jj ()
{
p=$(jobs $1);
echo $p
case "$p" in
[*) echo matches '[*'
;;
*) echo not a match\?
;;
esac
}
+62
View File
@@ -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
+35
View File
@@ -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
}
@@ -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 $?
+228
View File
@@ -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
}
+11
View File
@@ -0,0 +1,11 @@
# replace the `login' and `newgrp' builtins in old bourne shells
login()
{
exec login "$@"
}
newgrp()
{
exec newgrp "$@"
}
@@ -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
}
+129
View File
@@ -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
}
+16
View File
@@ -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$$
}
@@ -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
}
@@ -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;:\$;;"`
}
+63
View File
@@ -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"'
+43
View File
@@ -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
}
+12
View File
@@ -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;
}
+29
View File
@@ -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
}
+37
View File
@@ -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
}
+7
View File
@@ -0,0 +1,7 @@
shcat()
{
while read -r line
do
echo "$line"
done
}
+19
View File
@@ -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
}
@@ -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
+21
View File
@@ -0,0 +1,21 @@
#From: Syamala Rao Tadigadapa <stadigad@us.oracle.com>
#Subject: Re: Division in ksh(getting the exact number) Please HELP
#Date: Mon, 25 Oct 1999 15:05:08 -0700
#Message-ID: <3814D414.7B896084@us.oracle.com>
#Here is how to calculate the (integer part of the) square root
#of a number in a much cleaner way.
sqroot()
{
let arg=$1
let root=arg
while :
do
newroot=$(( (root+arg/root)/2 ))
(( newroot == root )) && { echo $root; return; }
let root=newroot
done
}
sqroot "$@"
+79
View File
@@ -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
}
+81
View File
@@ -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
}
+35
View File
@@ -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
}
+52
View File
@@ -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
}
+59
View File
@@ -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
}
+44
View File
@@ -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
}
@@ -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
}
@@ -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 "$@"
@@ -0,0 +1,238 @@
#
# Simple makefile for the sample loadable builtins
#
# Copyright (C) 1996 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
# Include some boilerplate Gnu makefile definitions.
prefix = @prefix@
exec_prefix = @exec_prefix@
bindir = @bindir@
libdir = @libdir@
infodir = @infodir@
includedir = @includedir@
topdir = @top_srcdir@
BUILD_DIR = @BUILD_DIR@
srcdir = @srcdir@
VPATH = .:@srcdir@
@SET_MAKE@
CC = @CC@
RM = rm -f
SHELL = @MAKE_SHELL@
host_os = @host_os@
host_cpu = @host_cpu@
host_vendor = @host_vendor@
CFLAGS = @CFLAGS@
LOCAL_CFLAGS = @LOCAL_CFLAGS@
DEFS = @DEFS@
LOCAL_DEFS = @LOCAL_DEFS@
CPPFLAGS = @CPPFLAGS@
BASHINCDIR = ${topdir}/include
LIBBUILD = ${BUILD_DIR}/lib
INTL_LIBSRC = ${topdir}/lib/intl
INTL_BUILDDIR = ${LIBBUILD}/intl
INTL_INC = @INTL_INC@
LIBINTL_H = @LIBINTL_H@
CCFLAGS = $(DEFS) $(LOCAL_DEFS) $(LOCAL_CFLAGS) $(CFLAGS)
#
# These values are generated for configure by ${topdir}/support/shobj-conf.
# If your system is not supported by that script, but includes facilities for
# dynamic loading of shared objects, please update the script and send the
# changes to bash-maintainers@gnu.org.
#
SHOBJ_CC = @SHOBJ_CC@
SHOBJ_CFLAGS = @SHOBJ_CFLAGS@
SHOBJ_LD = @SHOBJ_LD@
SHOBJ_LDFLAGS = @SHOBJ_LDFLAGS@
SHOBJ_XLDFLAGS = @SHOBJ_XLDFLAGS@
SHOBJ_LIBS = @SHOBJ_LIBS@
SHOBJ_STATUS = @SHOBJ_STATUS@
INC = -I. -I.. -I$(topdir) -I$(topdir)/lib -I$(topdir)/builtins \
-I$(BASHINCDIR) -I$(BUILD_DIR) -I$(LIBBUILD) \
-I$(BUILD_DIR)/builtins $(INTL_INC)
.c.o:
$(SHOBJ_CC) $(SHOBJ_CFLAGS) $(CCFLAGS) $(INC) -c -o $@ $<
ALLPROG = print truefalse sleep pushd finfo logname basename dirname \
tty pathchk tee head mkdir rmdir printenv id whoami \
uname sync push ln unlink cut realpath getconf strftime
OTHERPROG = necho hello cat
all: $(SHOBJ_STATUS)
supported: $(ALLPROG)
others: $(OTHERPROG)
unsupported:
@echo "Your system (${host_os}) is not supported by the"
@echo "${topdir}/support/shobj-conf script."
@echo "If your operating system provides facilities for dynamic"
@echo "loading of shared objects using the dlopen(3) interface,"
@echo "please update the script and re-run configure.
@echo "Please send the changes you made to bash-maintainers@gnu.org"
@echo "for inclusion in future bash releases."
everything: supported others
print: print.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ print.o $(SHOBJ_LIBS)
necho: necho.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ necho.o $(SHOBJ_LIBS)
getconf: getconf.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ getconf.o $(SHOBJ_LIBS)
hello: hello.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ hello.o $(SHOBJ_LIBS)
truefalse: truefalse.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ truefalse.o $(SHOBJ_LIBS)
sleep: sleep.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ sleep.o $(SHOBJ_LIBS)
finfo: finfo.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ finfo.o $(SHOBJ_LIBS)
cat: cat.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ cat.o $(SHOBJ_LIBS)
logname: logname.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ logname.o $(SHOBJ_LIBS)
basename: basename.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ basename.o $(SHOBJ_LIBS)
dirname: dirname.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ dirname.o $(SHOBJ_LIBS)
tty: tty.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ tty.o $(SHOBJ_LIBS)
pathchk: pathchk.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ pathchk.o $(SHOBJ_LIBS)
tee: tee.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ tee.o $(SHOBJ_LIBS)
mkdir: mkdir.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ mkdir.o $(SHOBJ_LIBS)
rmdir: rmdir.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ rmdir.o $(SHOBJ_LIBS)
head: head.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ head.o $(SHOBJ_LIBS)
printenv: printenv.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ printenv.o $(SHOBJ_LIBS)
id: id.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ id.o $(SHOBJ_LIBS)
whoami: whoami.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ whoami.o $(SHOBJ_LIBS)
uname: uname.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ uname.o $(SHOBJ_LIBS)
sync: sync.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ sync.o $(SHOBJ_LIBS)
push: push.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ push.o $(SHOBJ_LIBS)
ln: ln.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ ln.o $(SHOBJ_LIBS)
unlink: unlink.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ unlink.o $(SHOBJ_LIBS)
cut: cut.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ cut.o $(SHOBJ_LIBS)
realpath: realpath.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ realpath.o $(SHOBJ_LIBS)
strftime: strftime.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ strftime.o $(SHOBJ_LIBS)
# pushd is a special case. We use the same source that the builtin version
# uses, with special compilation options.
#
pushd.c: ${topdir}/builtins/pushd.def
$(RM) $@
${BUILD_DIR}/builtins/mkbuiltins -D ${topdir}/builtins ${topdir}/builtins/pushd.def
pushd.o: pushd.c
$(RM) $@
$(SHOBJ_CC) -DHAVE_CONFIG_H -DPUSHD_AND_POPD -DLOADABLE_BUILTIN $(SHOBJ_CFLAGS) $(CFLAGS) $(CPPFLAGS) $(INC) -c -o $@ $<
pushd: pushd.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ pushd.o $(SHOBJ_LIBS)
clean:
$(RM) $(ALLPROG) $(OTHERPROG) *.o
-( cd perl && ${MAKE} ${MFLAGS} $@ )
mostlyclean: clean
-( cd perl && ${MAKE} ${MFLAGS} $@ )
distclean maintainer-clean: clean
$(RM) Makefile pushd.c
-( cd perl && ${MAKE} ${MFLAGS} $@ )
print.o: print.c
truefalse.o: truefalse.c
sleep.o: sleep.c
finfo.o: finfo.c
logname.o: logname.c
basename.o: basename.c
dirname.o: dirname.c
tty.o: tty.c
pathchk.o: pathchk.c
tee.o: tee.c
head.o: head.c
rmdir.o: rmdir.c
necho.o: necho.c
getconf.o: getconf.c
hello.o: hello.c
cat.o: cat.c
printenv.o: printenv.c
id.o: id.c
whoami.o: whoami.c
uname.o: uname.c
sync.o: sync.c
push.o: push.c
mkdir.o: mkdir.c
realpath.o: realpath.c
strftime.o: strftime.c
+66
View File
@@ -0,0 +1,66 @@
Some examples of ready-to-dynamic-load builtins. Most of the
examples given are reimplementations of standard commands whose
execution time is dominated by process startup time. The
exceptions are sleep, which allows you to sleep for fractions
of a second, finfo, which provides access to the rest of the
elements of the `stat' structure that `test' doesn't let you
see, and pushd/popd/dirs, which allows you to compile them out
of the shell.
All of the new builtins in ksh93 that bash didn't already have
are included here, as is the ksh `print' builtin.
The configure script in the top-level source directory uses the
support/shobj-conf script to set the right values in the Makefile,
so you should not need to change the Makefile. If your system
is not supported by support/shobj-conf, and it has the necessary
facilities for building shared objects and support for the
dlopen/dlsyn/dlclose/dlerror family of functions, please make
the necessary changes to support/shobj-conf and send the changes
to bash-maintainers@gnu.org.
Loadable builtins are loaded into a running shell with
enable -f filename builtin-name
enable uses a simple reference-counting scheme to avoid unloading a
shared object that implements more than one loadable builtin before
all loadable builtins implemented in the object are removed.
Many of the details needed by builtin writers are found in hello.c,
the canonical example. There is no real `builtin writers' programming
guide'. The file template.c provides a template to use for creating
new loadable builtins.
basename.c Return non-directory portion of pathname.
cat.c cat(1) replacement with no options - the way cat was intended.
cut.c cut(1) replacement.
dirname.c Return directory portion of pathname.
finfo.c Print file info.
getconf.c POSIX.2 getconf utility.
getconf.h Replacement definitions for ones the system doesn't provide.
head.c Copy first part of files.
hello.c Obligatory "Hello World" / sample loadable.
id.c POSIX.2 user identity.
ln.c Make links.
logname.c Print login name of current user.
Makefile.in Simple makefile for the sample loadable builtins.
mkdir.c Make directories.
necho.c echo without options or argument interpretation.
pathchk.c Check pathnames for validity and portability.
print.c Loadable ksh-93 style print builtin.
printenv.c Minimal builtin clone of BSD printenv(1).
push.c Anyone remember TOPS-20?
README README
realpath.c Canonicalize pathnames, resolving symlinks.
rmdir.c Remove directory.
sleep.c sleep for fractions of a second.
strftime.c Loadable builtin interface to strftime(3).
sync.c Sync the disks by forcing pending filesystem writes to complete.
tee.c Duplicate standard input.
template.c Example template for loadable builtin.
truefalse.c True and false builtins.
tty.c Return terminal name.
uname.c Print system information.
unlink.c Remove a directory entry.
whoami.c Print out username of current user.
+4
View File
@@ -0,0 +1,4 @@
cmp
wc
mkfifo
paste
+108
View File
@@ -0,0 +1,108 @@
/* basename - return nondirectory portion of pathname */
/* See Makefile for compilation details. */
#include "config.h"
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include <stdio.h>
#include "builtins.h"
#include "shell.h"
basename_builtin (list)
WORD_LIST *list;
{
int slen, sufflen, off;
char *string, *suffix, *fn;
if (list == 0)
{
builtin_usage ();
return (EX_USAGE);
}
if (no_options (list))
return (EX_USAGE);
string = list->word->word;
suffix = (char *)NULL;
if (list->next)
{
list = list->next;
suffix = list->word->word;
}
if (list->next)
{
builtin_usage ();
return (EX_USAGE);
}
slen = strlen (string);
/* Strip trailing slashes */
while (slen > 0 && string[slen - 1] == '/')
slen--;
/* (2) If string consists entirely of slash characters, string shall be
set to a single slash character. In this case, skip steps (3)
through (5). */
if (slen == 0)
{
fputs ("/\n", stdout);
return (EXECUTION_SUCCESS);
}
/* (3) If there are any trailing slash characters in string, they
shall be removed. */
string[slen] = '\0';
/* (4) If there are any slash characters remaining in string, the prefix
of string up to an including the last slash character in string
shall be removed. */
while (--slen >= 0)
if (string[slen] == '/')
break;
fn = string + slen + 1;
/* (5) If the suffix operand is present, is not identical to the
characters remaining in string, and is identical to a suffix
of the characters remaining in string, the suffix suffix
shall be removed from string. Otherwise, string shall not be
modified by this step. */
if (suffix)
{
sufflen = strlen (suffix);
slen = strlen (fn);
if (sufflen < slen)
{
off = slen - sufflen;
if (strcmp (fn + off, suffix) == 0)
fn[off] = '\0';
}
}
printf ("%s\n", fn);
return (EXECUTION_SUCCESS);
}
char *basename_doc[] = {
"The STRING is converted to a filename corresponding to the last",
"pathname component in STRING. If the suffix string SUFFIX is",
"supplied, it is removed.",
(char *)NULL
};
/* The standard structure describing a builtin command. bash keeps an array
of these structures. */
struct builtin basename_struct = {
"basename", /* builtin name */
basename_builtin, /* function implementing the builtin */
BUILTIN_ENABLED, /* initial flags for builtin */
basename_doc, /* array of long documentation strings. */
"basename string [suffix]", /* usage synopsis */
0 /* reserved for internal use */
};
@@ -0,0 +1,191 @@
#include <stdio.h>
#include <limits.h>
#include <locale.h>
#include <unistd.h>
#include <errno.h>
#include <stdarg.h>
#include "bashansi.h"
#include "shell.h"
#include "builtins.h"
#include "stdc.h"
#include "common.h"
#include "bashgetopt.h"
char *this_command_name = (char *)NULL;
void
builtin_error (const char *format, ...)
{
va_list args;
char *name;
name = get_name_for_error ();
fprintf (stderr, "%s: ", name);
if (this_command_name && *this_command_name)
fprintf (stderr, "%s: ", this_command_name);
va_start (args, format);
vfprintf (stderr, format, args);
va_end (args);
fprintf (stderr, "\n");
}
int
no_options(list)
WORD_LIST *list;
{
reset_internal_getopt ();
if (internal_getopt (list, "") != -1)
{
builtin_usage ();
return (1);
}
return (0);
}
int
legal_number (string, result)
char *string;
long *result;
{
long value;
char *ep;
if (result)
*result = 0;
value = strtol (string, &ep, 10);
/* If *string is not '\0' but *ep is '\0' on return, the entire string
is valid. */
if (string && *string && *ep == '\0')
{
if (result)
*result = value;
/* The SunOS4 implementation of strtol() will happily ignore
overflow conditions, so this cannot do overflow correctly
on those systems. */
return 1;
}
return (0);
}
/* Return the number of elements in LIST, a generic list. */
int
list_length (list)
GENERIC_LIST *list;
{
register int i;
for (i = 0; list; list = list->next, i++);
return (i);
}
GENERIC_LIST *
reverse_list (list)
GENERIC_LIST *list;
{
register GENERIC_LIST *next, *prev;
for (prev = (GENERIC_LIST *)NULL; list; )
{
next = list->next;
list->next = prev;
prev = list;
list = next;
}
return (prev);
}
WORD_DESC *
make_bare_word (string)
char *string;
{
WORD_DESC *temp;
temp = (WORD_DESC *)xmalloc (sizeof (WORD_DESC));
if (*string)
temp->word = savestring (string);
else
{
temp->word = xmalloc (1);
temp->word[0] = '\0';
}
temp->flags = 0;
return (temp);
}
WORD_LIST *
make_word_list (word, link)
WORD_DESC *word;
WORD_LIST *link;
{
WORD_LIST *temp;
temp = (WORD_LIST *)xmalloc (sizeof (WORD_LIST));
temp->word = word;
temp->next = link;
return (temp);
}
void
builtin_usage()
{
if (this_command_name && *this_command_name)
fprintf (stderr, "%s: usage: %s args\n", this_command_name, this_command_name);
fflush (stderr);
}
char *
xmalloc(s)
size_t s;
{
return (malloc (s));
}
WORD_LIST *
argv_to_word_list (array, copy, starting_index)
char **array;
int copy, starting_index;
{
WORD_LIST *list;
WORD_DESC *w;
int i, count;
if (array == 0 || array[0] == 0)
return (WORD_LIST *)NULL;
for (count = 0; array[count]; count++)
;
for (i = starting_index, list = (WORD_LIST *)NULL; i < count; i++)
{
w = make_bare_word (copy ? "" : array[i]);
if (copy)
{
free (w->word);
w->word = array[i];
}
list = make_word_list (w, list);
}
return (REVERSE_LIST(list, WORD_LIST *));
}
/* Convert a WORD_LIST into a C-style argv. Return the number of elements
in the list in *IP, if IP is non-null. A convenience function for
loadable builtins; also used by `test'. */
char **
make_builtin_argv (list, ip)
WORD_LIST *list;
int *ip;
{
char **argv;
argv = strvec_from_word_list (list, 0, 1, ip);
argv[0] = this_command_name;
return argv;
}
+100
View File
@@ -0,0 +1,100 @@
/*
* cat replacement
*
* no options - the way cat was intended
*/
#include <fcntl.h>
#include <errno.h>
#include "builtins.h"
#include "shell.h"
#ifndef errno
extern int errno;
#endif
extern char *strerror ();
extern char **make_builtin_argv ();
static int
fcopy(fd)
int fd;
{
char buf[1024], *s;
int n, w, e;
while (n = read(fd, buf, sizeof (buf))) {
w = write(1, buf, n);
if (w != n) {
e = errno;
write(2, "cat: write error: ", 18);
s = strerror(e);
write(2, s, strlen(s));
write(2, "\n", 1);
return 1;
}
}
return 0;
}
cat_main (argc, argv)
int argc;
char **argv;
{
int i, fd, r;
char *s;
if (argc == 1)
return (fcopy(0));
for (i = r = 1; i < argc; i++) {
if (argv[i][0] == '-' && argv[i][1] == '\0')
fd = 0;
else {
fd = open(argv[i], O_RDONLY, 0666);
if (fd < 0) {
s = strerror(errno);
write(2, "cat: cannot open ", 17);
write(2, argv[i], strlen(argv[i]));
write(2, ": ", 2);
write(2, s, strlen(s));
write(2, "\n", 1);
continue;
}
}
r = fcopy(fd);
if (fd != 0)
close(fd);
}
return (r);
}
cat_builtin(list)
WORD_LIST *list;
{
char **v;
int c, r;
v = make_builtin_argv(list, &c);
r = cat_main(c, v);
free(v);
return r;
}
char *cat_doc[] = {
"Read each FILE and display it on the standard output. If any",
"FILE is `-' or if no FILE argument is given, the standard input",
"is read.",
(char *)0
};
struct builtin cat_struct = {
"cat",
cat_builtin,
BUILTIN_ENABLED,
cat_doc,
"cat [-] [file ...]",
0
};
+376
View File
@@ -0,0 +1,376 @@
/*
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Adam S. Moskowitz of Menlo Consulting and Marciano Pitargue.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
static const char copyright[] =
"@(#) Copyright (c) 1989, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static const char sccsid[] = "@(#)cut.c 8.3 (Berkeley) 5/4/95";
#endif /* not lint */
#include <config.h>
#include <ctype.h>
#include <stdio.h>
#include <errno.h>
#include "bashansi.h"
#ifdef HAVE_LIMITS_H
# include <limits.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include "builtins.h"
#include "shell.h"
#include "bashgetopt.h"
#if !defined (errno)
extern int errno;
#endif
#if !defined (_POSIX2_LINE_MAX)
# define _POSIX2_LINE_MAX 2048
#endif
static int cflag;
static char dchar;
static int dflag;
static int fflag;
static int sflag;
static int autostart, autostop, maxval;
static char positions[_POSIX2_LINE_MAX + 1];
static int c_cut __P((FILE *, char *));
static int f_cut __P((FILE *, char *));
static int get_list __P((char *));
static char *_cut_strsep __P((char **, const char *));
int
cut_builtin(list)
WORD_LIST *list;
{
FILE *fp;
int (*fcn) __P((FILE *, char *)) = NULL;
int ch;
fcn = NULL;
dchar = '\t'; /* default delimiter is \t */
/* Since we don't support multi-byte characters, the -c and -b
options are equivalent, and the -n option is meaningless. */
reset_internal_getopt ();
while ((ch = internal_getopt (list, "b:c:d:f:sn")) != -1)
switch(ch) {
case 'b':
case 'c':
fcn = c_cut;
if (get_list(list_optarg) < 0)
return (EXECUTION_FAILURE);
cflag = 1;
break;
case 'd':
dchar = *list_optarg;
dflag = 1;
break;
case 'f':
fcn = f_cut;
if (get_list(list_optarg) < 0)
return (EXECUTION_FAILURE);
fflag = 1;
break;
case 's':
sflag = 1;
break;
case 'n':
break;
case '?':
default:
builtin_usage();
return (EX_USAGE);
}
list = loptend;
if (fflag) {
if (cflag) {
builtin_usage();
return (EX_USAGE);
}
} else if (!cflag || dflag || sflag) {
builtin_usage();
return (EX_USAGE);
}
if (list) {
while (list) {
fp = fopen(list->word->word, "r");
if (fp == 0) {
builtin_error("%s", list->word->word);
return (EXECUTION_FAILURE);
}
ch = (*fcn)(fp, list->word->word);
(void)fclose(fp);
if (ch < 0)
return (EXECUTION_FAILURE);
list = list->next;
}
} else {
ch = (*fcn)(stdin, "stdin");
if (ch < 0)
return (EXECUTION_FAILURE);
}
return (EXECUTION_SUCCESS);
}
static int
get_list(list)
char *list;
{
int setautostart, start, stop;
char *pos;
char *p;
/*
* set a byte in the positions array to indicate if a field or
* column is to be selected; use +1, it's 1-based, not 0-based.
* This parser is less restrictive than the Draft 9 POSIX spec.
* POSIX doesn't allow lists that aren't in increasing order or
* overlapping lists. We also handle "-3-5" although there's no
* real reason too.
*/
for (; (p = _cut_strsep(&list, ", \t")) != NULL;) {
setautostart = start = stop = 0;
if (*p == '-') {
++p;
setautostart = 1;
}
if (isdigit((unsigned char)*p)) {
start = stop = strtol(p, &p, 10);
if (setautostart && start > autostart)
autostart = start;
}
if (*p == '-') {
if (isdigit((unsigned char)p[1]))
stop = strtol(p + 1, &p, 10);
if (*p == '-') {
++p;
if (!autostop || autostop > stop)
autostop = stop;
}
}
if (*p) {
builtin_error("[-cf] list: illegal list value");
return -1;
}
if (!stop || !start) {
builtin_error("[-cf] list: values may not include zero");
return -1;
}
if (stop > _POSIX2_LINE_MAX) {
builtin_error("[-cf] list: %d too large (max %d)",
stop, _POSIX2_LINE_MAX);
return -1;
}
if (maxval < stop)
maxval = stop;
for (pos = positions + start; start++ <= stop; *pos++ = 1);
}
/* overlapping ranges */
if (autostop && maxval > autostop)
maxval = autostop;
/* set autostart */
if (autostart)
memset(positions + 1, '1', autostart);
return 0;
}
/* ARGSUSED */
static int
c_cut(fp, fname)
FILE *fp;
char *fname;
{
int ch, col;
char *pos;
ch = 0;
for (;;) {
pos = positions + 1;
for (col = maxval; col; --col) {
if ((ch = getc(fp)) == EOF)
return;
if (ch == '\n')
break;
if (*pos++)
(void)putchar(ch);
}
if (ch != '\n') {
if (autostop)
while ((ch = getc(fp)) != EOF && ch != '\n')
(void)putchar(ch);
else
while ((ch = getc(fp)) != EOF && ch != '\n');
}
(void)putchar('\n');
}
return (0);
}
static int
f_cut(fp, fname)
FILE *fp;
char *fname;
{
int ch, field, isdelim;
char *pos, *p, sep;
int output;
char lbuf[_POSIX2_LINE_MAX + 1];
for (sep = dchar; fgets(lbuf, sizeof(lbuf), fp);) {
output = 0;
for (isdelim = 0, p = lbuf;; ++p) {
if (!(ch = *p)) {
builtin_error("%s: line too long.", fname);
return -1;
}
/* this should work if newline is delimiter */
if (ch == sep)
isdelim = 1;
if (ch == '\n') {
if (!isdelim && !sflag)
(void)printf("%s", lbuf);
break;
}
}
if (!isdelim)
continue;
pos = positions + 1;
for (field = maxval, p = lbuf; field; --field, ++pos) {
if (*pos) {
if (output++)
(void)putchar(sep);
while ((ch = *p++) != '\n' && ch != sep)
(void)putchar(ch);
} else {
while ((ch = *p++) != '\n' && ch != sep)
continue;
}
if (ch == '\n')
break;
}
if (ch != '\n') {
if (autostop) {
if (output)
(void)putchar(sep);
for (; (ch = *p) != '\n'; ++p)
(void)putchar(ch);
} else
for (; (ch = *p) != '\n'; ++p);
}
(void)putchar('\n');
}
return (0);
}
/*
* Get next token from string *stringp, where tokens are possibly-empty
* strings separated by characters from delim.
*
* Writes NULs into the string at *stringp to end tokens.
* delim need not remain constant from call to call.
* On return, *stringp points past the last NUL written (if there might
* be further tokens), or is NULL (if there are definitely no more tokens).
*
* If *stringp is NULL, strsep returns NULL.
*/
static char *
_cut_strsep(stringp, delim)
register char **stringp;
register const char *delim;
{
register char *s;
register const char *spanp;
register int c, sc;
char *tok;
if ((s = *stringp) == NULL)
return (NULL);
for (tok = s;;) {
c = *s++;
spanp = delim;
do {
if ((sc = *spanp++) == c) {
if (c == 0)
s = NULL;
else
s[-1] = 0;
*stringp = s;
return (tok);
}
} while (sc != 0);
}
/* NOTREACHED */
}
static char *cut_doc[] = {
"Select portions of each line (as specified by LIST) from each FILE",
"(by default, the standard input), and write them to the standard output.",
"Items specified by LIST are either column positions or fields delimited",
"by a special character. Column numbering starts at 1.",
(char *)0
};
struct builtin cut_struct = {
"cut",
cut_builtin,
BUILTIN_ENABLED,
cut_doc,
"cut -b list [-n] [file ...] OR cut -c list [file ...] OR cut -f list [-s] [-d delim] [file ...]",
0
};
@@ -0,0 +1,95 @@
/* dirname - return directory portion of pathname */
/* See Makefile for compilation details. */
#include "config.h"
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include <stdio.h>
#include "builtins.h"
#include "shell.h"
dirname_builtin (list)
WORD_LIST *list;
{
int slen;
char *string;
if (list == 0 || list->next)
{
builtin_usage ();
return (EX_USAGE);
}
if (no_options (list))
return (EX_USAGE);
string = list->word->word;
slen = strlen (string);
/* Strip trailing slashes */
while (slen > 0 && string[slen - 1] == '/')
slen--;
/* (2) If string consists entirely of slash characters, string shall be
set to a single slash character. In this case, skip steps (3)
through (8). */
if (slen == 0)
{
fputs ("/\n", stdout);
return (EXECUTION_SUCCESS);
}
/* (3) If there are any trailing slash characters in string, they
shall be removed. */
string[slen] = '\0';
/* (4) If there are no slash characters remaining in string, string
shall be set to a single period character. In this case, skip
steps (5) through (8).
(5) If there are any trailing nonslash characters in string,
they shall be removed. */
while (--slen >= 0)
if (string[slen] == '/')
break;
if (slen < 0)
{
fputs (".\n", stdout);
return (EXECUTION_SUCCESS);
}
/* (7) If there are any trailing slash characters in string, they
shall be removed. */
while (--slen >= 0)
if (string[slen] != '/')
break;
string[++slen] = '\0';
/* (8) If the remaining string is empty, string shall be set to a single
slash character. */
printf ("%s\n", (slen == 0) ? "/" : string);
return (EXECUTION_SUCCESS);
}
char *dirname_doc[] = {
"The STRING is converted to the name of the directory containing",
"the filename corresponding to the last pathname component in STRING.",
(char *)NULL
};
/* The standard structure describing a builtin command. bash keeps an array
of these structures. */
struct builtin dirname_struct = {
"dirname", /* builtin name */
dirname_builtin, /* function implementing the builtin */
BUILTIN_ENABLED, /* initial flags for builtin */
dirname_doc, /* array of long documentation strings. */
"dirname string", /* usage synopsis */
0 /* reserved for internal use */
};
+596
View File
@@ -0,0 +1,596 @@
/*
* finfo - print file info
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <sys/types.h>
#include "posixstat.h"
#include <stdio.h>
#include <pwd.h>
#include <grp.h>
#include <errno.h>
#include "bashansi.h"
#include "shell.h"
#include "builtins.h"
#include "common.h"
#ifndef errno
extern int errno;
#endif
extern char **make_builtin_argv ();
static int printst();
static int printsome();
static int printfinfo();
static int finfo_main();
extern int sh_optind;
extern char *sh_optarg;
extern char *this_command_name;
static char *prog;
static int pmask;
#define OPT_UID 0x00001
#define OPT_GID 0x00002
#define OPT_DEV 0x00004
#define OPT_INO 0x00008
#define OPT_PERM 0x00010
#define OPT_LNKNAM 0x00020
#define OPT_FID 0x00040
#define OPT_NLINK 0x00080
#define OPT_RDEV 0x00100
#define OPT_SIZE 0x00200
#define OPT_ATIME 0x00400
#define OPT_MTIME 0x00800
#define OPT_CTIME 0x01000
#define OPT_BLKSIZE 0x02000
#define OPT_BLKS 0x04000
#define OPT_FTYPE 0x08000
#define OPT_PMASK 0x10000
#define OPT_OPERM 0x20000
#define OPT_ASCII 0x1000000
#define OPTIONS "acdgiflmnopsuACGMP:U"
static int
octal(s)
char *s;
{
int r;
r = *s - '0';
while (*++s >= '0' && *s <= '7')
r = (r * 8) + (*s - '0');
return r;
}
static int
finfo_main(argc, argv)
int argc;
char **argv;
{
register int i;
int mode, flags, opt;
sh_optind = 0; /* XXX */
prog = base_pathname(argv[0]);
if (argc == 1) {
builtin_usage();
return(1);
}
flags = 0;
while ((opt = sh_getopt(argc, argv, OPTIONS)) != EOF) {
switch(opt) {
case 'a': flags |= OPT_ATIME; break;
case 'A': flags |= OPT_ATIME|OPT_ASCII; break;
case 'c': flags |= OPT_CTIME; break;
case 'C': flags |= OPT_CTIME|OPT_ASCII; break;
case 'd': flags |= OPT_DEV; break;
case 'i': flags |= OPT_INO; break;
case 'f': flags |= OPT_FID; break;
case 'g': flags |= OPT_GID; break;
case 'G': flags |= OPT_GID|OPT_ASCII; break;
case 'l': flags |= OPT_LNKNAM; break;
case 'm': flags |= OPT_MTIME; break;
case 'M': flags |= OPT_MTIME|OPT_ASCII; break;
case 'n': flags |= OPT_NLINK; break;
case 'o': flags |= OPT_OPERM; break;
case 'p': flags |= OPT_PERM; break;
case 'P': flags |= OPT_PMASK; pmask = octal(sh_optarg); break;
case 's': flags |= OPT_SIZE; break;
case 'u': flags |= OPT_UID; break;
case 'U': flags |= OPT_UID|OPT_ASCII; break;
default: builtin_usage (); return(1);
}
}
argc -= sh_optind;
argv += sh_optind;
if (argc == 0) {
builtin_usage();
return(1);
}
for (i = 0; i < argc; i++)
opt = flags ? printsome (argv[i], flags) : printfinfo(argv[i]);
return(opt);
}
static struct stat *
getstat(f)
char *f;
{
static struct stat st;
int fd, r;
intmax_t lfd;
if (strncmp(f, "/dev/fd/", 8) == 0) {
if ((legal_number(f + 8, &lfd) == 0) || (int)lfd != lfd) {
builtin_error("%s: invalid fd", f + 8);
return ((struct stat *)0);
}
fd = lfd;
r = fstat(fd, &st);
} else
#ifdef HAVE_LSTAT
r = lstat(f, &st);
#else
r = stat(f, &st);
#endif
if (r < 0) {
builtin_error("%s: cannot stat: %s", f, strerror(errno));
return ((struct stat *)0);
}
return (&st);
}
static int
printfinfo(f)
char *f;
{
struct stat *st;
st = getstat(f);
return (st ? printst(st) : 1);
}
static int
getperm(m)
int m;
{
return (m & (S_IRWXU|S_IRWXG|S_IRWXO|S_ISUID|S_ISGID));
}
static int
perms(m)
int m;
{
char ubits[4], gbits[4], obits[4]; /* u=rwx,g=rwx,o=rwx */
int i;
i = 0;
if (m & S_IRUSR)
ubits[i++] = 'r';
if (m & S_IWUSR)
ubits[i++] = 'w';
if (m & S_IXUSR)
ubits[i++] = 'x';
ubits[i] = '\0';
i = 0;
if (m & S_IRGRP)
gbits[i++] = 'r';
if (m & S_IWGRP)
gbits[i++] = 'w';
if (m & S_IXGRP)
gbits[i++] = 'x';
gbits[i] = '\0';
i = 0;
if (m & S_IROTH)
obits[i++] = 'r';
if (m & S_IWOTH)
obits[i++] = 'w';
if (m & S_IXOTH)
obits[i++] = 'x';
obits[i] = '\0';
if (m & S_ISUID)
ubits[2] = (m & S_IXUSR) ? 's' : 'S';
if (m & S_ISGID)
gbits[2] = (m & S_IXGRP) ? 's' : 'S';
if (m & S_ISVTX)
obits[2] = (m & S_IXOTH) ? 't' : 'T';
printf ("u=%s,g=%s,o=%s", ubits, gbits, obits);
}
static int
printmode(mode)
int mode;
{
if (S_ISBLK(mode))
printf("S_IFBLK ");
if (S_ISCHR(mode))
printf("S_IFCHR ");
if (S_ISDIR(mode))
printf("S_IFDIR ");
if (S_ISREG(mode))
printf("S_IFREG ");
if (S_ISFIFO(mode))
printf("S_IFIFO ");
if (S_ISLNK(mode))
printf("S_IFLNK ");
if (S_ISSOCK(mode))
printf("S_IFSOCK ");
#ifdef S_ISWHT
if (S_ISWHT(mode))
printf("S_ISWHT ");
#endif
perms(getperm(mode));
printf("\n");
}
static int
printst(st)
struct stat *st;
{
struct passwd *pw;
struct group *gr;
char *owner;
int ma, mi, d;
ma = major (st->st_rdev);
mi = minor (st->st_rdev);
#if defined (makedev)
d = makedev (ma, mi);
#else
d = st->st_rdev & 0xFF;
#endif
printf("Device (major/minor): %d (%d/%d)\n", d, ma, mi);
printf("Inode: %d\n", (int) st->st_ino);
printf("Mode: (%o) ", (int) st->st_mode);
printmode((int) st->st_mode);
printf("Link count: %d\n", (int) st->st_nlink);
pw = getpwuid(st->st_uid);
owner = pw ? pw->pw_name : "unknown";
printf("Uid of owner: %d (%s)\n", (int) st->st_uid, owner);
gr = getgrgid(st->st_gid);
owner = gr ? gr->gr_name : "unknown";
printf("Gid of owner: %d (%s)\n", (int) st->st_gid, owner);
printf("Device type: %d\n", (int) st->st_rdev);
printf("File size: %ld\n", (long) st->st_size);
printf("File last access time: %s", ctime (&st->st_atime));
printf("File last modify time: %s", ctime (&st->st_mtime));
printf("File last status change time: %s", ctime (&st->st_ctime));
fflush(stdout);
return(0);
}
static int
printsome(f, flags)
char *f;
int flags;
{
struct stat *st;
struct passwd *pw;
struct group *gr;
int p;
char *b;
st = getstat(f);
if (st == NULL)
return (1);
/* Print requested info */
if (flags & OPT_ATIME) {
if (flags & OPT_ASCII)
printf("%s", ctime(&st->st_atime));
else
printf("%ld\n", st->st_atime);
} else if (flags & OPT_MTIME) {
if (flags & OPT_ASCII)
printf("%s", ctime(&st->st_mtime));
else
printf("%ld\n", st->st_mtime);
} else if (flags & OPT_CTIME) {
if (flags & OPT_ASCII)
printf("%s", ctime(&st->st_ctime));
else
printf("%ld\n", st->st_ctime);
} else if (flags & OPT_DEV)
printf("%d\n", st->st_dev);
else if (flags & OPT_INO)
printf("%d\n", st->st_ino);
else if (flags & OPT_FID)
printf("%d:%ld\n", st->st_dev, st->st_ino);
else if (flags & OPT_NLINK)
printf("%d\n", st->st_nlink);
else if (flags & OPT_LNKNAM) {
#ifdef S_ISLNK
b = xmalloc(4096);
p = readlink(f, b, 4096);
if (p >= 0 && p < 4096)
b[p] = '\0';
else {
p = errno;
strcpy(b, prog);
strcat(b, ": ");
strcat(b, strerror(p));
}
printf("%s\n", b);
free(b);
#else
printf("%s\n", f);
#endif
} else if (flags & OPT_PERM) {
perms(st->st_mode);
printf("\n");
} else if (flags & OPT_OPERM)
printf("%o\n", getperm(st->st_mode));
else if (flags & OPT_PMASK)
printf("%o\n", getperm(st->st_mode) & pmask);
else if (flags & OPT_UID) {
pw = getpwuid(st->st_uid);
if (flags & OPT_ASCII)
printf("%s\n", pw ? pw->pw_name : "unknown");
else
printf("%d\n", st->st_uid);
} else if (flags & OPT_GID) {
gr = getgrgid(st->st_gid);
if (flags & OPT_ASCII)
printf("%s\n", gr ? gr->gr_name : "unknown");
else
printf("%d\n", st->st_gid);
} else if (flags & OPT_SIZE)
printf("%ld\n", st->st_size);
return (0);
}
#ifndef NOBUILTIN
int
finfo_builtin(list)
WORD_LIST *list;
{
int c, r;
char **v;
WORD_LIST *l;
v = make_builtin_argv (list, &c);
r = finfo_main (c, v);
free (v);
return r;
}
static char *finfo_doc[] = {
"Display information about each FILE. Only single operators should",
"be supplied. If no options are supplied, a summary of the info",
"available about each FILE is printed. If FILE is of the form",
"/dev/fd/XX, file descriptor XX is described. Operators, if supplied,",
"have the following meanings:",
"",
" -a last file access time",
" -A last file access time in ctime format",
" -c last file status change time",
" -C last file status change time in ctime format",
" -m last file modification time",
" -M last file modification time in ctime format",
" -d device",
" -i inode",
" -f composite file identifier (device:inode)",
" -g gid of owner",
" -G group name of owner",
" -l name of file pointed to by symlink",
" -n link count",
" -o permissions in octal",
" -p permissions in ascii",
" -P mask permissions ANDed with MASK (like with umask)",
" -s file size in bytes",
" -u uid of owner",
" -U user name of owner",
(char *)0
};
struct builtin finfo_struct = {
"finfo",
finfo_builtin,
BUILTIN_ENABLED,
finfo_doc,
"finfo [-acdgiflmnopsuACGMPU] file [file...]",
0
};
#endif
#ifdef NOBUILTIN
#if defined (PREFER_STDARG)
# include <stdarg.h>
#else
# if defined (PREFER_VARARGS)
# include <varargs.h>
# endif
#endif
char *this_command_name;
main(argc, argv)
int argc;
char **argv;
{
this_command_name = argv[0];
exit(finfo_main(argc, argv));
}
void
builtin_usage()
{
fprintf(stderr, "%s: usage: %s [-%s] [file ...]\n", prog, OPTIONS);
}
#ifndef HAVE_STRERROR
char *
strerror(e)
int e;
{
static char ebuf[40];
extern int sys_nerr;
extern char *sys_errlist[];
if (e < 0 || e > sys_nerr) {
sprintf(ebuf,"Unknown error code %d", e);
return (&ebuf[0]);
}
return (sys_errlist[e]);
}
#endif
char *
xmalloc(s)
size_t s;
{
char *ret;
extern char *malloc();
ret = malloc(s);
if (ret)
return (ret);
fprintf(stderr, "%s: cannot malloc %d bytes\n", prog, s);
exit(1);
}
char *
base_pathname(p)
char *p;
{
char *t;
if (t = strrchr(p, '/'))
return(++t);
return(p);
}
int
legal_number (string, result)
char *string;
long *result;
{
int sign;
long value;
sign = 1;
value = 0;
if (result)
*result = 0;
/* Skip leading whitespace characters. */
while (whitespace (*string))
string++;
if (!*string)
return (0);
/* We allow leading `-' or `+'. */
if (*string == '-' || *string == '+')
{
if (!digit (string[1]))
return (0);
if (*string == '-')
sign = -1;
string++;
}
while (digit (*string))
{
if (result)
value = (value * 10) + digit_value (*string);
string++;
}
/* Skip trailing whitespace, if any. */
while (whitespace (*string))
string++;
/* Error if not at end of string. */
if (*string)
return (0);
if (result)
*result = value * sign;
return (1);
}
int sh_optind;
char *sh_optarg;
int sh_opterr;
extern int optind;
extern char *optarg;
int
sh_getopt(c, v, o)
int c;
char **v, *o;
{
int r;
r = getopt(c, v, o);
sh_optind = optind;
sh_optarg = optarg;
return r;
}
#if defined (USE_VARARGS)
void
#if defined (PREFER_STDARG)
builtin_error (const char *format, ...)
#else
builtin_error (format, va_alist)
const char *format;
va_dcl
#endif
{
va_list args;
if (this_command_name && *this_command_name)
fprintf (stderr, "%s: ", this_command_name);
#if defined (PREFER_STDARG)
va_start (args, format);
#else
va_start (args);
#endif
vfprintf (stderr, format, args);
va_end (args);
fprintf (stderr, "\n");
}
#else
void
builtin_error (format, arg1, arg2, arg3, arg4, arg5)
char *format, *arg1, *arg2, *arg3, *arg4, *arg5;
{
if (this_command_name && *this_command_name)
fprintf (stderr, "%s: ", this_command_name);
fprintf (stderr, format, arg1, arg2, arg3, arg4, arg5);
fprintf (stderr, "\n");
fflush (stderr);
}
#endif /* !USE_VARARGS */
#endif
File diff suppressed because it is too large Load Diff
+214
View File
@@ -0,0 +1,214 @@
/* getconf.h -- replacement definitions for ones the system doesn't provide. */
#ifndef _GETCONF_H
#define _GETCONF_H
/* Some systems do not define these; use POSIX.2 minimum recommended values. */
#ifndef _POSIX2_COLL_WEIGHTS_MAX
# define _POSIX2_COLL_WEIGHTS_MAX 2
#endif
/* If we're on a posix system, but the system doesn't define the necessary
constants, use posix.1 minimum values. */
#if defined (_POSIX_VERSION)
#ifndef _POSIX_ARG_MAX
# define _POSIX_ARG_MAX 4096
#endif
#ifndef _POSIX_CHILD_MAX
# define _POSIX_CHILD_MAX 6
#endif
#ifndef _POSIX_LINK_MAX
# define _POSIX_LINK_MAX 8
#endif
#ifndef _POSIX_MAX_CANON
# define _POSIX_MAX_CANON 255
#endif
#ifndef _POSIX_MAX_INPUT
# define _POSIX_MAX_INPUT 255
#endif
#ifndef _POSIX_NAME_MAX
# define _POSIX_NAME_MAX 14
#endif
#ifndef _POSIX_NGROUPS_MAX
# define _POSIX_NGROUPS_MAX 0
#endif
#ifndef _POSIX_OPEN_MAX
# define _POSIX_OPEN_MAX 16
#endif
#ifndef _POSIX_PATH_MAX
# define _POSIX_PATH_MAX 255
#endif
#ifndef _POSIX_PIPE_BUF
# define _POSIX_PIPE_BUF 512
#endif
#ifndef _POSIX_SSIZE_MAX
# define _POSIX_SSIZE_MAX 32767
#endif
#ifndef _POSIX_STREAM_MAX
# define _POSIX_STREAM_MAX 8
#endif
#ifndef _POSIX_TZNAME_MAX
# define _POSIX_TZNAME_MAX 3
#endif
#ifndef _POSIX2_BC_BASE_MAX
# define _POSIX2_BC_BASE_MAX 99
#endif
#ifndef _POSIX2_BC_DIM_MAX
# define _POSIX2_BC_DIM_MAX 2048
#endif
#ifndef _POSIX2_BC_SCALE_MAX
# define _POSIX2_BC_SCALE_MAX 99
#endif
#ifndef _POSIX2_BC_STRING_MAX
# define _POSIX2_BC_STRING_MAX 1000
#endif
#ifndef _POSIX2_EQUIV_CLASS_MAX
# define _POSIX2_EQUIV_CLASS_MAX 2
#endif
#ifndef _POSIX2_EXPR_NEST_MAX
# define _POSIX2_EXPR_NEST_MAX 32
#endif
#ifndef _POSIX2_LINE_MAX
# define _POSIX2_LINE_MAX 2048
#endif
#ifndef _POSIX2_RE_DUP_MAX
# define _POSIX2_RE_DUP_MAX 255
#endif
/* configurable system variables */
#if !defined (HAVE_SYSCONF)
#ifndef _SC_ARG_MAX
# define _SC_ARG_MAX 1
# define _SC_CHILD_MAX 2
# define _SC_CLK_TCK 3
# define _SC_NGROUPS_MAX 4
# define _SC_OPEN_MAX 5
# define _SC_JOB_CONTROL 6
# define _SC_SAVED_IDS 7
# define _SC_VERSION 8
# define _SC_BC_BASE_MAX 9
# define _SC_BC_DIM_MAX 10
# define _SC_BC_SCALE_MAX 11
# define _SC_BC_STRING_MAX 12
# define _SC_COLL_WEIGHTS_MAX 13
# define _SC_EXPR_NEST_MAX 14
# define _SC_LINE_MAX 15
# define _SC_RE_DUP_MAX 16
#if 0
# define _SC_2_VERSION 17
# define _SC_2_C_BIND 18
# define _SC_2_C_DEV 19
# define _SC_2_CHAR_TERM 20
# define _SC_2_FORT_DEV 21
# define _SC_2_FORT_RUN 22
# define _SC_2_LOCALEDEF 23
# define _SC_2_SW_DEV 24
# define _SC_2_UPE 25
#endif /* 0 */
# define _SC_STREAM_MAX 26
# define _SC_TZNAME_MAX 27
#endif /* !_SC_ARG_MAX */
#endif /* !HAVE_SYSCONF */
/* configurable pathname variables */
#if !defined (HAVE_PATHCONF)
#ifndef _PC_LINK_MAX
#define _PC_LINK_MAX 1
#define _PC_MAX_CANON 2
#define _PC_MAX_INPUT 3
#define _PC_NAME_MAX 4
#define _PC_PATH_MAX 5
#define _PC_PIPE_BUF 6
#define _PC_CHOWN_RESTRICTED 7
#define _PC_NO_TRUNC 8
#define _PC_VDISABLE 9
#endif /* !_PC_LINK_MAX */
#endif /* !HAVE_PATHCONF */
#endif /* _POSIX_VERSION */
#ifndef _CS_PATH
# define _CS_PATH 1
#endif
/* ANSI/ISO C, POSIX.1-200x, XPG 4.2 (and later) C language type limits.
Defined only if the system include files don't. Assume a 32-bit
environment with signed 8-bit characters. */
#ifndef CHAR_BIT
# define CHAR_BIT 8
#endif
#ifndef CHAR_MAX
# define CHAR_MAX 127
#endif
#ifndef CHAR_MIN
# define CHAR_MIN -128
#endif
#ifndef INT_BIT
# define INT_BIT (sizeof (int) * CHAR_BIT)
#endif
#ifndef INT_MAX
# define INT_MAX 2147483647
#endif
#ifndef INT_MIN
# define INT_MIN (-2147483647-1)
#endif
#ifndef LONG_BIT
# define LONG_BIT (sizeof (long int) * CHAR_BIT)
#endif
#ifndef LONG_MAX
# define LONG_MAX 2147483647L
#endif
#ifndef LONG_MIN
# define LONG_MIN (-2147483647L-1L)
#endif
#ifndef SCHAR_MAX
# define SCHAR_MAX CHAR_MAX
#endif
#ifndef SCHAR_MIN
# define SCHAR_MIN CHAR_MIN
#endif
#ifndef SHRT_MAX
# define SHRT_MAX 32767
#endif
#ifndef SHRT_MIN
# define SHRT_MIN (-32768)
#endif
#ifndef UCHAR_MAX
# define UCHAR_MAX 255
#endif
#ifndef UINT_MAX
# define UINT_MAX 4294967295U
#endif
#ifndef ULONG_MAX
# define ULONG_MAX 4294967295UL
#endif
#ifndef USHRT_MAX
# define UCHAR_MAX 65535
#endif
/* assume size_t is `unsigned int'; ssize_t is `int' */
#ifndef SIZE_MAX
# define SIZE_MAX UINT_MAX
#endif
#ifndef SSIZE_MAX
# define SSIZE_MAX INT_MAX
#endif
#ifndef WORD_BIT
# define WORD_BIT (sizeof (int) * CHAR_BIT)
#endif
#endif /* _GETCONF_H */
+143
View File
@@ -0,0 +1,143 @@
/* head - copy first part of files. */
/* See Makefile for compilation details. */
#include "config.h"
#include "bashtypes.h"
#include "posixstat.h"
#include "filecntl.h"
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include "bashansi.h"
#include <stdio.h>
#include <errno.h>
#include "chartypes.h"
#include "builtins.h"
#include "shell.h"
#include "bashgetopt.h"
#if !defined (errno)
extern int errno;
#endif
static void
munge_list (list)
WORD_LIST *list;
{
WORD_LIST *l, *nl;
WORD_DESC *wd;
char *arg;
for (l = list; l; l = l->next)
{
arg = l->word->word;
if (arg[0] != '-' || arg[1] == '-' || (DIGIT(arg[1]) == 0))
return;
/* We have -[0-9]* */
wd = make_bare_word (arg+1);
nl = make_word_list (wd, l->next);
l->word->word[1] = 'n';
l->word->word[2] = '\0';
l->next = nl;
l = nl; /* skip over new argument */
}
}
static int
file_head (fp, cnt)
FILE *fp;
int cnt;
{
int ch;
while (cnt--)
{
while ((ch = getc (fp)) != EOF)
{
if (putchar (ch) == EOF)
{
builtin_error ("write error: %s", strerror (errno));
return EXECUTION_FAILURE;
}
if (ch == '\n')
break;
}
}
}
head_builtin (list)
WORD_LIST *list;
{
int nline, opt, rval;
WORD_LIST *l;
FILE *fp;
char *t;
munge_list (list); /* change -num into -n num */
reset_internal_getopt ();
nline = 10;
while ((opt = internal_getopt (list, "n:")) != -1)
{
switch (opt)
{
case 'n':
nline = atoi (list_optarg);
if (nline <= 0)
{
builtin_error ("bad line count: %s", list_optarg);
return (EX_USAGE);
}
break;
default:
builtin_usage ();
return (EX_USAGE);
}
}
list = loptend;
if (list == 0)
return (file_head (stdin, nline));
for (rval = EXECUTION_SUCCESS, opt = 1, l = list; l; l = l->next)
{
fp = fopen (l->word->word, "r");
if (fp == NULL)
{
builtin_error ("%s: %s", l->word->word, strerror (errno));
continue;
}
if (list->next) /* more than one file */
{
printf ("%s==> %s <==\n", opt ? "" : "\n", l->word->word);
opt = 0;
}
rval = file_head (fp, nline);
fclose (fp);
}
return (rval);
}
char *head_doc[] = {
"Copy the first N lines from the input files to the standard output.",
"N is supplied as an argument to the `-n' option. If N is not given,",
"the first ten lines are copied.",
(char *)NULL
};
struct builtin head_struct = {
"head", /* builtin name */
head_builtin, /* function implementing the builtin */
BUILTIN_ENABLED, /* initial flags for builtin */
head_doc, /* array of long documentation strings. */
"head [-n num] [file ...]", /* usage synopsis; becomes short_doc */
0 /* reserved for internal use */
};
+61
View File
@@ -0,0 +1,61 @@
/* Sample builtin to be dynamically loaded with enable -f and create a new
builtin. */
/* See Makefile for compilation details. */
#include <config.h>
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include <stdio.h>
#include "builtins.h"
#include "shell.h"
#include "bashgetopt.h"
/* A builtin `xxx' is normally implemented with an `xxx_builtin' function.
If you're converting a command that uses the normal Unix argc/argv
calling convention, use argv = make_builtin_argv (list, &argc) and call
the original `main' something like `xxx_main'. Look at cat.c for an
example.
Builtins should use internal_getopt to parse options. It is the same as
getopt(3), but it takes a WORD_LIST *. Look at print.c for an example
of its use.
If the builtin takes no options, call no_options(list) before doing
anything else. If it returns a non-zero value, your builtin should
immediately return EX_USAGE. Look at logname.c for an example.
A builtin command returns EXECUTION_SUCCESS for success and
EXECUTION_FAILURE to indicate failure. */
int
hello_builtin (list)
WORD_LIST *list;
{
printf("hello world\n");
fflush (stdout);
return (EXECUTION_SUCCESS);
}
/* An array of strings forming the `long' documentation for a builtin xxx,
which is printed by `help xxx'. It must end with a NULL. */
char *hello_doc[] = {
"this is the long doc for the sample hello builtin",
(char *)NULL
};
/* The standard structure describing a builtin command. bash keeps an array
of these structures. The flags must include BUILTIN_ENABLED so the
builtin can be used. */
struct builtin hello_struct = {
"hello", /* builtin name */
hello_builtin, /* function implementing the builtin */
BUILTIN_ENABLED, /* initial flags for builtin */
hello_doc, /* array of long documentation strings. */
"hello", /* usage synopsis; becomes short_doc */
0 /* reserved for internal use */
};
+308
View File
@@ -0,0 +1,308 @@
/*
* id - POSIX.2 user identity
*
* (INCOMPLETE -- supplementary groups for other users not yet done)
*
* usage: id [-Ggu] [-nr] [user]
*
* The default output format looks something like:
* uid=xxx(chet) gid=xx groups=aa(aname), bb(bname), cc(cname)
*/
#include <config.h>
#include <stdio.h>
#include "bashtypes.h"
#include <pwd.h>
#include <grp.h>
#include "bashansi.h"
#ifdef HAVE_LIMITS_H
# include <limits.h>
#else
# include <sys/param.h>
#endif
#if !defined (HAVE_GETPW_DECLS)
extern struct passwd *getpwuid ();
#endif
extern struct group *getgrgid ();
#include "shell.h"
#include "builtins.h"
#include "stdc.h"
#include "common.h"
#include "bashgetopt.h"
#define ID_ALLGROUPS 0x001 /* -G */
#define ID_GIDONLY 0x002 /* -g */
#define ID_USENAME 0x004 /* -n */
#define ID_USEREAL 0x008 /* -r */
#define ID_USERONLY 0x010 /* -u */
#define ID_FLAGSET(s) ((id_flags & (s)) != 0)
static int id_flags;
static uid_t ruid, euid;
static gid_t rgid, egid;
static char *id_user;
static int inituser ();
static int id_pruser ();
static int id_prgrp ();
static int id_prgroups ();
static int id_prall ();
int
id_builtin (list)
WORD_LIST *list;
{
int opt;
char *user;
id_flags = 0;
reset_internal_getopt ();
while ((opt = internal_getopt (list, "Ggnru")) != -1)
{
switch (opt)
{
case 'G': id_flags |= ID_ALLGROUPS; break;
case 'g': id_flags |= ID_GIDONLY; break;
case 'n': id_flags |= ID_USENAME; break;
case 'r': id_flags |= ID_USEREAL; break;
case 'u': id_flags |= ID_USERONLY; break;
default:
builtin_usage ();
return (EX_USAGE);
}
}
list = loptend;
user = list ? list->word->word : (char *)NULL;
/* Check for some invalid option combinations */
opt = ID_FLAGSET (ID_ALLGROUPS) + ID_FLAGSET (ID_GIDONLY) + ID_FLAGSET (ID_USERONLY);
if (opt > 1 || (opt == 0 && ((id_flags & (ID_USEREAL|ID_USENAME)) != 0)))
{
builtin_usage ();
return (EX_USAGE);
}
if (list && list->next)
{
builtin_usage ();
return (EX_USAGE);
}
if (inituser (user) < 0)
return (EXECUTION_FAILURE);
opt = 0;
if (id_flags & ID_USERONLY)
opt += id_pruser ((id_flags & ID_USEREAL) ? ruid : euid);
else if (id_flags & ID_GIDONLY)
opt += id_prgrp ((id_flags & ID_USEREAL) ? rgid : egid);
else if (id_flags & ID_ALLGROUPS)
opt += id_prgroups (user);
else
opt += id_prall (user);
putchar ('\n');
fflush (stdout);
return (opt == 0 ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
}
static int
inituser (uname)
char *uname;
{
struct passwd *pwd;
if (uname)
{
pwd = getpwnam (uname);
if (pwd == 0)
{
builtin_error ("%s: no such user", uname);
return -1;
}
ruid = euid = pwd->pw_uid;
rgid = egid = pwd->pw_gid;
}
else
{
ruid = current_user.uid;
euid = current_user.euid;
rgid = current_user.gid;
egid = current_user.egid;
}
return 0;
}
/* Print the name or value of user ID UID. */
static int
id_pruser (uid)
int uid;
{
struct passwd *pwd = NULL;
int r;
r = 0;
if (id_flags & ID_USENAME)
{
pwd = getpwuid (uid);
if (pwd == NULL)
r = 1;
}
if (pwd)
printf ("%s", pwd->pw_name);
else
printf ("%u", (unsigned) uid);
return r;
}
/* Print the name or value of group ID GID. */
static int
id_prgrp (gid)
int gid;
{
struct group *grp = NULL;
int r;
r = 0;
if (id_flags & ID_USENAME)
{
grp = getgrgid (gid);
if (grp == NULL)
r = 1;
}
if (grp)
printf ("%s", grp->gr_name);
else
printf ("%u", (unsigned) gid);
return r;
}
static int
id_prgroups (uname)
char *uname;
{
int *glist, ng, i, r;
r = 0;
id_prgrp (rgid);
if (egid != rgid)
{
putchar (' ');
id_prgrp (egid);
}
if (uname)
{
builtin_error ("supplementary groups for other users not yet implemented");
glist = (int *)NULL;
ng = 0;
r = 1;
}
else
glist = get_group_array (&ng);
for (i = 0; i < ng; i++)
if (glist[i] != rgid && glist[i] != egid)
{
putchar (' ');
id_prgrp (glist[i]);
}
return r;
}
static int
id_prall (uname)
char *uname;
{
int r, i, ng, *glist;
struct passwd *pwd;
struct group *grp;
r = 0;
printf ("uid=%u", (unsigned) ruid);
pwd = getpwuid (ruid);
if (pwd == NULL)
r = 1;
else
printf ("(%s)", pwd->pw_name);
printf (" gid=%u", (unsigned) rgid);
grp = getgrgid (rgid);
if (grp == NULL)
r = 1;
else
printf ("(%s)", grp->gr_name);
if (euid != ruid)
{
printf (" euid=%u", (unsigned) euid);
pwd = getpwuid (euid);
if (pwd == NULL)
r = 1;
else
printf ("(%s)", pwd->pw_name);
}
if (egid != rgid)
{
printf (" egid=%u", (unsigned) egid);
grp = getgrgid (egid);
if (grp == NULL)
r = 1;
else
printf ("(%s)", grp->gr_name);
}
if (uname)
{
builtin_error ("supplementary groups for other users not yet implemented");
glist = (int *)NULL;
ng = 0;
r = 1;
}
else
glist = get_group_array (&ng);
if (ng > 0)
printf (" groups=");
for (i = 0; i < ng; i++)
{
if (i > 0)
printf (", ");
printf ("%u", (unsigned) glist[i]);
grp = getgrgid (glist[i]);
if (grp == NULL)
r = 1;
else
printf ("(%s)", grp->gr_name);
}
return r;
}
char *id_doc[] = {
"return information about user identity",
(char *)NULL
};
struct builtin id_struct = {
"id",
id_builtin,
BUILTIN_ENABLED,
id_doc,
"id [user]\n\tid -G [-n] [user]\n\tid -g [-nr] [user]\n\tid -u [-nr] [user]",
0
};
+205
View File
@@ -0,0 +1,205 @@
/* ln - make links */
/* See Makefile for compilation details. */
#include "config.h"
#include "bashtypes.h"
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include "posixstat.h"
#include <stdio.h>
#include <errno.h>
#include "builtins.h"
#include "shell.h"
#include "bashgetopt.h"
#if !defined (errno)
extern int errno;
#endif
typedef int unix_link_syscall_t __P((const char *, const char *));
#define LN_SYMLINK 0x01
#define LN_UNLINK 0x02
static unix_link_syscall_t *linkfn;
static int dolink ();
ln_builtin (list)
WORD_LIST *list;
{
int rval, opt, flags;
WORD_LIST *l;
char *sdir;
struct stat sb;
flags = 0;
reset_internal_getopt ();
while ((opt = internal_getopt (list, "fs")) != -1)
{
switch (opt)
{
case 'f':
flags |= LN_UNLINK;
break;
case 's':
flags |= LN_SYMLINK;
break;
default:
builtin_usage ();
return (EX_USAGE);
}
}
list = loptend;
if (list == 0)
{
builtin_usage ();
return (EX_USAGE);
}
linkfn = (flags & LN_SYMLINK) ? symlink : link;
if (list->next == 0) /* ln target, equivalent to ln target . */
return (dolink (list->word->word, ".", flags));
if (list->next->next == 0) /* ln target source */
return (dolink (list->word->word, list->next->word->word, flags));
/* ln target1 target2 ... directory */
/* find last argument: target directory, and make sure it's an existing
directory. */
for (l = list; l->next; l = l->next)
;
sdir = l->word->word;
if (stat(sdir, &sb) < 0)
{
builtin_error ("%s", sdir);
return (EXECUTION_FAILURE);
}
if (S_ISDIR (sb.st_mode) == 0)
{
builtin_usage ();
return (EX_USAGE);
}
for (rval = EXECUTION_SUCCESS; list != l; list = list->next)
rval += dolink (list->word->word, sdir, flags);
return rval;
}
static char *
mkdirpath (dir, file)
char *dir, *file;
{
int dlen, flen;
char *ret;
dlen = strlen (dir);
flen = strlen (file);
ret = xmalloc (2 + dlen + flen);
strcpy (ret, dir);
if (ret[dlen - 1] != '/')
ret[dlen++] = '/';
strcpy (ret + dlen, file);
return ret;
}
#if defined (HAVE_LSTAT)
# define LSTAT lstat
#else
# define LSTAT stat
#endif
static int
dolink (src, dst, flags)
char *src, *dst;
int flags;
{
struct stat ssb, dsb;
int exists;
char *dst_path, *p;
/* If we're not doing symlinks, the source must exist and not be a
directory. */
if ((flags & LN_SYMLINK) == 0)
{
if (stat (src, &ssb) != 0)
{
builtin_error ("%s: %s", src, strerror (errno));
return (EXECUTION_FAILURE);
}
if (S_ISDIR (ssb.st_mode))
{
errno = EISDIR;
builtin_error ("%s: %s", src, strerror (errno));
return (EXECUTION_FAILURE);
}
}
/* If the destination is a directory, create the final filename by appending
the basename of the source to the destination. */
dst_path = 0;
if ((stat (dst, &dsb) == 0) && S_ISDIR (dsb.st_mode))
{
if ((p = strrchr (src, '/')) == 0)
p = src;
else
p++;
dst_path = mkdirpath (dst, p);
dst = dst_path;
}
exists = LSTAT (dst, &dsb) == 0;
/* If -f was specified, and the destination exists, unlink it. */
if ((flags & LN_UNLINK) && exists && unlink (dst) != 0)
{
builtin_error ("%s: cannot unlink: %s", dst, strerror (errno));
FREE (dst_path);
return (EXECUTION_FAILURE);
}
/* Perform the link. */
if ((*linkfn) (src, dst) != 0)
{
builtin_error ("cannot link %s to %s: %s", dst, src, strerror (errno));
FREE (dst_path);
return (EXECUTION_FAILURE);
}
FREE (dst_path);
return (EXECUTION_SUCCESS);
}
char *ln_doc[] = {
"Create a new directory entry with the same modes as the original",
"file. The -f option means to unlink any existing file, permitting",
"the link to occur. The -s option means to create a symbolic link.",
"By default, ln makes hard links.",
(char *)NULL
};
/* The standard structure describing a builtin command. bash keeps an array
of these structures. */
struct builtin ln_struct = {
"ln", /* builtin name */
ln_builtin, /* function implementing the builtin */
BUILTIN_ENABLED, /* initial flags for builtin */
ln_doc, /* array of long documentation strings. */
"ln [-fs] file1 [file2] OR ln [-fs] file ... directory", /* usage synopsis; becomes short_doc */
0 /* reserved for internal use */
};
@@ -0,0 +1,52 @@
/* logname - print login name of current user */
#include <config.h>
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include <stdio.h>
#include <errno.h>
#include "builtins.h"
#include "shell.h"
#if !defined (errno)
extern int errno;
#endif
logname_builtin (list)
WORD_LIST *list;
{
char *np;
if (no_options (list))
return (EX_USAGE);
np = getlogin ();
if (np == 0)
{
builtin_error ("cannot find username: %s", strerror (errno));
return (EXECUTION_FAILURE);
}
printf ("%s\n", np);
return (EXECUTION_SUCCESS);
}
char *logname_doc[] = {
"write the current user's login name to the standard output",
"and exit. logname ignores the LOGNAME and USER variables.",
"logname ignores any non-option arguments.",
(char *)NULL
};
struct builtin logname_struct = {
"logname",
logname_builtin,
BUILTIN_ENABLED,
logname_doc,
"logname",
0
};
+216
View File
@@ -0,0 +1,216 @@
/* mkdir - make directories */
/* See Makefile for compilation details. */
#include <config.h>
#include "bashtypes.h"
#include "posixstat.h"
#include <errno.h>
#include <stdio.h>
#include "bashansi.h"
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include "builtins.h"
#include "shell.h"
#include "bashgetopt.h"
#if !defined (errno)
extern int errno;
#endif
#define ISOCTAL(c) ((c) >= '0' && (c) <= '7')
extern int parse_symbolic_mode ();
static int make_path ();
static int original_umask;
int
mkdir_builtin (list)
WORD_LIST *list;
{
int opt, pflag, omode, rval, octal, nmode, parent_mode, um;
char *mode;
WORD_LIST *l;
reset_internal_getopt ();
pflag = 0;
mode = (char *)NULL;
while ((opt = internal_getopt(list, "m:p")) != -1)
switch (opt)
{
case 'p':
pflag = 1;
break;
case 'm':
mode = list_optarg;
break;
default:
builtin_usage();
return (EX_USAGE);
}
list = loptend;
if (list == 0)
{
builtin_usage ();
return (EX_USAGE);
}
if (mode == NULL)
omode = S_IRWXU | S_IRWXG | S_IRWXO; /* a=rwx */
else if (ISOCTAL (*mode)) /* octal number */
{
omode = read_octal (mode);
if (omode < 0)
{
builtin_error ("invalid file mode: %s", mode);
return (EXECUTION_FAILURE);
}
octal = 1;
}
else if (mode)
{
/* initial bits are a=rwx; the mode argument modifies them */
omode = parse_symbolic_mode (mode, S_IRWXU | S_IRWXG | S_IRWXO);
if (omode < 0)
{
builtin_error ("invalid file mode: %s", mode);
return (EXECUTION_FAILURE);
}
octal = 0;
}
/* Make the new mode */
original_umask = umask (0);
umask (original_umask);
nmode = (S_IRWXU | S_IRWXG | S_IRWXO) & ~original_umask;
parent_mode = nmode | (S_IWRITE|S_IEXEC); /* u+wx */
/* Adjust new mode based on mode argument */
nmode &= omode;
for (rval = EXECUTION_SUCCESS, l = list; l; l = l->next)
{
if (pflag && make_path (l->word->word, nmode, parent_mode))
{
rval = EXECUTION_FAILURE;
continue;
}
else if (pflag == 0 && mkdir (l->word->word, nmode) < 0)
{
builtin_error ("cannot create directory `%s': %s", l->word->word, strerror (errno));
rval = EXECUTION_FAILURE;
}
}
return rval;
}
/* Make all the directories leading up to PATH, then create PATH. Note that
this changes the process's umask; make sure that all paths leading to a
return reset it to ORIGINAL_UMASK */
static int
make_path (path, nmode, parent_mode)
char *path;
int nmode, parent_mode;
{
int oumask;
struct stat sb;
char *p, *npath;
if (stat (path, &sb) == 0)
{
if (S_ISDIR (sb.st_mode) == 0)
{
builtin_error ("`%s': file exists but is not a directory", path);
return 1;
}
if (chmod (path, nmode))
{
builtin_error ("%s: %s", path, strerror (errno));
return 1;
}
return 0;
}
oumask = umask (0);
npath = savestring (path); /* So we can write to it. */
/* Check whether or not we need to do anything with intermediate dirs. */
/* Skip leading slashes. */
p = npath;
while (*p == '/')
p++;
while (p = strchr (p, '/'))
{
*p = '\0';
if (stat (npath, &sb) != 0)
{
if (mkdir (npath, parent_mode))
{
builtin_error ("cannot create directory `%s': %s", npath, strerror (errno));
umask (original_umask);
free (npath);
return 1;
}
}
else if (S_ISDIR (sb.st_mode) == 0)
{
builtin_error ("`%s': file exists but is not a directory", npath);
umask (original_umask);
free (npath);
return 1;
}
*p++ = '/'; /* restore slash */
while (*p == '/')
p++;
}
/* Create the final directory component. */
if (stat (npath, &sb) && mkdir (npath, nmode))
{
builtin_error ("cannot create directory `%s': %s", npath, strerror (errno));
umask (original_umask);
free (npath);
return 1;
}
umask (original_umask);
free (npath);
return 0;
}
char *mkdir_doc[] = {
"Make directories. Create the directories named as arguments, in",
"the order specified, using mode rwxrwxrwx as modified by the current",
"umask (see `help umask'). The -m option causes the file permission",
"bits of the final directory to be MODE. The MODE argument may be",
"an octal number or a symbolic mode like that used by chmod(1). If",
"a symbolic mode is used, the operations are interpreted relative to",
"an initial mode of \"a=rwx\". The -p option causes any required",
"intermediate directories in PATH to be created. The directories",
"are created with permssion bits of rwxrwxrwx as modified by the current",
"umask, plus write and search permissions for the owner. mkdir",
"returns 0 if the directories are created successfully, and non-zero",
"if an error occurs.",
(char *)NULL
};
struct builtin mkdir_struct = {
"mkdir",
mkdir_builtin,
BUILTIN_ENABLED,
mkdir_doc,
"mkdir [-p] [-m mode] directory [directory ...]",
0
};
+33
View File
@@ -0,0 +1,33 @@
/* necho - echo without options or argument interpretation */
/* Sample builtin to be dynamically loaded with enable -f and replace an
existing builtin. */
#include <stdio.h>
#include "builtins.h"
#include "shell.h"
necho_builtin (list)
WORD_LIST *list;
{
print_word_list (list, " ");
printf("\n");
fflush (stdout);
return (EXECUTION_SUCCESS);
}
char *necho_doc[] = {
"Print the arguments to the standard ouput separated",
"by space characters and terminated with a newline.",
(char *)NULL
};
struct builtin necho_struct = {
"echo",
necho_builtin,
BUILTIN_ENABLED,
necho_doc,
"echo [args]",
0
};
+358
View File
@@ -0,0 +1,358 @@
/* pathchk - check pathnames for validity and portability */
/* Usage: pathchk [-p] path ...
For each PATH, print a message if any of these conditions are false:
* all existing leading directories in PATH have search (execute) permission
* strlen (PATH) <= PATH_MAX
* strlen (each_directory_in_PATH) <= NAME_MAX
Exit status:
0 All PATH names passed all of the tests.
1 An error occurred.
Options:
-p Instead of performing length checks on the
underlying filesystem, test the length of the
pathname and its components against the POSIX.1
minimum limits for portability, _POSIX_NAME_MAX
and _POSIX_PATH_MAX in 2.9.2. Also check that
the pathname contains no character not in the
portable filename character set. */
/* See Makefile for compilation details. */
#include <config.h>
#include <sys/types.h>
#include "posixstat.h"
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#if defined (HAVE_LIMITS_H)
# include <limits.h>
#endif
#include "bashansi.h"
#include <stdio.h>
#include <errno.h>
#include "builtins.h"
#include "shell.h"
#include "stdc.h"
#include "bashgetopt.h"
#include "maxpath.h"
#if !defined (errno)
extern int errno;
#endif
#if !defined (_POSIX_PATH_MAX)
# define _POSIX_PATH_MAX 255
#endif
#if !defined (_POSIX_NAME_MAX)
# define _POSIX_NAME_MAX 14
#endif
/* How do we get PATH_MAX? */
#if defined (_POSIX_VERSION) && !defined (PATH_MAX)
# define PATH_MAX_FOR(p) pathconf ((p), _PC_PATH_MAX)
#endif
/* How do we get NAME_MAX? */
#if defined (_POSIX_VERSION) && !defined (NAME_MAX)
# define NAME_MAX_FOR(p) pathconf ((p), _PC_NAME_MAX)
#endif
#if !defined (PATH_MAX_FOR)
# define PATH_MAX_FOR(p) PATH_MAX
#endif
#if !defined (NAME_MAX_FOR)
# define NAME_MAX_FOR(p) NAME_MAX
#endif
extern char *strerror ();
static int validate_path ();
pathchk_builtin (list)
WORD_LIST *list;
{
int retval, pflag, opt;
reset_internal_getopt ();
while ((opt = internal_getopt (list, "p")) != -1)
{
switch (opt)
{
case 'p':
pflag = 1;
break;
default:
builtin_usage ();
return (EX_USAGE);
}
}
list = loptend;
if (list == 0)
{
builtin_usage ();
return (EX_USAGE);
}
for (retval = 0; list; list = list->next)
retval |= validate_path (list->word->word, pflag);
return (retval ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
}
char *pathchk_doc[] = {
"Check each pathname argument for validity (i.e., it may be used to",
"create or access a file without casuing syntax errors) and portability",
"(i.e., no filename truncation will result). If the `-p' option is",
"supplied, more extensive portability checks are performed.",
(char *)NULL
};
/* The standard structure describing a builtin command. bash keeps an array
of these structures. */
struct builtin pathchk_struct = {
"pathchk", /* builtin name */
pathchk_builtin, /* function implementing the builtin */
BUILTIN_ENABLED, /* initial flags for builtin */
pathchk_doc, /* array of long documentation strings. */
"pathchk [-p] pathname ...", /* usage synopsis */
0 /* reserved for internal use */
};
/* The remainder of this file is stolen shamelessly from `pathchk.c' in
the sh-utils-1.12 distribution, by
David MacKenzie <djm@gnu.ai.mit.edu>
and Jim Meyering <meyering@cs.utexas.edu> */
/* Each element is nonzero if the corresponding ASCII character is
in the POSIX portable character set, and zero if it is not.
In addition, the entry for `/' is nonzero to simplify checking. */
static char const portable_chars[256] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0-15 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16-31 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, /* 32-47 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 48-63 */
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 64-79 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 80-95 */
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 96-111 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 112-127 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/* If PATH contains only portable characters, return 1, else 0. */
static int
portable_chars_only (path)
const char *path;
{
const char *p;
for (p = path; *p; ++p)
if (portable_chars[(const unsigned char) *p] == 0)
{
builtin_error ("path `%s' contains nonportable character `%c'", path, *p);
return 0;
}
return 1;
}
/* On some systems, stat can return EINTR. */
#ifndef EINTR
# define SAFE_STAT(name, buf) stat (name, buf)
#else
# define SAFE_STAT(name, buf) safe_stat (name, buf)
static inline int
safe_stat (name, buf)
const char *name;
struct stat *buf;
{
int ret;
do
ret = stat (name, buf);
while (ret < 0 && errno == EINTR);
return ret;
}
#endif
/* Return 1 if PATH is a usable leading directory, 0 if not,
2 if it doesn't exist. */
static int
dir_ok (path)
const char *path;
{
struct stat stats;
if (SAFE_STAT (path, &stats))
return 2;
if (!S_ISDIR (stats.st_mode))
{
builtin_error ("`%s' is not a directory", path);
return 0;
}
/* Use access to test for search permission because
testing permission bits of st_mode can lose with new
access control mechanisms. Of course, access loses if you're
running setuid. */
if (access (path, X_OK) != 0)
{
if (errno == EACCES)
builtin_error ("directory `%s' is not searchable", path);
else
builtin_error ("%s: %s", path, strerror (errno));
return 0;
}
return 1;
}
static char *
xstrdup (s)
char *s;
{
return (savestring (s));
}
/* Make sure that
strlen (PATH) <= PATH_MAX
&& strlen (each-existing-directory-in-PATH) <= NAME_MAX
If PORTABILITY is nonzero, compare against _POSIX_PATH_MAX and
_POSIX_NAME_MAX instead, and make sure that PATH contains no
characters not in the POSIX portable filename character set, which
consists of A-Z, a-z, 0-9, ., _, -.
Make sure that all leading directories along PATH that exist have
`x' permission.
Return 0 if all of these tests are successful, 1 if any fail. */
static int
validate_path (path, portability)
char *path;
int portability;
{
int path_max;
int last_elem; /* Nonzero if checking last element of path. */
int exists; /* 2 if the path element exists. */
char *slash;
char *parent; /* Last existing leading directory so far. */
if (portability && !portable_chars_only (path))
return 1;
if (*path == '\0')
return 0;
#ifdef lint
/* Suppress `used before initialized' warning. */
exists = 0;
#endif
/* Figure out the parent of the first element in PATH. */
parent = xstrdup (*path == '/' ? "/" : ".");
slash = path;
last_elem = 0;
while (1)
{
int name_max;
int length; /* Length of partial path being checked. */
char *start; /* Start of path element being checked. */
/* Find the end of this element of the path.
Then chop off the rest of the path after this element. */
while (*slash == '/')
slash++;
start = slash;
slash = strchr (slash, '/');
if (slash != NULL)
*slash = '\0';
else
{
last_elem = 1;
slash = strchr (start, '\0');
}
if (!last_elem)
{
exists = dir_ok (path);
if (dir_ok == 0)
{
free (parent);
return 1;
}
}
length = slash - start;
/* Since we know that `parent' is a directory, it's ok to call
pathconf with it as the argument. (If `parent' isn't a directory
or doesn't exist, the behavior of pathconf is undefined.)
But if `parent' is a directory and is on a remote file system,
it's likely that pathconf can't give us a reasonable value
and will return -1. (NFS and tempfs are not POSIX . . .)
In that case, we have no choice but to assume the pessimal
POSIX minimums. */
name_max = portability ? _POSIX_NAME_MAX : NAME_MAX_FOR (parent);
if (name_max < 0)
name_max = _POSIX_NAME_MAX;
if (length > name_max)
{
builtin_error ("name `%s' has length %d; exceeds limit of %d",
start, length, name_max);
free (parent);
return 1;
}
if (last_elem)
break;
if (exists == 1)
{
free (parent);
parent = xstrdup (path);
}
*slash++ = '/';
}
/* `parent' is now the last existing leading directory in the whole path,
so it's ok to call pathconf with it as the argument. */
path_max = portability ? _POSIX_PATH_MAX : PATH_MAX_FOR (parent);
if (path_max < 0)
path_max = _POSIX_PATH_MAX;
free (parent);
if (strlen (path) > path_max)
{
builtin_error ("path `%s' has length %d; exceeds limit of %d",
path, strlen (path), path_max);
return 1;
}
return 0;
}
+1
View File
@@ -0,0 +1 @@
/usr/local/build/chet/bash/bash-current/examples/loadables/perl/Makefile
@@ -0,0 +1,97 @@
#
# Makefile for builtin perl interpreter
#
#
# Copyright (C) 1998 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
# Include some boilerplate Gnu makefile definitions.
prefix = @prefix@
exec_prefix = @exec_prefix@
bindir = @bindir@
libdir = @libdir@
infodir = @infodir@
includedir = @includedir@
topdir = @top_srcdir@
BUILD_DIR = @BUILD_DIR@
srcdir = @srcdir@
VPATH = .:@srcdir@
@SET_MAKE@
CC = @CC@
RM = rm -f
SHELL = @MAKE_SHELL@
PERL5 = perl5
CFLAGS = @CFLAGS@
#
# These values are generated for configure by ${topdir}/support/shobj-conf.
# If your system is not supported by that script, but includes facilities for
# dynamic loading of shared objects, please update the script and send the
# changes to bash-maintainers@gnu.org.
#
SHOBJ_CC = @SHOBJ_CC@
SHOBJ_CFLAGS = @SHOBJ_CFLAGS@
SHOBJ_LD = @SHOBJ_LD@
SHOBJ_LDFLAGS = @SHOBJ_LDFLAGS@
SHOBJ_XLDFLAGS = @SHOBJ_XLDFLAGS@
SHOBJ_LIBS = @SHOBJ_LIBS@
SHOBJ_STATUS = @SHOBJ_STATUS@
# Values used for compiling the perl files
PERL_LDOPTS = `${PERL5} -MExtUtils::Embed -e ldopts`
PERL_CFLAGS = ${CCFLAGS} `${PERL5} -MExtUtils::Embed -e ccopts`
SRC = bperl.c iperl.c perlxsi.c
OBJ = bperl.o iperl.o perlxsi.o
BUILTIN = bperl5
INC = -I. -I.. -I$(topdir) -I$(topdir)/lib -I$(topdir)/builtins \
-I$(topdir)/include -I$(BUILD_DIR) -I$(BUILD_DIR)/lib \
-I$(BUILD_DIR)/builtins
${BUILTIN}: ${OBJ}
${RM} $@
${SHOBJ_LD} ${SHOBJ_LDFLAGS} ${SHOBJ_XLDFLAGS} -o $@ ${OBJ} ${PERL_LDOPTS} ${SHOBJ_LIBS}
bperl.o: bperl.c
${RM} $@
$(SHOBJ_CC) $(SHOBJ_CFLAGS) $(CFLAGS) $(INC) -c -o $@ ${srcdir}/bperl.c
iperl.o: iperl.c
${RM} $@
$(SHOBJ_CC) ${SHOBJ_CFLAGS} $(PERL_CFLAGS) -c -o $@ ${srcdir}/iperl.c
perlxsi.c:
${PERL5} -MExtUtils::Embed -e xsinit -- -o $@
perlxsi.o: perlxsi.c
${RM} $@
${SHOBJ_CC} ${SHOBJ_CFLAGS} $(PERL_CFLAGS) -c -o $@ perlxsi.c
clean mostlyclean:
${RM} ${OBJ}
${RM} ${BUILTIN}
distclean maintainer-clean: clean
${RM} perlxsi.c
@@ -0,0 +1,6 @@
This illustrates how to build a perl interpreter into bash. It's not
especially useful; more a proof of concept (it provides none of the
bash internals to the perl interpreter, for example).
This *may* require adding "-rpath /path/to/perl/CORE" and -lperl options
when compiling bash itself.
@@ -0,0 +1,46 @@
/*
* perl builtin
*/
#include <config.h>
#include <fcntl.h>
#include <errno.h>
#include "builtins.h"
#include "shell.h"
#ifndef errno
extern int errno;
#endif
extern char **make_builtin_argv ();
extern char **export_env;
extern int perl_main();
bperl_builtin(list)
WORD_LIST *list;
{
char **v;
int c, r;
v = make_builtin_argv(list, &c);
r = perl_main(c, v, export_env);
free(v);
return r;
}
char *bperl_doc[] = {
"An interface to a perl5 interpreter.",
(char *)0
};
struct builtin bperl_struct = {
"bperl",
bperl_builtin,
BUILTIN_ENABLED,
bperl_doc,
"bperl [perl options] [file ...]",
0
};
@@ -0,0 +1,24 @@
#include <EXTERN.h> /* from the Perl distribution */
#include <perl.h> /* from the Perl distribution */
extern void xs_init _((void));
static PerlInterpreter *iperl; /*** The Perl interpreter ***/
int
perl_main(int argc, char **argv, char **env)
{
int r;
iperl = perl_alloc();
perl_construct(iperl);
perl_parse(iperl, xs_init, argc, argv, (char **)NULL);
r = perl_run(iperl);
PerlIO_flush(PerlIO_stdout());
PerlIO_flush(PerlIO_stderr());
perl_destruct(iperl);
perl_free(iperl);
return (r);
}
+169
View File
@@ -0,0 +1,169 @@
/*
* print -- loadable ksh-93 style print builtin
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "bashtypes.h"
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include "bashansi.h"
#include "shell.h"
#include "builtins.h"
#include "stdc.h"
#include "bashgetopt.h"
#if !defined (errno)
extern int errno;
#endif
int print_builtin ();
static int printargs ();
static FILE *ofp;
extern char *this_command_name;
static char *print_doc[] = {
"Output the arguments. The -f option means to use the argument as a",
"format string as would be supplied to printf(1). The rest of the",
"options are as in ksh.",
(char *)NULL
};
struct builtin print_struct = {
"print",
print_builtin,
BUILTIN_ENABLED,
print_doc,
"print [-Rnprs] [-u unit] [-f format] [arguments]",
(char *)0
};
#ifndef ISOPTION
#define ISOPTION(s, c) (s[0] == '-' && s[2] == '\0' && s[1] == c)
#endif
int
print_builtin (list)
WORD_LIST *list;
{
int c, r, nflag, raw, ofd, sflag;
intmax_t lfd;
char **v, *pfmt, *arg;
WORD_LIST *l;
nflag = raw = sflag = 0;
ofd = 1;
pfmt = 0;
reset_internal_getopt ();
while ((c = internal_getopt (list, "Rnprsu:f:")) != -1)
{
switch (c)
{
case 'R':
raw = 2;
loptend = lcurrent;
if (loptend && ISOPTION (loptend->word->word, 'n'))
{
loptend = loptend->next;
nflag = 1;
}
goto opt_end;
case 'r':
raw = 1;
break;
case 'n':
nflag = 1;
break;
case 's':
sflag = 1;
break;
case 'p':
break; /* NOP */
case 'u':
if (all_digits (list_optarg) && legal_number (list_optarg, &lfd) && lfd == (int)lfd)
ofd = lfd;
else
{
for (l = list; l->next && l->next != lcurrent; l = l->next);
lcurrent = loptend = l;
goto opt_end;
}
break;
case 'f':
pfmt = list_optarg;
break;
default:
builtin_usage ();
return (EX_USAGE);
}
}
opt_end:
list = loptend;
ofp = (ofd == 1) ? stdout : fdopen (dup (ofd), "w");
if (pfmt)
{
WORD_DESC *w;
WORD_LIST *nlist;
w = make_word (pfmt);
nlist = make_word_list (w, list);
r = printf_builtin (nlist);
nlist->next = (WORD_LIST *)NULL;
dispose_words (nlist);
return (r);
}
if (raw)
{
for (l = list; l; l = l->next)
{
fprintf (ofp, "%s", l->word->word);
if (l->next)
fprintf (ofp, " ");
}
if (nflag == 0)
fprintf (ofp, "\n");
fflush (ofp);
return (0);
}
r = printargs (list, ofp);
if (r && nflag == 0)
fprintf (ofp, "\n");
if (ofd != 1)
fclose (ofp);
return 0;
}
static int
printargs (list, ofp)
WORD_LIST *list;
FILE *ofp;
{
WORD_LIST *l;
char *ostr;
int sawc;
for (sawc = 0, l = list; l; l = l->next)
{
ostr = ansicstr (l->word->word, strlen (l->word->word), 0, &sawc, (int *)0);
fprintf (ofp, "%s", ostr);
free (ostr);
if (sawc)
return (0);
if (l->next)
fprintf (ofp, " ");
}
return (1);
}
@@ -0,0 +1,71 @@
/*
* printenv -- minimal builtin clone of BSD printenv(1).
*
* usage: printenv [varname]
*
*/
#include <config.h>
#include <stdio.h>
#include "builtins.h"
#include "shell.h"
#include "bashgetopt.h"
extern char **export_env;
int
printenv_builtin (list)
WORD_LIST *list;
{
register char **envp;
int opt;
SHELL_VAR *var;
reset_internal_getopt ();
while ((opt = internal_getopt (list, "")) != -1)
{
switch (opt)
{
default:
builtin_usage ();
return (EX_USAGE);
}
}
list = loptend;
/* printenv */
if (list == 0)
{
maybe_make_export_env (); /* this allows minimal code */
for (envp = export_env; *envp; envp++)
printf ("%s\n", *envp);
return (EXECUTION_SUCCESS);
}
/* printenv varname */
var = find_variable (list->word->word);
if (var == 0 || (exported_p (var) == 0))
return (EXECUTION_FAILURE);
if (function_p (var))
print_var_function (var);
else
print_var_value (var, 0);
return (EXECUTION_SUCCESS);
}
char *printenv_doc[] = {
"print values of environment variables",
(char *)NULL
};
struct builtin printenv_struct = {
"printenv",
printenv_builtin,
BUILTIN_ENABLED,
printenv_doc,
"printenv [varname]",
0
};
+95
View File
@@ -0,0 +1,95 @@
/*
* push - anyone remember TOPS-20?
*
*/
#include <config.h>
#include <stdio.h>
#include <errno.h>
#include "builtins.h"
#include "shell.h"
#include "jobs.h"
#include "bashgetopt.h"
#ifndef errno
extern int errno;
#endif
extern int dollar_dollar_pid;
extern int last_command_exit_value;
int
push_builtin (list)
WORD_LIST *list;
{
pid_t pid;
int xstatus, opt;
xstatus = EXECUTION_SUCCESS;
reset_internal_getopt ();
while ((opt = internal_getopt (list, "")) != -1)
{
switch (opt)
{
default:
builtin_usage ();
return (EX_USAGE);
}
}
list = loptend;
pid = make_child (savestring ("push"), 0);
if (pid == -1)
{
builtin_error ("cannot fork: %s", strerror (errno));
return (EXECUTION_FAILURE);
}
else if (pid == 0)
{
/* Shell variable adjustments: $SHLVL, $$, $PPID, $! */
adjust_shell_level (1);
dollar_dollar_pid = getpid ();
set_ppid ();
/* Clean up job control stuff. */
stop_making_children ();
cleanup_the_pipeline ();
delete_all_jobs (0);
last_asynchronous_pid = NO_PID;
/* Make sure the job control code has the right values for
the shell's process group and tty process group, and that
the signals are set correctly for job control. */
initialize_job_control (0);
initialize_job_signals ();
/* And read commands until exit. */
reader_loop ();
exit_shell (last_command_exit_value);
}
else
{
stop_pipeline (0, (COMMAND *)NULL);
xstatus = wait_for (pid);
return (xstatus);
}
}
char *push_doc[] = {
"Create a child that is an exact duplicate of the running shell",
"and wait for it to exit. The $SHLVL, $!, $$, and $PPID variables",
"are adjusted in the child. The return value is the exit status",
"of the child.",
(char *)NULL
};
struct builtin push_struct = {
"push",
push_builtin,
BUILTIN_ENABLED,
push_doc,
"push",
0
};
+611
View File
@@ -0,0 +1,611 @@
This file is pushd.def, from which is created pushd.c. It implements the
builtins "pushd", "popd", and "dirs" in Bash.
Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 1, or (at your option) any later
version.
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with Bash; see the file COPYING. If not, write to the Free Software
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
$PRODUCES pushd.c
$BUILTIN pushd
$FUNCTION pushd_builtin
$DEPENDS_ON PUSHD_AND_POPD
$SHORT_DOC pushd [dir | +N | -N] [-n]
Adds a directory to the top of the directory stack, or rotates
the stack, making the new top of the stack the current working
directory. With no arguments, exchanges the top two directories.
+N Rotates the stack so that the Nth directory (counting
from the left of the list shown by `dirs', starting with
zero) is at the top.
-N Rotates the stack so that the Nth directory (counting
from the right of the list shown by `dirs', starting with
zero) is at the top.
-n suppress the normal change of directory when adding directories
to the stack, so only the stack is manipulated.
dir adds DIR to the directory stack at the top, making it the
new current working directory.
You can see the directory stack with the `dirs' command.
$END
$BUILTIN popd
$FUNCTION popd_builtin
$DEPENDS_ON PUSHD_AND_POPD
$SHORT_DOC popd [+N | -N] [-n]
Removes entries from the directory stack. With no arguments,
removes the top directory from the stack, and cd's to the new
top directory.
+N removes the Nth entry counting from the left of the list
shown by `dirs', starting with zero. For example: `popd +0'
removes the first directory, `popd +1' the second.
-N removes the Nth entry counting from the right of the list
shown by `dirs', starting with zero. For example: `popd -0'
removes the last directory, `popd -1' the next to last.
-n suppress the normal change of directory when removing directories
from the stack, so only the stack is manipulated.
You can see the directory stack with the `dirs' command.
$END
$BUILTIN dirs
$FUNCTION dirs_builtin
$DEPENDS_ON PUSHD_AND_POPD
$SHORT_DOC dirs [-clpv] [+N] [-N]
Display the list of currently remembered directories. Directories
find their way onto the list with the `pushd' command; you can get
back up through the list with the `popd' command.
The -l flag specifies that `dirs' should not print shorthand versions
of directories which are relative to your home directory. This means
that `~/bin' might be displayed as `/homes/bfox/bin'. The -v flag
causes `dirs' to print the directory stack with one entry per line,
prepending the directory name with its position in the stack. The -p
flag does the same thing, but the stack position is not prepended.
The -c flag clears the directory stack by deleting all of the elements.
+N displays the Nth entry counting from the left of the list shown by
dirs when invoked without options, starting with zero.
-N displays the Nth entry counting from the right of the list shown by
dirs when invoked without options, starting with zero.
$END
#include <config.h>
#if defined (PUSHD_AND_POPD)
#include <stdio.h>
#include <sys/param.h>
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include "../bashansi.h"
#include <errno.h>
#include <tilde/tilde.h>
#include "../shell.h"
#include "../maxpath.h"
#include "common.h"
#include "builtext.h"
#if !defined (errno)
extern int errno;
#endif /* !errno */
static char *m_badarg = "%s: bad argument";
/* The list of remembered directories. */
static char **pushd_directory_list = (char **)NULL;
/* Number of existing slots in this list. */
static int directory_list_size;
/* Offset to the end of the list. */
static int directory_list_offset;
static void pushd_error ();
static void clear_directory_stack ();
static int cd_to_string ();
static int change_to_temp ();
static int get_dirstack_index ();
static void add_dirstack_element ();
#define NOCD 0x01
#define ROTATE 0x02
#define LONGFORM 0x04
#define CLEARSTAK 0x08
int
pushd_builtin (list)
WORD_LIST *list;
{
char *temp, *current_directory, *top;
int j, flags;
long num;
char direction;
/* If there is no argument list then switch current and
top of list. */
if (list == 0)
{
if (directory_list_offset == 0)
{
builtin_error ("no other directory");
return (EXECUTION_FAILURE);
}
current_directory = get_working_directory ("pushd");
if (current_directory == 0)
return (EXECUTION_FAILURE);
j = directory_list_offset - 1;
temp = pushd_directory_list[j];
pushd_directory_list[j] = current_directory;
j = change_to_temp (temp);
free (temp);
return j;
}
for (flags = 0; list; list = list->next)
{
if (ISOPTION (list->word->word, 'n'))
{
flags |= NOCD;
}
else if (ISOPTION (list->word->word, '-'))
{
list = list->next;
break;
}
else if (list->word->word[0] == '-' && list->word->word[1] == '\0')
/* Let `pushd -' work like it used to. */
break;
else if (((direction = list->word->word[0]) == '+') || direction == '-')
{
if (legal_number (list->word->word + 1, &num) == 0)
{
builtin_error (m_badarg, list->word->word);
builtin_usage ();
return (EXECUTION_FAILURE);
}
if (direction == '-')
num = directory_list_offset - num;
if (num > directory_list_offset || num < 0)
{
pushd_error (directory_list_offset, list->word->word);
return (EXECUTION_FAILURE);
}
flags |= ROTATE;
}
else if (*list->word->word == '-')
{
bad_option (list->word->word);
builtin_usage ();
return (EXECUTION_FAILURE);
}
else
break;
}
if (flags & ROTATE)
{
/* Rotate the stack num times. Remember, the current
directory acts like it is part of the stack. */
temp = get_working_directory ("pushd");
if (num == 0)
{
j = ((flags & NOCD) == 0) ? change_to_temp (temp) : EXECUTION_SUCCESS;
free (temp);
return j;
}
do
{
top = pushd_directory_list[directory_list_offset - 1];
for (j = directory_list_offset - 2; j > -1; j--)
pushd_directory_list[j + 1] = pushd_directory_list[j];
pushd_directory_list[j + 1] = temp;
temp = top;
num--;
}
while (num);
j = ((flags & NOCD) == 0) ? change_to_temp (temp) : EXECUTION_SUCCESS;
free (temp);
return j;
}
if (list == 0)
return (EXECUTION_SUCCESS);
/* Change to the directory in list->word->word. Save the current
directory on the top of the stack. */
current_directory = get_working_directory ("pushd");
if (current_directory == 0)
return (EXECUTION_FAILURE);
j = ((flags & NOCD) == 0) ? cd_builtin (list) : EXECUTION_SUCCESS;
if (j == EXECUTION_SUCCESS)
{
add_dirstack_element ((flags & NOCD) ? savestring (list->word->word) : current_directory);
dirs_builtin ((WORD_LIST *)NULL);
if (flags & NOCD)
free (current_directory);
return (EXECUTION_SUCCESS);
}
else
{
free (current_directory);
return (EXECUTION_FAILURE);
}
}
/* Pop the directory stack, and then change to the new top of the stack.
If LIST is non-null it should consist of a word +N or -N, which says
what element to delete from the stack. The default is the top one. */
int
popd_builtin (list)
WORD_LIST *list;
{
register int i;
long which;
int flags;
char direction;
char *which_word;
which_word = (char *)NULL;
for (flags = 0, which = 0L, direction = '+'; list; list = list->next)
{
if (ISOPTION (list->word->word, 'n'))
{
flags |= NOCD;
}
else if (ISOPTION (list->word->word, '-'))
{
list = list->next;
break;
}
else if (((direction = list->word->word[0]) == '+') || direction == '-')
{
if (legal_number (list->word->word + 1, &which) == 0)
{
builtin_error (m_badarg, list->word->word);
builtin_usage ();
return (EXECUTION_FAILURE);
}
which_word = list->word->word;
}
else if (*list->word->word == '-')
{
bad_option (list->word->word);
builtin_usage ();
return (EXECUTION_FAILURE);
}
else
break;
}
if (which > directory_list_offset || (directory_list_offset == 0 && which == 0))
{
pushd_error (directory_list_offset, which_word ? which_word : "");
return (EXECUTION_FAILURE);
}
/* Handle case of no specification, or top of stack specification. */
if ((direction == '+' && which == 0) ||
(direction == '-' && which == directory_list_offset))
{
i = ((flags & NOCD) == 0) ? cd_to_string (pushd_directory_list[directory_list_offset - 1])
: EXECUTION_SUCCESS;
if (i != EXECUTION_SUCCESS)
return (i);
free (pushd_directory_list[--directory_list_offset]);
}
else
{
/* Since an offset other than the top directory was specified,
remove that directory from the list and shift the remainder
of the list into place. */
i = (direction == '+') ? directory_list_offset - which : which;
free (pushd_directory_list[i]);
directory_list_offset--;
/* Shift the remainder of the list into place. */
for (; i < directory_list_offset; i++)
pushd_directory_list[i] = pushd_directory_list[i + 1];
}
dirs_builtin ((WORD_LIST *)NULL);
return (EXECUTION_SUCCESS);
}
/* Print the current list of directories on the directory stack. */
int
dirs_builtin (list)
WORD_LIST *list;
{
int flags, desired_index, index_flag, vflag;
long i;
char *temp, *w;
for (flags = vflag = index_flag = 0, desired_index = -1, w = ""; list; list = list->next)
{
if (ISOPTION (list->word->word, 'l'))
{
flags |= LONGFORM;
}
else if (ISOPTION (list->word->word, 'c'))
{
flags |= CLEARSTAK;
}
else if (ISOPTION (list->word->word, 'v'))
{
vflag |= 2;
}
else if (ISOPTION (list->word->word, 'p'))
{
vflag |= 1;
}
else if (ISOPTION (list->word->word, '-'))
{
list = list->next;
break;
}
else if (*list->word->word == '+' || *list->word->word == '-')
{
int sign;
if (legal_number (w = list->word->word + 1, &i) == 0)
{
builtin_error (m_badarg, list->word->word);
builtin_usage ();
return (EXECUTION_FAILURE);
}
sign = (*list->word->word == '+') ? 1 : -1;
desired_index = get_dirstack_index (i, sign, &index_flag);
}
else
{
bad_option (list->word->word);
builtin_usage ();
return (EXECUTION_FAILURE);
}
}
if (flags & CLEARSTAK)
{
clear_directory_stack ();
return (EXECUTION_SUCCESS);
}
if (index_flag && (desired_index < 0 || desired_index > directory_list_offset))
{
pushd_error (directory_list_offset, w);
return (EXECUTION_FAILURE);
}
#define DIRSTACK_FORMAT(temp) \
(flags & LONGFORM) ? temp : polite_directory_format (temp)
/* The first directory printed is always the current working directory. */
if (index_flag == 0 || (index_flag == 1 && desired_index == 0))
{
temp = get_working_directory ("dirs");
if (temp == 0)
temp = savestring ("<no current directory>");
if (vflag & 2)
printf ("%2d %s", 0, DIRSTACK_FORMAT (temp));
else
printf ("%s", DIRSTACK_FORMAT (temp));
free (temp);
if (index_flag)
{
putchar ('\n');
return EXECUTION_SUCCESS;
}
}
#define DIRSTACK_ENTRY(i) \
(flags & LONGFORM) ? pushd_directory_list[i] \
: polite_directory_format (pushd_directory_list[i])
/* Now print the requested directory stack entries. */
if (index_flag)
{
if (vflag & 2)
printf ("%2d %s", directory_list_offset - desired_index,
DIRSTACK_ENTRY (desired_index));
else
printf ("%s", DIRSTACK_ENTRY (desired_index));
}
else
for (i = directory_list_offset - 1; i >= 0; i--)
if (vflag >= 2)
printf ("\n%2d %s", directory_list_offset - (int)i, DIRSTACK_ENTRY (i));
else
printf ("%s%s", (vflag & 1) ? "\n" : " ", DIRSTACK_ENTRY (i));
putchar ('\n');
fflush (stdout);
return (EXECUTION_SUCCESS);
}
static void
pushd_error (offset, arg)
int offset;
char *arg;
{
if (offset == 0)
builtin_error ("directory stack empty");
else if (arg)
builtin_error ("%s: bad directory stack index", arg);
else
builtin_error ("bad directory stack index");
}
static void
clear_directory_stack ()
{
register int i;
for (i = 0; i < directory_list_offset; i++)
free (pushd_directory_list[i]);
directory_list_offset = 0;
}
/* Switch to the directory in NAME. This uses the cd_builtin to do the work,
so if the result is EXECUTION_FAILURE then an error message has already
been printed. */
static int
cd_to_string (name)
char *name;
{
WORD_LIST *tlist;
int result;
tlist = make_word_list (make_word (name), NULL);
result = cd_builtin (tlist);
dispose_words (tlist);
return (result);
}
static int
change_to_temp (temp)
char *temp;
{
int tt;
tt = temp ? cd_to_string (temp) : EXECUTION_FAILURE;
if (tt == EXECUTION_SUCCESS)
dirs_builtin ((WORD_LIST *)NULL);
return (tt);
}
static void
add_dirstack_element (dir)
char *dir;
{
int j;
if (directory_list_offset == directory_list_size)
{
j = (directory_list_size += 10) * sizeof (char *);
pushd_directory_list = (char **)xrealloc (pushd_directory_list, j);
}
pushd_directory_list[directory_list_offset++] = dir;
}
static int
get_dirstack_index (ind, sign, indexp)
int ind, sign, *indexp;
{
if (indexp)
*indexp = sign > 0 ? 1 : 2;
/* dirs +0 prints the current working directory. */
/* dirs -0 prints last element in directory stack */
if (ind == 0 && sign > 0)
return 0;
else if (ind == directory_list_offset)
{
if (indexp)
*indexp = sign > 0 ? 2 : 1;
return 0;
}
else
return (sign > 0 ? directory_list_offset - ind : ind);
}
char *
get_dirstack_element (ind, sign)
int ind, sign;
{
int i;
i = get_dirstack_index (ind, sign, (int *)NULL);
return (i < 0 || i > directory_list_offset) ? (char *)NULL
: pushd_directory_list[i];
}
void
set_dirstack_element (ind, sign, value)
int ind, sign;
char *value;
{
int i;
i = get_dirstack_index (ind, sign, (int *)NULL);
if (ind == 0 || i < 0 || i > directory_list_offset)
return;
free (pushd_directory_list[i]);
pushd_directory_list[i] = savestring (value);
}
WORD_LIST *
get_directory_stack ()
{
register int i;
WORD_LIST *ret;
char *d, *t;
for (ret = (WORD_LIST *)NULL, i = 0; i < directory_list_offset; i++)
{
d = polite_directory_format (pushd_directory_list[i]);
ret = make_word_list (make_word (d), ret);
}
/* Now the current directory. */
d = get_working_directory ("dirstack");
i = 0; /* sentinel to decide whether or not to free d */
if (d == 0)
d = ".";
else
{
t = polite_directory_format (d);
/* polite_directory_format sometimes returns its argument unchanged.
If it does not, we can free d right away. If it does, we need to
mark d to be deleted later. */
if (t != d)
{
free (d);
d = t;
}
else /* t == d, so d is what we want */
i = 1;
}
ret = make_word_list (make_word (d), ret);
if (i)
free (d);
return ret; /* was (REVERSE_LIST (ret, (WORD_LIST *)); */
}
#endif /* PUSHD_AND_POPD */
@@ -0,0 +1,90 @@
static char *dirs_doc[] = {
"Display the list of currently remembered directories. Directories",
"find their way onto the list with the `pushd' command; you can get",
"back up through the list with the `popd' command.",
"",
"The -l flag specifies that `dirs' should not print shorthand versions",
"of directories which are relative to your home directory. This means",
"that `~/bin' might be displayed as `/homes/bfox/bin'. The -v flag",
"causes `dirs' to print the directory stack with one entry per line,",
"prepending the directory name with its position in the stack. The -p",
"flag does the same thing, but the stack position is not prepended.",
"The -c flag clears the directory stack by deleting all of the elements.",
"",
"+N displays the Nth entry counting from the left of the list shown by",
" dirs when invoked without options, starting with zero.",
"",
"-N displays the Nth entry counting from the right of the list shown by",
" dirs when invoked without options, starting with zero.",
(char *)NULL
};
static char *pushd_doc[] = {
"Adds a directory to the top of the directory stack, or rotates",
"the stack, making the new top of the stack the current working",
"directory. With no arguments, exchanges the top two directories.",
"",
"+N Rotates the stack so that the Nth directory (counting",
" from the left of the list shown by `dirs', starting with"
" zero) is at the top.",
"",
"-N Rotates the stack so that the Nth directory (counting",
" from the right of the list shown by `dirs', starting with"
" zero) is at the top.",
"",
"-n suppress the normal change of directory when adding directories",
" to the stack, so only the stack is manipulated.",
"",
"dir adds DIR to the directory stack at the top, making it the",
" new current working directory.",
"",
"You can see the directory stack with the `dirs' command.",
(char *)NULL
};
static char *popd_doc[] = {
"Removes entries from the directory stack. With no arguments,",
"removes the top directory from the stack, and cd's to the new",
"top directory.",
"",
"+N removes the Nth entry counting from the left of the list",
" shown by `dirs', starting with zero. For example: `popd +0'",
" removes the first directory, `popd +1' the second.",
"",
"-N removes the Nth entry counting from the right of the list",
" shown by `dirs', starting with zero. For example: `popd -0'",
" removes the last directory, `popd -1' the next to last.",
"",
"-n suppress the normal change of directory when removing directories",
" from the stack, so only the stack is manipulated.",
"",
"You can see the directory stack with the `dirs' command.",
(char *)NULL
};
struct builtin pushd_struct = {
"pushd",
pushd_builtin,
BUILTIN_ENABLED,
pushd_doc,
"pushd [+N | -N] [-n] [dir]",
0
};
struct builtin popd_struct = {
"popd",
popd_builtin,
BUILTIN_ENABLED,
popd_doc,
"popd [+N | -N] [-n]",
0
};
struct builtin dirs_struct = {
"dirs",
dirs_builtin,
BUILTIN_ENABLED,
dirs_doc,
"dirs [-clpv] [+N] [-N]",
0
};
+119
View File
@@ -0,0 +1,119 @@
/*
* realpath -- canonicalize pathnames, resolving symlinks
*
* usage: realpath [-csv] pathname [pathname...]
*
* options: -c check whether or not each resolved path exists
* -s no output, exit status determines whether path is valid
* -v produce verbose output
*
*
* exit status: 0 if all pathnames resolved
* 1 if any of the pathname arguments could not be resolved
*
*
* Bash loadable builtin version
*
* Chet Ramey
* chet@po.cwru.edu
*/
#include "config.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include "bashansi.h"
#include <maxpath.h>
#include <errno.h>
#include "builtins.h"
#include "shell.h"
#include "bashgetopt.h"
#ifndef errno
extern int errno;
#endif
extern char *sh_realpath();
realpath_builtin(list)
WORD_LIST *list;
{
int opt, cflag, vflag, sflag, es;
char *r, realbuf[PATH_MAX], *p;
struct stat sb;
if (list == 0) {
builtin_usage();
return (EX_USAGE);
}
vflag = cflag = sflag = 0;
reset_internal_getopt();
while ((opt = internal_getopt (list, "csv")) != -1) {
switch (opt) {
case 'c':
cflag = 1;
break;
case 's':
sflag = 1;
break;
case 'v':
vflag = 1;
break;
default:
usage();
}
}
list = loptend;
if (list == 0)
usage();
for (es = EXECUTION_SUCCESS; list; list = list->next) {
p = list->word->word;
r = sh_realpath(p, realbuf);
if (r == 0) {
es = EXECUTION_FAILURE;
if (sflag == 0)
builtin_error("%s: cannot resolve: %s", p, strerror(errno));
continue;
}
if (cflag && (stat(realbuf, &sb) < 0)) {
es = EXECUTION_FAILURE;
if (sflag == 0)
builtin_error("%s: %s", p, strerror(errno));
continue;
}
if (sflag == 0) {
if (vflag)
printf ("%s -> ", p);
printf("%s\n", realbuf);
}
}
return es;
}
char *realpath_doc[] = {
"Display the canonicalized version of each PATHNAME argument, resolving",
"symbolic links. The -c option checks whether or not each resolved name",
"exists. The -s option produces no output; the exit status determines the",
"valididty of each PATHNAME. The -v option produces verbose output. The",
"exit status is 0 if each PATHNAME was resolved; non-zero otherwise.",
(char *)NULL
};
struct builtin realpath_struct = {
"realpath", /* builtin name */
realpath_builtin, /* function implementing the builtin */
BUILTIN_ENABLED, /* initial flags for builtin */
realpath_doc, /* array of long documentation strings */
"realpath [-csv] pathname [pathname...]", /* usage synopsis */
0 /* reserved for internal use */
};
+50
View File
@@ -0,0 +1,50 @@
/* rmdir - remove directory */
/* See Makefile for compilation details. */
#include "config.h"
#include <stdio.h>
#include <errno.h>
#include "builtins.h"
#include "shell.h"
#if !defined (errno)
extern int errno;
#endif
rmdir_builtin (list)
WORD_LIST *list;
{
int rval;
WORD_LIST *l;
if (no_options (list))
return (EX_USAGE);
for (rval = EXECUTION_SUCCESS, l = list; l; l = l->next)
if (rmdir (l->word->word) < 0)
{
builtin_error ("%s: %s", l->word->word, strerror (errno));
rval = EXECUTION_FAILURE;
}
return rval;
}
char *rmdir_doc[] = {
"rmdir removes the directory entry specified by each argument,",
"provided the directory is empty.",
(char *)NULL
};
/* The standard structure describing a builtin command. bash keeps an array
of these structures. */
struct builtin rmdir_struct = {
"rmdir", /* builtin name */
rmdir_builtin, /* function implementing the builtin */
BUILTIN_ENABLED, /* initial flags for builtin */
rmdir_doc, /* array of long documentation strings. */
"rmdir directory ...", /* usage synopsis; becomes short_doc */
0 /* reserved for internal use */
};

Some files were not shown because too many files have changed in this diff Show More