What is this page about, anyway? It doesn't say anything about my family, my other interests outside work, etc. If you already know about me and my interests, fine. If you don't, fine. Which begs the question, what is this page doing here? Well, I've been asked a couple of times to post various code I've written, so here is a collection of code: shell scripts, awk scripts, Tcl scripts, and C programs. Some of them really are useful and some of them probably aren't. A couple of them aren't even my own work, but are so simple, cool, and useful, that I've included them below (their authors are identified in the script description).
To fetch any of them, go to its long description and shift-click on the link. Simple stuff like scripts that are a single text file will arrive unpackaged. Anything that consists of more than one file is packaged as a gzip'd tar file (.tar.gz).
(Disclaimer: There may be bugs in any of these programs. Use at your own risk.)
And without further ado, here are the programs:
#define
's.
$PATH
is a real directory or not. It discards all the non-directory
components and all the duplicates. It's useful in
.cshrc
or .bashrc
files,
because you can go ahead and casually compose an over-generous
PATH
and then use
PATH=`cleanuppath`to get rid of the cruft.
hh:mm:ss.ssIts value is that it prints time with finer granularity than the 1-second clock normally available, and its printing is synchronized to the correct time -- that is, when it prints 12:34:56.7, the time really is within a few ms of 12:34:56.7 (according to your system clock!), and won't be (say) 12:34:56.66 or 12:34:56.73.
compdir dir1 dir2
Unlike diff -r,
compdir only prints the names of the differing
files (not the contents), and it has command-line options to
easily exclude unwanted files. For example, to exclude
all .o, .a, and .sl
files from comparison of directories dir1
and dir2, you can do:
compdir -X "*.[oa]" "*.sl" dir1 dir2
csh $HOME/bin/csh2shenv > $HOME/.shenv-tmp . $HOME/.shenv-tmp
% dirfits r22*.fits r220.fits 1999-04-12T03:20:43.0 bias r222.fits 1999-04-12T03:22:27.0 bias r224.fits 1999-04-12T03:24:48.0 bias r226.fits 1999-04-12T03:26:54.0 bias r228.fits 1999-04-12T03:32:57.0 GD71 r229.fits 1999-04-12T04:11:56.0 object direct for 99by
dirfits -h
#define
's.
The dtags output can optionally be merged into a
standard tags file.
The value of this is that you can jump (when editing source code)
to a macro definition as easily as you can jump to a
function definition.
dtags -h
Duptape is a script that uses recordio to do the actual copying. When reading a tape, recordio creates a single stream of data that represents the tape. The stream includes both the actual data bytes plus metadata that specifies each record length and the filemarks. When writing to a tape, recordio reads one of these date-plus-metadata streams, and uses the embedded record and filemark information to create a precise copy of the original.
These tools can occasionally be helpful when operating on rigorously fixed-format files. (Fancier binary-file editors can do this stuff better, but these are extremely fast when pulling sparse but regular data from large files.)
Filestrings is a script that applies the strings command to a file, and then keeps only the results that
For example, here is the result of applying filestrings to /sbin/portmap on a Linux system:
$ filestrings /sbin/portmap /bin/sh /dev/null /etc/hosts.allow /etc/hosts.deny /lib/ld-linux.so.2It is very simple to see that the portmapper is probably processing /etc/hosts.allow and /etc/hosts.deny. By comparison, the output of plain strings is about 300 lines long, and is correspondingly difficult to browse through.
Filestrings is complementary to programs like truss (on Solaris) or strace (on Linux), which print the system calls that are made while a program runs. Inspecting the open() calls will show which files are opened; however, it's not always opportune or safe to run arbitrary programs in such a test configuration, and furthermore different run-time options can change the particular files opened, as can environment variables or some disk data. By contrast, filestrings cannot say exactly which files will be opened, but it does show all the built-in paths.
filestrings -h
Follow takes each command-line argument to be a pathname. If the path is not a symbolic link, it simply prints the path. Otherwise, it follows the (possible chain of) symlink pointers from start to end, printing each link along the way. For each link printed, it also prints a non-symlink path to the file.
Follow can also follow every path component that makes up a pathname, which is helpful when one or more directories along the way are themselves symbolic links. As a convenience, it can also do ls -l on each path printed.
follow -h
ftags -h
% ps -ef | grep whatever
will 20369 6535 0 13:20 pts/9 00:00:00 grep whatever
but the grep command has thrown out the column titles
along with the unwanted data.
The hdr command will keep the first (or more) line,
and then apply the grep command to the rest of the input:
% ps -ef | hdr grep whatever
UID PID PPID C STIME TTY TIME CMD
will 20372 6535 0 13:22 pts/9 00:00:00 grep whatever
The general use is
hdr [-Nlines] command...
which will keep Nlines of header before the
command is exec'd to process the rest of the input.
hdr -h
hilight is
'' produces:
hilight is a filter to highlight (with boldface,
reverse-video, or underlining) selected text from stdin.
For instance, feeding this paragraph to the command
hilight is
produces:
The default hilighting is the terminal's standout escape sequence. There are options to explicitly select boldface, reverse-video, or underlining. Pagers such as less may not pass the highlight escape sequences through to the terminal (for example, the ASCII ESC character may be printed as \E), so there are also options to generate output in a format that less will correctly display.
hilight -h
For example, to overwrite textfile
with only its lines containing woogums
, you can write
grep woogums textfile | hold textfile
Hold is a variant of the overwrite script from
Brian W. Kernighan and Rob Pike's
The Unix Programming Environment
(Prentice Hall, Inc., 1984; ISBN 0-13-937681-X).
Although published in 1984, it remains the best book ever
written on the general topic of programming under Unix.
lines 1-30,67,158-200 myfile
than to put
sed -n -e 1,30p -e 67p -e 158,200p myfile
Lines has one option: -n causes it to
prefix each line with its line number from the original file.
lines -h
Lineup is useful for tidying up the output from a script into an easily readable format.
lineup -h
Maillog's capabilities are perhaps best show by example:
maillog to#jeepers from#creepers syslog
maillog { to#june or to#july } and from#august syslog
maillog to#jen 'date==Apr 19 3:17' syslog
maillog to#lil from#abner \
{ 'date==today' or 'date==Mar 20' or 'date>Apr 3 3:17' } syslog
% maillog from#smith 'date >= jun 5' \
'date < jun 5 08:12' syslog
Message : IAA07301 1.506 sunup date Jun 5 08:10:10 1.506 sunup from smith 1.512 sunup date Jun 5 08:10:15 1.512 sunup to svasq@sci.gmt.carney.nowhere 1.512 sunup ctladdr smith (87/200) 1.512 sunup stat Sent (IAA01006 Message accepted for delivery)
Message : IAA01006 1.511 helipad date Jun 5 08:05:56 1.511 helipad fromHere, host sunup accepted a message from user smith (line 506 in the syslog file), and used host helipad as a relay (line 512; the relay field wasn't printed because this is not a verbose listing), and the stat field shows that helipad's message queue id for the message is IAA01006. At line 511, host helipad accepted the message. (Clearly, helipad's and sunup's clocks are badly skewed, since helipad says that it accepted the message about 4 minutes before sunup says that it sent the message). Four seconds after accepting the message, helipad recorded that the message was undeliverable because "User unknown" (line 513).1.513 helipad date Jul 5 08:06:00 1.513 helipad to 1.513 helipad ctladdr (87/200) 1.513 helipad stat User unknown 1.514 helipad date Jul 5 08:06:01 1.514 helipad notes IAA01014: DSN: User unknown
PATH
variables.
Mklinks is a tool for creating the flocks of symlinks that point back to the real files. It is longer than some other scripts that do a similar job, but that is because it does much more robust error-checking and plausibility-checking.
mklinks -h
Nm is a command to display the symbol table of object files or libraries. However, its output is quite verbose, and it doesn't supply a means of listing just the entries that refer to a particular symbol. Nmsearch combines nm with grep to limit the output to stuff matching a particular grep pattern.
This is quite helpful when your linker has complained that some
symbol can't be found, and you need to figure out what library
is missing from your link line.
For example, here is a command line to find the library
that defines BigPush
:
$ nmsearch BigPush /usr/lib/*.a /usr/lib/*.sl /usr/lib/libcompface.a 00000040 T BigPush U BigPush
nmsearch -h
...which is nothing more than:
pathrelay -mode "19200,odd,8,1" /dev/ttyS0 \ -allow "192.168.*.*" 1234
Pdiff has a lot of options so that you can arrange the output to be as visually useful as possible. See pdiff -h for all the options.
pdiff -h
The special printer names local or attached mean to print the detailed description of all locally-attached printers, ie printers for which there is no rm field, or for which there is a bsdaddr field that matches our host.
The script also contains an English description of most fields
in a printcap file, so it's easy to understand the
entry. For example, the following entry:
hp04|color2|inkcolor|hpdj1600|HP DeskJet 1600CM Color Printer:\
:lp=/dev/hp04:sd=/var/spool/printers/hp04:\
:lf=/var/adm/hp04-errs:af=/var/adm/hp04-acct:\
:mx#0:if=/opt/transcript/lib/psif:gf=/opt/transcript/lib/psgf:\
:nf=/opt/transcript/lib/psnf:tf=/opt/transcript/lib/pstf:\
:rf=/opt/transcript/lib/psrf:vf=/opt/transcript/lib/psvf:\
:cf=/opt/transcript/lib/pscf:df=/opt/transcript/lib/psdf:
would be displayed as:
hp04 (color2, inkcolor, hpdj1600):
HP DeskJet 1600CM Color Printer
lp=/dev/hp04 # Device name to open for output.
sd=/var/spool/printers/hp04 # Spool directory.
lf=/var/adm/hp04-errs # Error-logging filename.
af=/var/adm/hp04-acct # Name of accounting file
mx#0 # Max file size, in BUFSIZ blks. 0=inf.
if=/opt/transcript/lib/psif # Name of text filter that does accounting.
gf=/opt/transcript/lib/psgf # Graph data filter (plot format).
nf=/opt/transcript/lib/psnf # Ditroff data filter.
tf=/opt/transcript/lib/pstf # Troff data filter.
rf=/opt/transcript/lib/psrf # Filter for FORTRAN style text files.
vf=/opt/transcript/lib/psvf # Raster image filter.
cf=/opt/transcript/lib/pscf # The cifplot data filter.
df=/opt/transcript/lib/psdf # Tex data filter (DVI format).
printers -h
Rpn's use will be familiar to users of HP's RPN calculators; if you like those calculators, you may well like rpn; otherwise, don't bother looking at it. I find it quicker to use than the calculators normally available on Unixen.
Rpn has a rich set of operators, including both bitwise and the usual mathematical operators (including most of the standard C math library). You can also define variables and macros, and execute procedures that have been stored in a file.
....+....1....+....2....+....3..
all the way across the width of the screen. The -o option
tells it to overwrite the command line, which is handy when you want
a ruler to appear immediately underneath some text that was just
printed.
I find it useful to define a vi macro to invoke the ruler command. My .exrc file contains the following line:
:map ^R :r! ruler ^M
where ^R is a literal control-R, and ^M is a literal
Return (you can enter these in vi by using
cntl-v cntl-r
and
cntl-v cntl-m
, respectively).
Then, typing ^R creates a ruler just below the cursor.
Of course, you could skip the ruler script and instead
put a line similar to the following in your .exrc file:
:map ^R o....+....1....+....2....+....3... (etc) ESC
(here, ESC is a literal escape), but in that case you get a
fixed-length ruler instead of one that will matches the width
of the screen.
(The shell script itself spends most of its time figuring out the
screen width. This is tedious because stty comes in
two very different flavors which are very different in the way they
can be embedded in command substitution, and because there are at
least three major ways of formatting the stty output.)
ruler -h
% grep somestring `sets *.c -not xxx.c`
The general format is
sets e1... op1 e2... op2 e3...
where op's are operators and e's are any
elements not in the operator list.
The output is the elements formed by evaluating the
operators left-to-right.
The valid operators are:
sets
(without any arguments)
The functions are:
arg
N words returns the
N'th word. For example,
arg 3 a b c d e
returns "c".
findcommand
cmd
looks for cmd in your PATH. It returns the
path if cmd exists, else an empty string.
Example:
# Start vnc server if it is avail.
test `findcommand vncserver` != "" && vncserver ...
testbool value
sets the status to 0 if
the value is true, else 1. Useful for testing the value
of prompt strings:
echo -n "Proceed (y/n)? " ; read ans
if [ testbool "$ans" ] ; then
...
fi
colonjoin words
joins all the words
arguments together with colons. This makes it easy to convert a list
of space-separated paths (which are therefore easy to read and edit)
to a proper colon-separated path:
PATH="a b c ..."
PATH="$PATH d e f ..."
...
PATH=`colonjoin $PATH`
source
file) or sh
(.
file).
You just fill in a section with whatever Bourne-shell code you desire, and the template code handles the magic to let you source it from either kind of shell.
As a result, you can write a single Bourne-shell file to provide a common environment for a suite of shell scripts that may be written in both csh and sh. (Perhaps you are thinking that while this is a pretty cool trick, it is even more amazing that anyone would want to write scripts in csh, but let's just call that one of the mysteries of life.)
sps -h
Warning: the price of these enhancements is that no range-checking is done!
The extensions include:
-DALLOW_0B
, the
prefix 0b
or 0B
means
a base-2 number (e.g. 0b1101 means 13).
bX%
'', where X is from [2-9a-zA-Z],
gives the base. For example,
b9%17
means 17 base 9 = 16.
extern
variable
strtox_allow_arith
is set
to a non-zero value, then the suffix [-+/*%]nnn
means to carry out the corresponding arithmetic operation
(e.g. 20+4 means 24).
Any number of extensions can be applied; they are all evaluated left-to-right. For example, 20e3+4*6 means 120024.
Sample uses:
operatorgroup) complete root access to sets of selected commands such as, say, line-printer control commands, without giving away access to other commands, and with full logging of all commands used.
Example 1:
timetransfer file1 file2
transfers the mtime from file1 to file2.
Example 2:
timetransfer +86400 file1 file1
increases the mtime of file1 by 1 day (86400 seconds).
titlebar [-tty] text
e.g.
titlebar this is a title
treedu -h
trim -h
Which is a bit dumb about the shell flavor: if your login shell ends with csh, it assumes that you are currently using a C-shell (or variant); otherwise, it assumes that your current shell is Bourne shell (or variant).
Which checks for aliases by executing a copy of your login shell, and checking the aliases that are defined in that shell. It then checks each directory in your current PATH.
Example 1: check which rdist commands are available:
% Which rdist /opt/bin/rdist /usr/local/bin/rdist /usr/bin/rdist
Example 2: list all commands with dist in the name:
% Which "*dist*" /opt/bin/rdistd /opt/bin/rdist /u/will/bin/dupdir.rdist /opt/bin/rdistd /opt/bin/rdist /opt/share/bin/sdist /opt/share/etc/distrib /opt/share/etc/sdist_ssh /opt/share/etc/cron.dist /usr/local/bin/rdistd /usr/local/bin/rdist /usr/sbin/rdistd /usr/bin/ppmdist /usr/bin/dist /usr/bin/rdist /usr/bin/rdistd
will@ucolick.org