[alt.sources.d] Multiple executables in path

mleisher@nmsu.edu (Mark Leisher) (01/19/91)

Tom's Perl script reminded me of a program I have that hasn't been
posted for a while.

Here's a program called which5 by Maarten Litmaath that is
particularly fast at finding executables that occur more than once in
a path.
---- Cut Here and feed the following to sh ----
#!/bin/sh
# This is a shell archive (produced by shar 3.49)
# To extract the files from this archive, save it to a file, remove
# everything above the "!/bin/sh" line above, and type "sh file_name".
#
# made 01/18/1991 23:55 UTC by mleisher@nmsu.edu
# Source directory /thrinakia1/mleisher/c_stuff
#
# existing files will NOT be overwritten unless -c is specified
#
# This shar contains:
# length  mode       name
# ------ ---------- ------------------------------------------
#    169 -rw-rw-r-- which5/Makefile
#   2384 -rw-rw-r-- which5/which.1
#   5142 -rw-rw-r-- which5/which5.c
#
# ============= which5/Makefile ==============
if test ! -d 'which5'; then
    echo 'x - creating directory which5'
    mkdir 'which5'
fi
if test -f 'which5/Makefile' -a X"$1" != X"-c"; then
	echo 'x - skipping which5/Makefile (File already exists)'
else
echo 'x - extracting which5/Makefile (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'which5/Makefile' &&
# Makefile for /usr/local/bin/which
X
which:		which5.c
X		cc -O which5.c -o which
X
install:	which
X		/bin/mv -f which /usr/local/bin
X
doc:
X		nroff -man which.1 > which.man
SHAR_EOF
chmod 0664 which5/Makefile ||
echo 'restore of which5/Makefile failed'
Wc_c="`wc -c < 'which5/Makefile'`"
test 169 -eq "$Wc_c" ||
	echo 'which5/Makefile: original size 169, current size' "$Wc_c"
fi
# ============= which5/which.1 ==============
if test -f 'which5/which.1' -a X"$1" != X"-c"; then
	echo 'x - skipping which5/which.1 (File already exists)'
else
echo 'x - extracting which5/which.1 (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'which5/which.1' &&
.TH WHICH 1 Apr\ 04\ 1990
.SH NAME
which \- give alias, function or path expansion of command
.SH SYNOPSIS
.B which
[
.B \-i
] [
.B \-a
] [
.B \-\-
] [
.I command
]
.SH DESCRIPTION
.I Which
provides the user with the full expansion of the
.I command
argument, be it either an \fIalias\fR, a \fIshell function\fR
or an executable file (default). To enable search for
.I aliases
and \fIshell functions\fR
the user should supply the `\fI\-i\fR'
(= interactive) flag. In that case
.I which
expects as standard input the expansion of the \fIalias\fR
or \fIshell function\fR.
If the standard input is empty or the `\fI\-i\fR' flag has not been
given, \fIwhich\fR will try to locate \fIcommand\fR
in the user's \fBPATH\fR.
The interactive mode is easily used by setting an
.I alias
like the following:
.ft B
.nf
X
X	alias	which	alias !\\$ \\| /usr/local/bin/which \-i !\\*
X
.fi
.ft R
in \fIcsh\fR, or
.ft B
.nf
X
X	alias	which	eval alias '\\"\\$$#\\" |' \\
X			/usr/local/bin/which \-i '${1+"$@"}'
X
.fi
.ft R
in shells which are supersets of
.I sh
and which know \fIaliases\fR. If your shell has \fIshell functions\fR, you
can use the following function:
.ft B
.nf
X
X	which()
X	{
X		eval last=\\"\\$$#\\"
X		set | sed \-n "/^$last(){$/,/^}$/p" |
X			/usr/local/bin/which \-i ${1+"$@"}
X	}
X
.fi
.ft R
If the `\fI\-a\fR' (= all) flag is given,
.I which
will not stop after the first `match', but search for all occurrences of
.I command
in the user's
.B PATH.
The `\fI\-\-\fR'
flag can be used to end the list of options: the next argument (if present)
will be taken as \fIcommand\fR, even if it starts with a `\-'.
\fIWhich [\-i] [\-a] [\-\-]\fR
without further arguments prints the user's
.B PATH
broken up into its components,
one per line.
.PP
This new version of the
.I which
command is not a
.I csh
script.
Being an executable it is much faster, and not sourcing 
.I .cshrc
it gives a true picture of one's
.I aliases.
Furthermore it will give the correct answers even if:
.IP \-
the \fIeffective uid\fR
(\fIgid\fR) differs from the \fIreal\fR uid (gid)
.IP \-
the effective uid is 0 (\fIroot\fR).
.SH EXAMPLE
.ft B
.nf
% alias
which	alias !$ | /usr/local/bin/which \-i !*
% which which
which	alias !$ | /usr/local/bin/which \-i !*
% which \-a which
which	alias !$ | /usr/local/bin/which \-i !*
/usr/local/bin/which
/usr/ucb/which
%
.fi
.ft R
.SH AUTHOR
Maarten Litmaath @ VU Informatika Amsterdam
SHAR_EOF
chmod 0664 which5/which.1 ||
echo 'restore of which5/which.1 failed'
Wc_c="`wc -c < 'which5/which.1'`"
test 2384 -eq "$Wc_c" ||
	echo 'which5/which.1: original size 2384, current size' "$Wc_c"
fi
# ============= which5/which5.c ==============
if test -f 'which5/which5.c' -a X"$1" != X"-c"; then
	echo 'x - skipping which5/which5.c (File already exists)'
else
echo 'x - extracting which5/which5.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'which5/which5.c' &&
/*
X * which [-i] [-a] [--] [<command>]
X * alias which alias !\$ \| /usr/local/bin/which -i !\*
X * alias which 'eval alias \$$# | /usr/local/bin/which -i ${1+"$@"}'
X * which()
X * {
X *	eval last=\"\$$#\"
X *	set | sed -n "/^$last(){$/,/^}$/p" |
X *		/usr/local/bin/which -i ${1+"$@"}
X * }
X *
X * Author: Maarten Litmaath @ VU University Amsterdam (maart@cs.vu.nl)
X * First change:
X *	Emile LeBlanc (leblanc%math.Berkeley.EDU@ucbvax.berkeley.edu) notes
X *	the access() system call considering everything executable for
X *	root (!), so we give root a special treatment.  :-(
X *	`which', `which -i' and `which -a' with no further arguments now
X *	return the PATH environment variable, split up into its components.
X *	The aliases defined above are slightly different from the previous
X *	version - now it's the shell who's doing the alias checking.
X * Second change:
X *	Added support for shell functions and multiline aliases, added the
X *	`--' option, changed the source style.
X * Third change:
X *	To hell with access()!
X *	Now stat() is used to give the right answer even if the effective
X *	uid (gid) differs from the real uid (gid).
X *	We can't use setuid(geteuid()), because that's nonportable.  :-(
X * Fourth change:
X *	Jim Meyering <meyering@cs.utexas.edu> notes convert() will clobber
X *	the stack if the PATH is longer than BUF_SIZE - 1 characters.
X *	I've changed convert() altogether to return a path vector (cf. argv),
X *	whose components are the respective directories in the PATH.
X *	Furthermore in printing the PATH there are no trailing colons anymore.
X */
X
#include	<sys/types.h>
#include	<sys/stat.h>
#include	<stdio.h>
X
#define		BUF_SIZE	512
#define		M_USR		0700
#define		M_GRP		0070
#define		M_OTH		0007
#define		X_ALL		0111
#define		R_ALL		0444
X
char	Version[] =
X	"@(#)which 5.0 90/03/24 Maarten Litmaath @ VU Informatika Amsterdam";
char	*Prog;
X
X
void	usage()
{
X	fprintf(stderr, "Usage: %s [-i] [-a] [--] [<command>]\n", Prog);
X	exit(1);
}
X
X
main(argc, argv) 
int	argc;
register char	**argv;
{
X	register char	*path, *s, **pathv, **p;
X	char	*strcpy(), *getenv(), *fgets(), buf[BUF_SIZE], **convert();
X	int	all = 0, inter = 0, stop = 0, found = 0, uid, gid, mask,
X		xmask, rmask;
X	struct	stat	st;
X	void	usage();
X
X
X	Prog = *argv++;
X	--argc;
X
X	while (!stop && (s = *argv) && (*s == '-')) {
X		++argv;
X		--argc;
X		++s;
X		while (*s)
X			switch (*s++) {
X			case 'a':
X				all = 1;
X				break;
X			case 'i':
X				inter = 1;
X				break;
X			case '-':
X				stop = 1;
X				break;
X			default:
X				usage();
X			}
X	}
X
X	if (argc > 1)
X		usage();
X
X	if (inter && *argv) {
X		while (fgets(buf, sizeof buf, stdin)) {
X			if (!found) {
X				printf("%s", *argv);
X				found = 1;
X			}
X			printf("\t%s", buf);
X		}
X		if (found && !all)
X			exit(0);
X	}
X
X	if (!(path = getenv("PATH"))) {
X		fprintf(stderr, "%s: no PATH in environment!\n", Prog);
X		exit(1);
X	}
X
X	if (!*path)
X		path = ".";		/* another dubious convention */
X
X	pathv = convert(path);		/* convert path string to vector */
X
X	if (!*argv) {			/* print path if no more arguments */
X		while (*pathv)
X			puts(*pathv++);
X		exit(0);
X	}
X
X	uid = geteuid();
X	gid = getegid();
X	if (uid == 0) {
X		xmask = X_ALL;
X		rmask = R_ALL;
X	}
X
X	for (p = pathv; path = *p++; ) {	/* try every component */
X		s = buf;
X		while (*s++ = *path++)
X			;
X		(void) strcpy(s, *argv);
X		*--s = '/';
X
X		if (stat(buf, &st) != 0 || (st.st_mode & S_IFMT) != S_IFREG)
X			continue;
X
X		/* file exists and is regular */
X
X		if (uid != 0) {
X			mask = st.st_uid == uid ? M_USR :
X				st.st_gid == gid ? M_GRP : M_OTH;
X			xmask = X_ALL & mask;
X			rmask = R_ALL & mask;
X		}
X
X		if (!(st.st_mode & xmask))
X			continue;
X
X		/* file is executable */
X
X		*s = 0;
X		if (stat(buf, &st) != 0) {
X			perror(buf);
X			continue;
X		}
X
X		if (!(st.st_mode & rmask)) {
X			fprintf(stderr,
X				"%s: %s found in unreadable directory %s!\n",
X				Prog, *argv, buf);
X			found = 1;
X			continue;
X		}
X
X		/* directory is readable */
X
X		*s = '/';
X		puts(buf);
X		if (!all)
X			exit(0);
X		found = 1;
X	}
X
X	if (found)
X		exit(0);
X
X	fprintf(stderr, "%s not found in:\n", *argv);
X	while (*pathv)
X		fprintf(stderr, "%s\n", *pathv++);
X	exit(1);
}
X
X
char	**convert(path)
char	*path;
{
X	register char	*s, c;
X	register int	pathc;		/* the length of the path vector */
X	char	**v, **pathv, *malloc();
X
X	for (s = path, pathc = 2; c = *s++; )
X		if (c == ':')
X			++pathc;
X
X	if (!(pathv = (char **) malloc(pathc * sizeof(char *)))) {
X		perror("malloc");
X		exit(1);
X	}
X
X	for (s = path, v = pathv; (c = *s) != '\0'; ) {
X		if (c == ':') {
X			/*
X			 * This colon is spurious.  According to some
X			 * dubious convention it is made equivalent to a dot.
X			 */
X			*v++ = ".";
X			if (*++s == '\0')
X				*v++ = ".";
X				/*
X				 * The PATH ended in a spurious colon.
X				 * To be consistent we add another dot
X				 * to the path vector.  One day you'll
X				 * be glad we did.
X				 */
X		} else {
X			*v++ = s;
X			while ((c = *++s) != '\0')
X				if (c == ':') {
X					*s++ = '\0';
X					if (*s == '\0')
X						*v++ = ".";
X						/*
X						 * The PATH ended in a
X						 * (spurious) colon, so
X						 * add dot to the vector.
X						 */
X					break;
X				}
X		}
X	}
X
X	*v = 0;		/* Signal the end of the path vector. */
X
X	return pathv;
}
SHAR_EOF
chmod 0664 which5/which5.c ||
echo 'restore of which5/which5.c failed'
Wc_c="`wc -c < 'which5/which5.c'`"
test 5142 -eq "$Wc_c" ||
	echo 'which5/which5.c: original size 5142, current size' "$Wc_c"
fi
exit 0
-----------------------------------------------------------------------------
mleisher@nmsu.edu                      "I laughed.
Mark Leisher                                I cried.
Computing Research Lab                          I fell down.
New Mexico State University                        It changed my life."
Las Cruces, NM                     - Rich [Cowboy Feng's Space Bar and Grille]

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (01/19/91)

Hmmm. I've always been satisfied with the speed of

  alias which 'echo `echo "$PATH" | tr : '\''\012'\'' | sed -e '\''s+$+/\!:1+'\'' -e '\''s:^:/.[.]:'\''` | sed '\''s:/../:/:g'\'''

---Dan

tchrist@convex.COM (Tom Christiansen) (01/19/91)

From the keyboard of brnstnd@kramden.acf.nyu.edu (Dan Bernstein):
:Hmmm. I've always been satisfied with the speed of
:
:  alias which 'echo `echo "$PATH" | tr : '\''\012'\'' | sed -e '\''s+$+/\!:1+'\'' -e '\''s:^:/.[.]:'\''` | sed '\''s:/../:/:g'\'''

But it doesn't do the same thing as mine does, Dan.  Yours is more like this:

    for $file (@ARGV) {
	for $dir (split(/:/,$ENV{'PATH'})) {
	    print $path,"\n" if -x ($path="$dir/$file");
	} 
    }

except that it uses many more processes, runs more slowly, and is 
significantly more difficult to read and thus maintain.

But as I said, the original code does something different: it doesn't just
tell you which paths lead to a particular command.  Rather, it produces a
complete list of all commands in your $PATH with more than one path to
them, except for those duplicates that are just there due to symlinks to
the same executable and by the same name, such as /etc/foo ->
/usr/etc/foo.  That's why the $files{$name, $dev, $ino} array is kept.  I
doubt you can do the last part with a csh alias, and even if you could, I
wouldn't want to try to make sense out of it, unless of course it just
pointed to my script. :-)

--tom
--
"Hey, did you hear Stallman has replaced /vmunix with /vmunix.el?  Now
 he can finally have the whole O/S built-in to his editor like he
 always wanted!" --me (Tom Christiansen <tchrist@convex.com>)

tchrist@convex.COM (Tom Christiansen) (01/19/91)

Oops -- read the postings out of order, and somehow thought Dan was
replying to me.  I kinda like Maarten's version in that it catches
aliases.

--tom
--
"Hey, did you hear Stallman has replaced /vmunix with /vmunix.el?  Now
 he can finally have the whole O/S built-in to his editor like he
 always wanted!" --me (Tom Christiansen <tchrist@convex.com>)

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (01/21/91)

In article <1991Jan19.105624.15369@convex.com> tchrist@convex.COM (Tom Christiansen) writes:
> From the keyboard of brnstnd@kramden.acf.nyu.edu (Dan Bernstein):
> :Hmmm. I've always been satisfied with the speed of
> :  alias which 'echo `echo "$PATH" | tr : '\''\012'\'' | sed -e '\''s+$+/\!:1+'\'' -e '\''s:^:/.[.]:'\''` | sed '\''s:/../:/:g'\'''
> But it doesn't do the same thing as mine does, Dan.

I didn't say that it did. Yours produces a result that is useful in only
a limited problem domain, and I don't see why I should write a 35-line
script for a useless result.

> Yours is more like this:
>     for $file (@ARGV) {
> 	for $dir (split(/:/,$ENV{'PATH'})) {
> 	    print $path,"\n" if -x ($path="$dir/$file");
> 	} 
>     }
> except that it uses many more processes, runs more slowly,

I tried the Perl version and the csh version on two different machines.
The csh version uses three execs and four processes, but because tr and
sed are one tenth the size of perl, the perl version is *SLOWER*.

> and is 
> significantly more difficult to read and thus maintain.

Oh? I see ``echo path, colons to newlines, tack argument on end of line
and /.[.] on beginning, glob, trash that beginning ..,'' which makes
perfect sense. The Perl version has all these confusing parenthesization
and quoting conventions, as well as -x. What's -x? Izzat from test?
What's worse, there's no obvious linear flow through the Perl code;
``file'', for example, appears near the beginning and near the end, and
your eyes have to jump all around to trace the data flow.

So the Perl version is slower, takes more memory, and is more difficult
to read and thus maintain. Sounds like a loser to me.

> But as I said, the original code does something different: it doesn't just
> tell you which paths lead to a particular command.  Rather, it produces a
> complete list of all commands in your $PATH with more than one path to
> them,

Yay.

> except for those duplicates that are just there due to symlinks to
> the same executable and by the same name, such as /etc/foo ->
> /usr/etc/foo.  That's why the $files{$name, $dev, $ino} array is kept.  I
> doubt you can do the last part with a csh alias,

Rather than expressing your doubt, why don't you spend thirty seconds
putting together the right combination of ls, rev, and sort to eliminate
your doubt?

---Dan

tchrist@convex.COM (Tom Christiansen) (01/21/91)

Go away, Dan.  The quotes you needed for your solution were gross and nigh
unto illegible.  If you can't follow a simple three-line piece of simple
flow-control, I'm sorry for you.  The quoting is also obvious -- go read
your shell man page about $foo interpolation in double-quoted strings.
The parens make sense if you spend 5 seconds looking at them, thinking
about lists in csh, function calls (split) and the precedence of
assignment statements.  Following the principle of least surprise, -x
is obviously from /bin/test.  My solution really is much faster on my
machine, and provably so.  Some people want to bend over backwards for
slow, convoluted solutions that you have to dick with to get just quite
right; others don't.  You do what you want, I'll do what I want, and so
will everybody else; they'll decide what's better and easier for them.

--tom

MINE:

for $file (@ARGV) {
    for $dir (split(/:/,$ENV{"PATH"})) {
	print "$path\n" if -x ($path="$dir/$file");
    } 
}

DAN'S:

  alias which 'echo `echo "$PATH" | tr : '\''\012'\'' | sed -e '\''s+$+/\!:1+'\'' -e '\''s:^:/.[.]:'\''` | sed '\''s:/../:/:g'\'''

--
"Hey, did you hear Stallman has replaced /vmunix with /vmunix.el?  Now
 he can finally have the whole O/S built-in to his editor like he
 always wanted!" --me (Tom Christiansen <tchrist@convex.com>)

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (01/21/91)

In article <1991Jan21.082717.22130@convex.com> tchrist@convex.COM (Tom Christiansen) writes:
> The quotes you needed for your solution were gross and nigh
> unto illegible.

Illegible? It's not my fault if you haven't written enough shell code to
instantly recognize '\''. Or would you prefer double quoting?

Has it ever occurred to you that if there were a usable Perl shell, then
it would require just as much special quoting as csh aliases do? I could
put the alias into a separate file so that we're on even ground. Still,
if you don't want to figure out the quoting conventions, you can just
feed csh the alias and type ``alias which'' to see the unquoted version:

  echo `echo "$PATH" | tr : '\012' | sed -e 's+$+/!:1+' -e 's:^:/.[.]:'`
    | sed 's:/../:/:g'

C'mon, surely you admit that ``echo path, make colons into newlines, add
argument at end, add /.[.] at beginning, glob, trash /..'' is not only
an exact reading of the command in linear order, but a perfectly
sensible solution. Again, your Perl solution has no obvious linear flow,
and your eyes have to keep jumping around to see where the data goes.

(If you want to put quotes back into an alias, use the ``quote'' and
``makealias'' aliases, which have been running around for quite some
time now. It takes soooo much effort.)

> If you can't follow a simple three-line piece of simple
> flow-control, I'm sorry for you.

It's just not as instantly obvious as the pipeline. I prefer easily
maintainable code with obvious data flaw (and obvious firewalls) to an
unportable, unconventional, ungodly muck.

> The quoting is also obvious -- go read
> your shell man page about $foo interpolation in double-quoted strings.

Right, so $path="$dir/$file" means to find the value of path, interpret
that as the name of an environment variable, and set that to $dir/$file.
'Zactly like the shell.

> The parens make sense if you spend 5 seconds looking at them,

Yeah. That's about 5 seconds too much.

> My solution really is much faster on my
> machine, and provably so.

Yes, your Convex probably has perl running all the time, so it doesn't
have to be loaded from disk. The large address space must help too.

> Some people want to bend over backwards for
> slow, convoluted solutions that you have to dick with to get just quite
> right;

Yeah. Like yours.

---Dan

tchrist@convex.COM (Tom Christiansen) (01/22/91)

From the keyboard of brnstnd@kramden.acf.nyu.edu (Dan Bernstein):
:In article <1991Jan21.082717.22130@convex.com> tchrist@convex.COM (Tom Christiansen) writes:
:> The quotes you needed for your solution were gross and nigh
:> unto illegible.
:
:Illegible? It's not my fault if you haven't written enough shell code to
:instantly recognize '\''. Or would you prefer double quoting?

There's our Dan, who when he cannot win his point on technical merits,
resorts instead to petty, unfounded (and flat-out wrong), ad hominem
attacks laced with deprecating sarcasm in order to belittle the other
party.  Why does it make you feel better to insult other people, Dan?  Is
it because you think so little of yourself you have to put everybody else
down?  If that's your game, why don't you go off to Fidonet or some other
even more puerile bulletin board system where this behavior may be more
expected?  Better yet, go see a good counselor.  Maybe you wouldn't be
posting so much drivel if you hadn't been kicked out of Princeton.  Would
you care to tell us all about that incident, Dan?  And while you're at it,
it would be interesting to learn what is wrong inside of you that makes
you want to convert every newsgroup you touch into a battleground for
petulant, anal-retentive abuse?  What ever did happen to rec.games.rpg
anyway?

:  echo `echo "$PATH" | tr : '\012' | sed -e 's+$+/!:1+' -e 's:^:/.[.]:'`
:    | sed 's:/../:/:g'

:It's just not as instantly obvious as the pipeline. I prefer easily
:maintainable code with obvious data flaw (and obvious firewalls) to an
:unportable, unconventional, ungodly muck.

Data flaw?  There you have it.

Unportable: I think not.  In fact, perl runs on more machines than 
sed and tr.  I've not seen DOS or Macintosh ports of them, let alone
of the shell-from-hell you like to post things in.

Unconventional:  That's what the Fortran programmer said when he
first saw Algol, Pascal, C, etc.  Or if you prefer, the MVS hack
when he saw UNIX.  As you can seen, this argument merely demonstrates
a myopic approach to new and better technology.

Ungodly:  Oh, now *there's* an effective criticism for you.  I'm sure
the whole net will rise up in popular accord for this one.  With gods
on your side, who can stand against you?  

Anything that requires multiple levels of evaluation is more complex than
something that does not.  You are looking at the problem from a "munge the
I/O stream until done" approach, which is often just a crufty hack for
inadequate tools.

Let's sit back and look at the algorithm.  What is really desired here?
It's really much simpler than you've made it out to be.  All that's
needed is to check each component in the user's path for an executable
of that name, and if it exists, print out the full pathname.  That's
surely not an algorithm that's conveyed by your solution, but that's 
all that's needed here.

Here's my solution:

    $file = shift;
    for $dir (split(/:/,$ENV{"PATH"})) {
	print "$path\n" if -x ($path="$dir/$file");
    }

I've not gone to much trouble to obfuscate it, like using && notation:

	-x ($path="$dir/$file") && print "$path\n";

or some greply convolution.

If you want it unraveled a bit because you prefer assignments to stand on
their own and not be used in expressions, you could have this:

    $file = shift;
    for $dir (split(/:/,$ENV{"PATH"})) {
	$path = "$dir/$file";
	if (-x $path) {
	    print "$path\n";
	}
    }

Notice how easily I can deal with multiple arguments by simply slapping
another for loop around everything:

    for $file (@ARGV) {
	for $dir (split(/:/,$ENV{"PATH"})) {
	    print "$path\n" if -x ($path="$dir/$file");
	}
    }

Notice how little confusion is added by adding that functionality.
That's not easily done in csh.  

I'd like to see others' opinions on algorithmic complexity here.  Which 
way is more straightforward?  Bear in mind that Dan's solution, here
reproduced for your inspection:

    alias which 'echo `echo "$PATH" | tr : '\''\012'\'' | sed -e '\''s+$+/\!:1+'\'' -e '\''s:^:/.[.]:'\''` | sed '\''s:/../:/:g'\'''

contains 30 quotes, 9 backslashes, and several levels of evaluation to
worry about.  Of course, in a real shell instead of the abomination cited
above, most of these problems go away:

    function mwhence {
	for file in $*; do
	    for dir in `echo $PATH | tr ':' ' '`; do
		path=$dir/$file
		if [ -x $path ]; then echo $path; fi
		# AKA: test -x $path && echo $path
	    done
	done
    }

For the truly curious, the ksh solution takes 2x time time the perl one
does, probably because of having to call tr.  If I had used the ## or %%
variable munging, I probably could have trimmed this down, but that's not
as succinctly expressed and I didn't feel like playing with it.  It's a
good deal faster than the disgusting csh alias.

We'll see who has to say what here about the shell and the perl algorithm
(which are equivalent) versus the massively piped one.  Of course, a lot
of the UNIX gurus are here in Dallas right now for USENIX, plus a lot more
have given up on the alt hierarchy, and a few have given up on anything
that should really have been posted to alt.flame.dan-bernstein instead.

--tom
--
"Hey, did you hear Stallman has replaced /vmunix with /vmunix.el?  Now
 he can finally have the whole O/S built-in to his editor like he
 always wanted!" --me (Tom Christiansen <tchrist@convex.com>)

monson@diablo.amd.com (Steve Monson) (01/22/91)

In article <1991Jan21.171227.12138@convex.com> tchrist@convex.COM (Tom Christiansen) writes:
>From the keyboard of brnstnd@kramden.acf.nyu.edu (Dan Bernstein):
>:In article <1991Jan21.082717.22130@convex.com> tchrist@convex.COM (Tom Christiansen) writes:
>:> The quotes you needed for your solution were gross and nigh
>:> unto illegible.
>:
>:Illegible? It's not my fault if you haven't written enough shell code to
>:instantly recognize '\''. Or would you prefer double quoting?
>
>There's our Dan, who when he cannot win his point on technical merits,
>resorts instead to petty, unfounded (and flat-out wrong), ad hominem
>attacks laced with deprecating sarcasm in order to belittle the other
>party.  Why does it make you feel better to insult other people, Dan?  Is
>it because you think so little of yourself you have to put everybody else
>down?  If that's your game, why don't you go off to Fidonet or some other
>even more puerile bulletin board system where this behavior may be more
>expected?  Better yet, go see a good counselor.  Maybe you wouldn't be
>posting so much drivel if you hadn't been kicked out of Princeton.  Would
>you care to tell us all about that incident, Dan?  And while you're at it,
>it would be interesting to learn what is wrong inside of you that makes
>you want to convert every newsgroup you touch into a battleground for
>petulant, anal-retentive abuse?  What ever did happen to rec.games.rpg
>anyway?
>
>:  echo `echo "$PATH" | tr : '\012' | sed -e 's+$+/!:1+' -e 's:^:/.[.]:'`
>:    | sed 's:/../:/:g'
>
>:It's just not as instantly obvious as the pipeline. I prefer easily
>:maintainable code with obvious data flaw (and obvious firewalls) to an
>:unportable, unconventional, ungodly muck.
>
>Data flaw?  There you have it.
>
>Unportable: I think not.  In fact, perl runs on more machines than 
>sed and tr.  I've not seen DOS or Macintosh ports of them, let alone
>of the shell-from-hell you like to post things in.
>
>Unconventional:  That's what the Fortran programmer said when he
>first saw Algol, Pascal, C, etc.  Or if you prefer, the MVS hack
>when he saw UNIX.  As you can seen, this argument merely demonstrates
>a myopic approach to new and better technology.
>
>Ungodly:  Oh, now *there's* an effective criticism for you.  I'm sure
>the whole net will rise up in popular accord for this one.  With gods
>on your side, who can stand against you?  
>
>Anything that requires multiple levels of evaluation is more complex than
>something that does not.  You are looking at the problem from a "munge the
>I/O stream until done" approach, which is often just a crufty hack for
>inadequate tools.
>
>Let's sit back and look at the algorithm.  What is really desired here?
>It's really much simpler than you've made it out to be.  All that's
>needed is to check each component in the user's path for an executable
>of that name, and if it exists, print out the full pathname.  That's
>surely not an algorithm that's conveyed by your solution, but that's 
>all that's needed here.
>
>Here's my solution:
>
>    $file = shift;
>    for $dir (split(/:/,$ENV{"PATH"})) {
>	print "$path\n" if -x ($path="$dir/$file");
>    }
>
>I've not gone to much trouble to obfuscate it, like using && notation:
>
>	-x ($path="$dir/$file") && print "$path\n";
>
>or some greply convolution.
>
>If you want it unraveled a bit because you prefer assignments to stand on
>their own and not be used in expressions, you could have this:
>
>    $file = shift;
>    for $dir (split(/:/,$ENV{"PATH"})) {
>	$path = "$dir/$file";
>	if (-x $path) {
>	    print "$path\n";
>	}
>    }
>
>Notice how easily I can deal with multiple arguments by simply slapping
>another for loop around everything:
>
>    for $file (@ARGV) {
>	for $dir (split(/:/,$ENV{"PATH"})) {
>	    print "$path\n" if -x ($path="$dir/$file");
>	}
>    }
>
>Notice how little confusion is added by adding that functionality.
>That's not easily done in csh.  
>
>I'd like to see others' opinions on algorithmic complexity here.  Which 
>way is more straightforward?  Bear in mind that Dan's solution, here
>reproduced for your inspection:
>
>    alias which 'echo `echo "$PATH" | tr : '\''\012'\'' | sed -e '\''s+$+/\!:1+'\'' -e '\''s:^:/.[.]:'\''` | sed '\''s:/../:/:g'\'''
>
>contains 30 quotes, 9 backslashes, and several levels of evaluation to
>worry about.  Of course, in a real shell instead of the abomination cited
>above, most of these problems go away:
>
>    function mwhence {
>	for file in $*; do
>	    for dir in `echo $PATH | tr ':' ' '`; do
>		path=$dir/$file
>		if [ -x $path ]; then echo $path; fi
>		# AKA: test -x $path && echo $path
>	    done
>	done
>    }
>
>For the truly curious, the ksh solution takes 2x time time the perl one
>does, probably because of having to call tr.  If I had used the ## or %%
>variable munging, I probably could have trimmed this down, but that's not
>as succinctly expressed and I didn't feel like playing with it.  It's a
>good deal faster than the disgusting csh alias.
>
>We'll see who has to say what here about the shell and the perl algorithm
>(which are equivalent) versus the massively piped one.  Of course, a lot
>of the UNIX gurus are here in Dallas right now for USENIX, plus a lot more
>have given up on the alt hierarchy, and a few have given up on anything
>that should really have been posted to alt.flame.dan-bernstein instead.
>
>--tom
>--
>"Hey, did you hear Stallman has replaced /vmunix with /vmunix.el?  Now
> he can finally have the whole O/S built-in to his editor like he
> always wanted!" --me (Tom Christiansen <tchrist@convex.com>)

#!/bin/csh

#As a matter of fact, you can do in csh just what you did in perl. I'm not
#a csh fanatic, but I remember how much I liked it over the Bourne shell,
#with its aliases and history, etc. In this example:

set file=$1
foreach dir ($path)
  if ( -x $dir/$file ) echo $dir/$file
end

#or, to add multiple arguments on the command line:

foreach arg ($argv)
  set file=$arg
  foreach dir ($path)
    if ( -x $dir/$file ) echo $dir/$file
  end
end

#The offending one-liner is a bit obscure, I admit, but then one-line mania
#is usually prone to generation of convoluted expressions. The nice thing
#about sh, ksh, perl is that the loops can be put on a single line if you
#want, but csh makes you split it up into multiple lines, making an alias
#impossible.

# But even with a one-liner, it's not as bad as that horribly convoluted
# example that was posted:

ls -1 {`echo $PATH|tr ':' ','`}/$1 |& grep -v 'not found'

# or, with multiple arguments:

foreach arg ($argv)
  ls -1 {`echo $PATH|tr : ,`}/$arg |& grep -v 'not found'
end
It's not whether you win or lose

It's whether *I* win or lose.

maart@cs.vu.nl (Maarten Litmaath) (01/22/91)

In article <17373:Jan1908:30:3191@kramden.acf.nyu.edu>,
	brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:
)Hmmm. I've always been satisfied with the speed of

[_Excessively_ long line split.]

)  alias which 'echo `echo "$PATH" | tr : '\''\012'\'\
)  ' | sed -e '\''s+$+/\!:1+'\'' -e '\''s:^:/.[.]:'\'\
)  '` | sed '\''s:/../:/:g'\'''

This alias doesn't deal with aliases (easily fixed), but most importantly
it _fails_.  Two examples:

	% which passwd
	/bin/passwd /usr/bin/passwd /etc/passwd

	# How odd: /etc/passwd is executable!

	% set path=($path .)
	% cp /bin/true foo
	% which foo


	# Silence.

Had you read the documentation of `which5', you would have known it's not
that trivial to get things right.
--
kinnersley@kuhub.cc.ukans.edu (Bill Kinnersley):
	"Do phonograph turntables turn the other way in Australia?"
gjh@krebs.acc.Virginia.EDU (Galen J. Hekhuis)
	"How do you think satanic messages were discovered on records?"

kaul@icarus.eng.ohio-state.edu (Rich Kaul) (01/22/91)

In article <1991Jan21.171227.12138@convex.com> tchrist@convex.COM (Tom Christiansen) writes:
   Here's my solution:

       $file = shift;
       for $dir (split(/:/,$ENV{"PATH"})) {
	   print "$path\n" if -x ($path="$dir/$file");
       }
   [ ... ]
   I'd like to see others' opinions on algorithmic complexity here.  Which 
   way is more straightforward?

After seeing Dan's solution, either the perl code or the ksh script
are far simpler to maintain for most users.  I would hate to give that
alias to some naive user.  The first time he looked at his list of
aliases and wanted an explaination of what that alias did would take a
lot of educating in slightly more obsure things than most users need
to know -- and it's more time that I have to spend on such things.
Besides, I have a soft spot for perl ;-)

Also, I should mention that none of the the above solutions work well
with bash, where you can have a PATH with unexpanded ~ references in
the PATH environment variable.  There are other tricks you have to
play on that shell to get these scripts to work.
-- 
Rich Kaul                         | Every man is given the key to the door
kaul@icarus.eng.ohio-state.edu    | of heaven; unfortunately, the same key
or ...!osu-cis!kaul		  | opens the door to hell.

tchrist@convex.COM (Tom Christiansen) (01/22/91)

From the keyboard of kaul@icarus.eng.ohio-state.edu (Rich Kaul):
:Also, I should mention that none of the the above solutions work well
:with bash, where you can have a PATH with unexpanded ~ references in
:the PATH environment variable.  There are other tricks you have to
:play on that shell to get these scripts to work.

That's odd -- if you have unexpanded tildes in your environment,
I wonder how you get system, popen, and execlp to work without
changing the C library.

--tom
--
"Hey, did you hear Stallman has replaced /vmunix with /vmunix.el?  Now
 he can finally have the whole O/S built-in to his editor like he
 always wanted!" --me (Tom Christiansen <tchrist@convex.com>)

pfalstad@phoenix.Princeton.EDU (Paul Falstad) (01/22/91)

tchrist@convex.COM (Tom Christiansen) wrote:
>From the keyboard of kaul@icarus.eng.ohio-state.edu (Rich Kaul):
>:with bash, where you can have a PATH with unexpanded ~ references in
>That's odd -- if you have unexpanded tildes in your environment,
>I wonder how you get system, popen, and execlp to work without
>changing the C library.

You don't, it seems.  At least it didn't work for me.  This is probably
a bug in bash.  You should use $HOME instead of ~ when you define
your PATH.

--
Paul Falstad, pfalstad@phoenix.princeton.edu PLink:HYPNOS GEnie:P.FALSTAD
In the heat of composition I find that I have inadvertently allowed
myself to assume the form of a large centipede.  I am accordingly
dictating the rest to my secretary.

kaul@icarus.eng.ohio-state.edu (Rich Kaul) (01/23/91)

In article <5570@idunno.Princeton.EDU> pfalstad@phoenix.Princeton.EDU (Paul Falstad) writes:
   tchrist@convex.COM (Tom Christiansen) wrote:
   >From the keyboard of kaul@icarus.eng.ohio-state.edu (Rich Kaul):
   >:with bash, where you can have a PATH with unexpanded ~ references in
   >That's odd -- if you have unexpanded tildes in your environment,
   >I wonder how you get system, popen, and execlp to work without
   >changing the C library.

   You don't, it seems.  At least it didn't work for me.  This is probably
   a bug in bash.  You should use $HOME instead of ~ when you define
   your PATH.

Hmmm, I beg to disagree.  Also, $HOME is not appropriate when
searching another user's directory, cf:

Script started on Tue Jan 22 08:45:16 1991
bash$ echo $PATH
/usr/1/kaul/bin:/usr/1/kaul/bin/sun3:/usr/bin/X11:/usr/local/gnu/bin:/usr/local/bin:~octtools/bin:~cad/bin:/usr/ucb:/usr/bin:/usr/etc:.
bash$ which magic
/usr/1/cad/bin/magic
bash$ magic

Magic - Version 6.3 - Last updated Thu Sep 13 13:21:25 PDT 1990  

Using technology "scmos".

> :quit
bash$ exit
exit

script done on Tue Jan 22 08:46:09 1991

(saying ~cad/bin/magic gives the same result).  Bash does the
expansion of the ~ before running the program.  It is possible to
force the expansions manually, but that's usually more work than
desired.  Besides, the ~ in bash has more functions than the
equivalent ~ in csh (see Chet Ramey's bash man page for more
information).

Obligatory plug for bash: it's worth it.  It's a very nice shell, with
full emacs editing and very good vi editing if that's your dialect.
It's certainly more fun than tcsh, which I used before, and has a more
POSIX-ified behavior.  There are still some bugs, although Chet's
version is nearly bug free, and version 1.06 is long overdue.  I liked
it so much, I use the shell (or something to that effect).
-- 
Rich Kaul                         | Every man is given the key to the door
kaul@icarus.eng.ohio-state.edu    | of heaven; unfortunately, the same key
or ...!osu-cis!kaul		  | opens the door to hell.

chet@odin.INS.CWRU.Edu (Chet Ramey) (01/23/91)

In article <5570@idunno.Princeton.EDU> pfalstad@phoenix.Princeton.EDU (Paul Falstad) writes:
>tchrist@convex.COM (Tom Christiansen) wrote:
>>From the keyboard of kaul@icarus.eng.ohio-state.edu (Rich Kaul):
>>:with bash, where you can have a PATH with unexpanded ~ references in
>>That's odd -- if you have unexpanded tildes in your environment,
>>I wonder how you get system, popen, and execlp to work without
>>changing the C library.
>
>You don't, it seems.  At least it didn't work for me.  This is probably
>a bug in bash.  You should use $HOME instead of ~ when you define
>your PATH.

It's not a bug in bash.  It's bash doing something useful with what
would otherwise be useless.

You have to go through special pains to get an unexpanded tilde in
your PATH, since tilde expansion is performed on the rhs of assignment
statements.  The only way you can get a tilde into your path is to
surround it with quotes.  It might be a bug that double quotes can
inhibit the expansion.

Chet
-- 
Chet Ramey				``There's just no surf in
Network Services Group			  Cleveland, U.S.A. ...''
Case Western Reserve University
chet@ins.CWRU.Edu		My opinions are just those, and mine alone.

pfalstad@phoenix.Princeton.EDU (Paul Falstad) (01/23/91)

kaul@icarus.eng.ohio-state.edu (Rich Kaul) wrote:
>In article <5570@idunno.Princeton.EDU> pfalstad@phoenix.Princeton.EDU (Paul Falstad) writes:
>   tchrist@convex.COM (Tom Christiansen) wrote:
>   >From the keyboard of kaul@icarus.eng.ohio-state.edu (Rich Kaul):
>   >That's odd -- if you have unexpanded tildes in your environment,
>   >I wonder how you get system, popen, and execlp to work without
>   >changing the C library.
>   You don't, it seems.  At least it didn't work for me.  This is probably
>   a bug in bash.  You should use $HOME instead of ~ when you define
>   your PATH.
>Hmmm, I beg to disagree.  Also, $HOME is not appropriate when
>searching another user's directory, cf:

Yes, I know.  You'll have to expand ~name yourself.

>bash$ echo $PATH
>/usr/1/kaul/bin:/usr/1/kaul/bin/sun3:/usr/bin/X11:/usr/local/gnu/bin:/usr/local/bin:~octtools/bin:~cad/bin:/usr/ucb:/usr/bin:/usr/etc:.
>bash$ which magic
>/usr/1/cad/bin/magic
>bash$ magic
>(saying ~cad/bin/magic gives the same result).  Bash does the
>expansion of the ~ before running the program.  It is possible to

Fine, I agree this works.  That's not what Tom was talking about.

Here's a script that demonstrates the problem:  (BIFF is a filter I got
off the net, a la jive)

Script started on Tue Jan 22 18:06:38 1991
Z 1 phoenix:~/pub bash
bash$ PATH=/usr/ucb:/bin:/usr/bin:/usr/princeton/bin:~/bin/sun4
bash$ echo $PATH
/usr/ucb:/bin:/usr/bin:/usr/princeton/bin:~/bin/sun4
bash$ which BIFF
/n/uffda/b/pfalstad/bin/sun4/BIFF
bash$ ls | BIFF
101LAY0UT
CENTREX
CLIENTS
C0MMANDS
KEYREP
MEGAHACK
NEWPH0ENIX
PHXPEF
STRINGS
TYPESCRIPT
VI..REF.  K0WABUNGA D00DZ!!!7
--
BIFF@BIT.NET                                           BIFF@PSUVM.PSU.EDU
BIFF@BIFFVM.BIT.NET                                  BIFF+@ANDREW.CMU.EDU
     BIFF@PSUVM.ANDREW.PORTAL.COM.XZ.US.RUTGERS.ARPA.BITNET.EDU.UUCP
 MAN!WOMAN!BIRTH!DEATH!INFINITI!ROCKS!TREES!BIT.NET!BIFF@UUNET.UU.NET.EDU
--
BIFF@BIT.NET                                           BIFF@PSUVM.PSU.EDU
BIFF@BIFFVM.BIT.NET                                  BIFF+@ANDREW.CMU.EDU
     BIFF@PSUVM.ANDREW.PORTAL.COM.XZ.US.RUTGERS.ARPA.BITNET.EDU.UUCP
 MAN!WOMAN!BIRTH!DEATH!INFINITI!ROCKS!TREES!BIT.NET!BIFF@UUNET.UU.NET.EDU
bash$ mail
"/usr/spool/mail/pfalstad": 1 message 1 new
>N  1 pfalstad           Tue Jan 22 18:07   13/396   foo.
& | BIFF
Pipe to: "BIFF"
/bin/sh: BIFF: not found
"BIFF" 13/396
& q
Saved 1 message in /n/uffda/b/pfalstad/mbox
bash$ PATH=/usr/ucb:/bin:/usr/bin:/usr/princeton/bin:/u/pfalstad/bin/sun4
bash$ mail -f ~/mbox
"/n/uffda/b/pfalstad/mbox": 1 message
>   1 pfalstad           Tue Jan 22 18:07   14/407   foo.
& | BIFF
Pipe to: "BIFF"
FR0M PFALSTAD TUE JAN 22 18:07:27 1991
RECEIVED, L00K AT THIS D00DZ: FRUM B0W.  D0N"T HAVE A K0W!!! (THE SIMPSUNZ AR THU KULEST!)PRINCET0N.  C0WABUNGA!!!EDU BY PH0ENIX.PRINCET0N.  C0WABUNGA!!!EDU (4.1/1.106)
        ID AA08726; TUE, 22 JAN 91 18:07:27 EST
FR0M, L00K AT THIS D00DZ: PAUL FALSTAD <PFALSTAD>
RECEIVED, L00K AT THIS D00DZ: BY B0W.  D0N"T HAVE A K0W!!! (THE SIMPSUNZ AR THU KULEST!)PRINCET0N.  C0WABUNGA!!!EDU (4.1/CS_002_CLUSTUR_CLIENT)
        ID AA02829; TUE, 22 JAN 91 18:07:25 EST
DATE, L00K AT THIS D00DZ: TUE, 22 JAN 91 18:07:25 EST
MESSAGE-ID, L00K AT THIS D00DZ: <9101222307.AA02829@B0W.  D0N"T HAVE A K0W!!! (THE SIMPSUNZ AR THU KULEST!)PRINCET0N.  C0WABUNGA!!!EDU>
T0, L00K AT THIS D00DZ: PFALSTAD
SUBJECT, L00K AT THIS D00DZ: F00.
STATUS, L00K AT THIS D00DZ: R0



--
BIFF@BIT.NET                                           BIFF@PSUVM.PSU.EDU
BIFF@BIFFVM.BIT.NET                                  BIFF+@ANDREW.CMU.EDU
     BIFF@PSUVM.ANDREW.PORTAL.COM.XZ.US.RUTGERS.ARPA.BITNET.EDU.UUCP
 MAN!WOMAN!BIRTH!DEATH!INFINITI!ROCKS!TREES!BIT.NET!BIFF@UUNET.UU.NET.EDU
--
BIFF@BIT.NET                                           BIFF@PSUVM.PSU.EDU
BIFF@BIFFVM.BIT.NET                                  BIFF+@ANDREW.CMU.EDU
     BIFF@PSUVM.ANDREW.PORTAL.COM.XZ.US.RUTGERS.ARPA.BITNET.EDU.UUCP
 MAN!WOMAN!BIRTH!DEATH!INFINITI!ROCKS!TREES!BIT.NET!BIFF@UUNET.UU.NET.EDU
"BIFF" 14/407
& d
& q
"/n/uffda/b/pfalstad/mbox" complete
bash$ Z 2 phoenix:~/pub exit

script done on Tue Jan 22 18:09:56 1991


See the problem?  mail, which uses execlp or popen or some such thing,
can't find BIFF because it doesn't know how to expand ~'s in the path.
I know bash does, but other programs don't.  You either need to fix
the c library or fix bash.

>Obligatory plug for bash: it's worth it.  It's a very nice shell, with
>full emacs editing and very good vi editing if that's your dialect.
>It's certainly more fun than tcsh, which I used before, and has a more
>POSIX-ified behavior.  There are still some bugs, although Chet's
>version is nearly bug free, and version 1.06 is long overdue.  I liked
>it so much, I use the shell (or something to that effect).

I mostly agree, although I'm partial to zsh for some strange reason.  :-)

--
Paul Falstad, pfalstad@phoenix.princeton.edu PLink:HYPNOS GEnie:P.FALSTAD
In the heat of composition I find that I have inadvertently allowed
myself to assume the form of a large centipede.  I am accordingly
dictating the rest to my secretary.

pfalstad@phoenix.Princeton.EDU (Paul Falstad) (01/23/91)

chet@po.CWRU.Edu wrote:
>In article <5570@idunno.Princeton.EDU> pfalstad@phoenix.Princeton.EDU (Paul Falstad) writes:
>>tchrist@convex.COM (Tom Christiansen) wrote:
>>>From the keyboard of kaul@icarus.eng.ohio-state.edu (Rich Kaul):
>>>That's odd -- if you have unexpanded tildes in your environment,
>>>I wonder how you get system, popen, and execlp to work without
>>>changing the C library.
>>You don't, it seems.  At least it didn't work for me.  This is probably
>>a bug in bash.  You should use $HOME instead of ~ when you define
>>your PATH.

>You have to go through special pains to get an unexpanded tilde in
>your PATH, since tilde expansion is performed on the rhs of assignment
>statements.  The only way you can get a tilde into your path is to
>surround it with quotes.  It might be a bug that double quotes can
>inhibit the expansion.

Well, you might have fixed it in the CWRU version, but my version
(1.05.1) has the bug.  Perhaps I need an update.  But I would hardly
call the following script "going through special pains."

Script started on Tue Jan 22 19:48:33 1991
warning: could not update utmp entry
Z 1 phoenix:~/src/zsh echo $PATH
/n/uffda/b/pfalstad/scr:/u/pfalstad/bin/sun4:/usr/princeton/bin:/usr/ucb:/usr/bi
n:/bin:/u/maruchck/scr:/u/cs320/bin:/u/subbarao/bin:/u/maruchck/bin:/usr/hosts:/
usr/princeton/bin/X11:/usr/etc:/etc
Z 2 phoenix:~/src/zsh bash
bash$ echo $PATH
/n/uffda/b/pfalstad/scr:/u/pfalstad/bin/sun4:/usr/princeton/bin:/usr/ucb:/usr/bi
n:/bin:/u/maruchck/scr:/u/cs320/bin:/u/subbarao/bin:/u/maruchck/bin:/usr/hosts:/
usr/princeton/bin/X11:/usr/etc:/etc
bash$ PATH=~/scr:~/bin/sun4:/usr/princeton/bin:/usr/ucb:/usr/bin:/bin:~maruchck
/scr:~cs320/bin:~subbarao/bin:~maruchck/bin:/usr/hosts:/usr/princeton/bin/X11:/
usr/etc:/etc
bash$ echo $PATH
/n/uffda/b/pfalstad/scr:~/bin/sun4:/usr/princeton/bin:/usr/ucb:/usr/bin:/bin:~ma
ruchck/scr:~cs320/bin:~subbarao/bin:~maruchck/bin:/usr/hosts:/usr/princeton/bin/
X11:/usr/etc:/etc
bash$ Z 3 phoenix:~/src/zsh exit

script done on Tue Jan 22 19:49:30 1991


The ~ is expanded only for the first component in the PATH, not for the
remaining components.  Bash handles this fine, of course, but execlp
does not.

--
Paul Falstad, pfalstad@phoenix.princeton.edu PLink:HYPNOS GEnie:P.FALSTAD
In the heat of composition I find that I have inadvertently allowed
myself to assume the form of a large centipede.  I am accordingly
dictating the rest to my secretary.

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (01/23/91)

In article <1991Jan21.171227.12138@convex.com> tchrist@convex.COM (Tom Christiansen) writes:
> From the keyboard of brnstnd@kramden.acf.nyu.edu (Dan Bernstein):
> :In article <1991Jan21.082717.22130@convex.com> tchrist@convex.COM (Tom Christiansen) writes:
> :> The quotes you needed for your solution were gross and nigh
> :> unto illegible.
> :Illegible? It's not my fault if you haven't written enough shell code to
> :instantly recognize '\''. Or would you prefer double quoting?
> There's our Dan, who when he cannot win his point on technical merits,

Objective fact, which anyone who's been reading this discussion can
verify: After ``Or would you prefer double quoting?'' I presented
several technical points in answer to Tom's complaint.

Objective fact: Tom, who to me seems to be more interested in libel than
in rational discussion, failed to quote those points.

I wonder how often Tom perverts the discussion to prove his point?

> Maybe you wouldn't be
> posting so much drivel if you hadn't been kicked out of Princeton.  Would
> you care to tell us all about that incident, Dan?

That is an... interesting... accusation, which, in case anyone cares, I
flat-out deny. I'm perfectly willing to answer questions about my past
that aren't on the moral and intellectual level of ``Have you stopped
beating your wife?''

``So, Tom, maybe you wouldn't be posting so much drivel if you hadn't
been kicked out of Yale. Would you care to tell us all about that
incident, Tom?''

> What ever did happen to rec.games.rpg
> anyway?

The one time I proposed it, it didn't seem feasible, so I didn't call
for votes.

> Unportable: I think not.  In fact, perl runs on more machines than 
> sed and tr.

Objective fact: sed and tr have been ported to MS-DOS and the Mac.
Furthermore, they run on almost every BSD and System V machine. perl
doesn't even come close.

> I've not seen DOS or Macintosh ports of them, let alone
> of the shell-from-hell you like to post things in.

Objective fact: Tom just posted a statement (``perl runs on more
machines than sed and tr'') which is objectively false, and which, if he
had taken the time to check his facts, he would have known to be false.

I wonder how many of Tom's statements are like that.

> Unconventional:  That's what the Fortran programmer said when he
> first saw Algol, Pascal, C, etc.

Fair enough.

> Ungodly:  Oh, now *there's* an effective criticism for you.  I'm sure
> the whole net will rise up in popular accord for this one.  With gods
> on your side, who can stand against you?  

``Gross: Oh, now *there's* an effective criticism for you. I'm sure the
whole net will rise up in popular accord for this one. With un-grossness
on your side, who can stand against you?''

---Dan

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (01/23/91)

In article <8807@star.cs.vu.nl> maart@cs.vu.nl (Maarten Litmaath) writes:
> In article <17373:Jan1908:30:3191@kramden.acf.nyu.edu>,
> 	brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:
> )Hmmm. I've always been satisfied with the speed of
> [_Excessively_ long line split.]
> )  alias which 'echo `echo "$PATH" | tr : '\''\012'\'\
> )  ' | sed -e '\''s+$+/\!:1+'\'' -e '\''s:^:/.[.]:'\'\
> )  '` | sed '\''s:/../:/:g'\'''
> This alias doesn't deal with aliases (easily fixed), but most importantly
> it _fails_.

No, it does exactly what it's meant to do.

> 	% which passwd
> 	/bin/passwd /usr/bin/passwd /etc/passwd
> 	# How odd: /etc/passwd is executable!

I like a which that points out non-executables in PATH, because it shows
quite clearly any wasted exec()s.

> 	% set path=($path .)
> 	% cp /bin/true foo
> 	% which foo
> 	# Silence.

It is a mistake to have . (or any other relative directories, if your
system supports them) in your path.

> Had you read the documentation of `which5', you would have known it's not
> that trivial to get things right.

Different people will prefer different behaviors of ``which''; no single
behavior is right. (Should we say that which5 is wrong because it
doesn't follow the BSD which man page?)

---Dan

tchrist@convex.COM (Tom Christiansen) (01/23/91)

The nature of my article was intended to echo Dan's: a bunch of 
childish insults (which he calls libel when I utter them) followed
by some technical talk.  Obviously, it's a wasted effort.  But
I just won't put up with insults.  I thought fire with fire might
place perspective and show why it's a bad thing.

Dan ducked most technical issues.  Let's try again.  This is probably
going to be more pearls before swine, but I'll try anyway.

It's not a matter of quoting: it's one of complexity.  The algorithm I
used, which has been demo'd in shell, perl, and even the shell from hell,
uses a straightforward decomposition of the problem.  Others have
concurred here that this approach seems more intuitive, legible, and
maintainable than Dan's.  

Maarten also pointed out that Dan's solution made mistakes.

Back to implementation language: do you really have csh on DOS, Mac's, etc?
If so, why? Aren't you just spreading the sickness?  If not, then that
solution isn't going to work even if you should have sed and tr.

Give me a list of BSD and SysV systems, Dan, on which Perl will not
compile and run.  I disblieve that there are a lot of them.  In fact, I
know of none, possibly modulo chez da Silva.

--tom
--
"Hey, did you hear Stallman has replaced /vmunix with /vmunix.el?  Now
 he can finally have the whole O/S built-in to his editor like he
 always wanted!" --me (Tom Christiansen <tchrist@convex.com>)

chet@odin.INS.CWRU.Edu (Chet Ramey) (01/23/91)

Paul Falstad replied to a posting of mine:
>The ~ is expanded only for the first component in the PATH, not for the
>remaining components.  Bash handles this fine, of course, but execlp
>does not.

You're right, of course.  I had changed bash a while back to be more like
ksh-86, which expanded tildes after colons when doing tilde expansion, but
have since backed that change out after deciding it wasn't Posix compliant. 
(The ksh book says ksh88 doesn't expand tildes after colons, but I have no
way to check that.)

It might be better to expand tildes after colons, but bash is doing exactly
what the documentation says it does. 

Chet
-- 
Chet Ramey				``There's just no surf in
Network Services Group			  Cleveland, U.S.A. ...''
Case Western Reserve University
chet@ins.CWRU.Edu		My opinions are just those, and mine alone.

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (01/24/91)

Tom, I posted a message saying ``I've always been satisfied with the
speed of'' followed by my which alias. It was short and to the point; it
was a direct followup to another article; and I hope somebody out there
finds the alias useful.

Then you started flaming, for no apparent reason. Why? We were having a
perfectly pleasant technical discussion until you jumped in (again).

Afterwards, you were making your usual pokes at the standard UNIX tools,
so I poked fun at perl---and that pushed you over the edge. An entire
article just to try to prove to the world how competent you are at
making up insults. Is perl really that close to your heart? I always
assume that criticism is meant to be constructive. Why don't you do the
same?

[End sermon. Begin light flames.]

In article <1991Jan23.142528.12085@convex.com> tchrist@convex.COM (Tom Christiansen) writes:
> The nature of my article was intended to echo Dan's: a bunch of 
> childish insults (which he calls libel when I utter them)

I'm glad you admit that you were uttering a bunch of childish insults.

> But
> I just won't put up with insults.

As anyone who has read this discussion can verify, any insults I've
thrown at you have been direct responses to insults on your part.
Witness this article, for example.

> I thought fire with fire might
> place perspective and show why it's a bad thing.

Bullshit. You were just trying to protect your wounded di

'Scuse me. What I mean is, to put it simply, ``You started.'' The fact
is that I was trying to contribute to a technical discussion, and you
began flaming for no reason.

> Dan ducked most technical issues.

We can get into an infinite loop of ``No, you ducked first'' here; I'm
sure that anyone who reviews the discussion will notice that you ducked
first, though you probably believe exactly the opposite.

> It's not a matter of quoting: it's one of complexity.  The algorithm I
> used, which has been demo'd in shell, perl, and even the shell from hell,
> uses a straightforward decomposition of the problem.  Others have
> concurred here that this approach seems more intuitive, legible, and
> maintainable than Dan's.  

Yes, one other person has agreed with you. So what? People have
opinions. As I've told you in e-mail, I find shell solutions easy to
deal with, for the same reason that you find perl solutions easy to deal
with.

> Maarten also pointed out that Dan's solution made mistakes.

No, it did not make mistakes. What Maarten pointed out was that my
``which'' did something different from his ``which.''

> Back to implementation language: do you really have csh on DOS, Mac's, etc?
> If so, why? Aren't you just spreading the sickness?  If not, then that
> solution isn't going to work even if you should have sed and tr.

sh has been around for five years on DOS.

Furthermore, as I've now told you twice and as you've repeatedly failed
to acknowledge, my alias could be written in any shell with no effort. I
only presented it as a csh alias because I use csh for interactive work
on most systems. It seems to have escaped you that unquoting and quoting
are five-letter commands in csh.

Tom, you are failing to look beyond the simplest level of syntax. Do you
criticize shars because they put X's before every line? Of course not:
if you have trouble reading with the X's, you just unpack or pipe
through sed. So why should you criticize a quoted alias, when all it
takes is one ``alias'' command to see it without the quoting?

> Give me a list of BSD and SysV systems, Dan, on which Perl will not
> compile and run.

Nobody's saying anything about where Perl *can* run. The question is
where it *does* run. Stop perverting the argument.

---Dan

maart@cs.vu.nl (Maarten Litmaath) (01/24/91)

In article <9688:Jan2313:09:4391@kramden.acf.nyu.edu>,
	brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:
)[...]
)> 	% which passwd
)> 	/bin/passwd /usr/bin/passwd /etc/passwd
)> 	# How odd: /etc/passwd is executable!
)
)I like a which that points out non-executables in PATH, because it shows
)quite clearly any wasted exec()s.

I like a `which' that gives the right answer all the time, that is, the
answer to the following question:

	When I type a command, say `foo', which file will be executed?

)> 	% set path=($path .)
)> 	% cp /bin/true foo
)> 	% which foo
)> 	# Silence.
)
)It is a mistake to have . (or any other relative directories, if your
)system supports them) in your path.

Nonsense.  It's a mistake to put `.' _before_ the standard directories.
In my PATH `.' is the very last component.

)> Had you read the documentation of `which5', you would have known it's not
)> that trivial to get things right.
)
)Different people will prefer different behaviors of ``which''; [...]

Agreed.  But some types of behavior are questionable at best, ridiculous
at worst.
--
kinnersley@kuhub.cc.ukans.edu (Bill Kinnersley):
	"Do phonograph turntables turn the other way in Australia?"
gjh@krebs.acc.Virginia.EDU (Galen J. Hekhuis)
	"How do you think satanic messages were discovered on records?"

pfalstad@phoenix.Princeton.EDU (Paul Falstad) (01/24/91)

maart@cs.vu.nl (Maarten Litmaath) wrote:
>In article <9688:Jan2313:09:4391@kramden.acf.nyu.edu>,
>	brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:
>)> 	% which passwd
>)> 	/bin/passwd /usr/bin/passwd /etc/passwd
>)> 	# How odd: /etc/passwd is executable!
>)I like a which that points out non-executables in PATH, because it shows
>)quite clearly any wasted exec()s.
>I like a `which' that gives the right answer all the time, that is, the
>answer to the following question:
>	When I type a command, say `foo', which file will be executed?

Good point.  But if you do agree with Dan, and want a which that points
out non-executables in PATH, you can make a simple easy obvious change
to Tom's perl script (take out the -x, move the $path assigment) to make it
do that.  His is much more flexible.  If you don't agree with Dan, and want
to fix the csh version to exclude non-executables, after deciphering the csh
brain-damage you'd discover that there's no way to change it.  Perhaps
since Dan can't fix his which, he's decided that it's OK the way it is.
(That's only a suggestion.  He probably does like which to have that behavior.)
But Tom's solution can easily be changed to have either behavior.

>)> 	% set path=($path .)
>)> 	% cp /bin/true foo
>)> 	% which foo
>)> 	# Silence.
>)It is a mistake to have . (or any other relative directories, if your
>)system supports them) in your path.

That's nice, but the fact is many people do have . in their path (it's
last in the default path at our site).  You're saying, "Well, my version
doesn't work if you have . in your path, so don't put . in your path."
"Doctor, it hurts when I do this."  "So don't do that."

I agree that's its not too smart to have . in your path.  (I don't.)
But for those who do, it's all the more important for which to report
executables in the current directory, to make sure you're not about to
execute a trojan horse by accident.  In any case, your version should do
something sensible when someone has . in his path; instead it does
something strange, and it's hard for someone who doesn't speak csh to
figure out why after looking at your code.

Again I could ask, does your csh alias behave this way because you
designed it to, or because there's no other way it could act?  The perl
solution could easily be changed to print a blank line or print garbage
or coredump if you're stupid enough to have . in your path; your
solution is not so flexible.

>)> Had you read the documentation of `which5', you would have known it's not
>)> that trivial to get things right.
>)
>)Different people will prefer different behaviors of ``which''; [...]
>
>Agreed.  But some types of behavior are questionable at best, ridiculous
>at worst.

Dan prefers the behavior of his which because the crufty language it's
written in allows no other behavior.  How convenient.  Yet different people
can easily change the perl solution to have the different behaviors they
prefer.  That seems much more sensible to me.

Aren't flame wars fun?

--
Paul Falstad, pfalstad@phoenix.princeton.edu PLink:HYPNOS GEnie:P.FALSTAD
In the heat of composition I find that I have inadvertently allowed
myself to assume the form of a large centipede.  I am accordingly
dictating the rest to my secretary.
409 shift/reduce, 62 reduce/reduce conflicts.  Beat that!

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (01/24/91)

Ya want other behaviors? Fine, ya get other behaviors. These all use the
same strategy as the original.

Original:

  echo `echo "$PATH" | tr : '\012' | sed -e 's:$:/!:1': -e 's:^:/.[.]:'`\
    | sed 's:/\.\./:/:g'

The same thing, but with marks from ls showing the type of each file:

  ls -dF `echo "$PATH" | tr : '\012' | sed -e 's:$:/!:1': -e 's:^:/.[.]:'`\
    | sed 's:/\.\./:/:g'

The same thing, but following symbolic links:

  ls -dFL `echo "$PATH" | tr : '\012' | sed -e 's:$:/!:1': -e 's:^:/.[.]:'`\
    | sed 's:/\.\./:/:g'

The same thing, but showing only executables:

  ls -dFL `echo "$PATH" | tr : '\012' | sed -e 's:$:/!:1': -e 's:^:/.[.]:'`\
    | sed -n -e 's:/\.\./:/:g' -e '/*$/p'

The same thing, but removing the *:

  ls -dFL `echo "$PATH" | tr : '\012' | sed -e 's:$:/!:1': -e 's:^:/.[.]:'`\
    | sed -n -e 's:/\.\./:/:g' -e 's/*$//p'

The same thing, but showing only the first executable:

  ls -dFL `echo "$PATH" | tr : '\012' | sed -e 's:$:/!:1': -e 's:^:/.[.]:'`\
    | sed -n -e 's:/\.\./:/:g' -e 's/*$//p' | head -1

Same as the first one, but converting . in PATH into the actual cwd:

  setenv WD "`pwd`"
  echo `echo "$PATH" | tr : '\012' | sed -e 's:^\.$:'"$WD": -e 's:$:/!:1': -e 's:^:/.[.]:'`\
    | sed 's:/\.\./:/:g'

The same thing, but with ./ instead of `pwd`/:

  echo `echo "$PATH" | tr : '\012' | sed -e 's:^\.$:'"$WD": -e 's:$:/!:1': -e 's:^:/.[.]:'`\
    | sed -e 's:/\.\./:/:g' -e 's:^'"$WD"'/:./:g'

You can easily combine these to make other behaviors if you want, e.g.,
to just show the first executable including in ., or whatever.

If you want to quote a command for csh or sh, e.g., to make a csh alias,
or to pass something to sh -c or csh -cf: Use quote and makealias, which
have been running around since I posted them in 1988. You can pick up a
pile of random shell tricks from pub/hier/misc/faq-shell via anonymous
ftp to 128.122.128.22.

If you want to put these in a script instead: Replace !:1 with '"$1"',
and top the script with #!/bin/csh -f.

If you want to accept aliases from .cshrc: Same, but remove the -f.

In article <5648@idunno.Princeton.EDU> pfalstad@phoenix.Princeton.EDU (Paul Falstad) writes:
> If you don't agree with Dan, and want
> to fix the csh version to exclude non-executables, after deciphering the csh
> brain-damage you'd discover that there's no way to change it.

Again, the deciphering is as simple as ``alias which'', but it's a fair
accusation. Wrong, but fair.

> Perhaps
> since Dan can't fix his which, he's decided that it's OK the way it is.

An interesting thought.

> (That's only a suggestion.  He probably does like which to have that behavior.)

Obviously.

> But Tom's solution can easily be changed to have either behavior.

So what? So can any reasonable solution.

> That's nice, but the fact is many people do have . in their path (it's
> last in the default path at our site).  You're saying, "Well, my version
> doesn't work if you have . in your path, so don't put . in your path."
> "Doctor, it hurts when I do this."  "So don't do that."

Again, wrong, though fair.

> Again I could ask, does your csh alias behave this way because you
> designed it to, or because there's no other way it could act?

I think I've answered that question.

> >)> Had you read the documentation of `which5', you would have known it's not
> >)> that trivial to get things right.
> >)Different people will prefer different behaviors of ``which''; [...]
> >Agreed.  But some types of behavior are questionable at best, ridiculous
> >at worst.
> Dan prefers the behavior of his which because the crufty language it's
> written in allows no other behavior.

Now, now, don't make silly accusations without thinking things through
first.

---Dan

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (01/24/91)

In article <8833@star.cs.vu.nl> maart@cs.vu.nl (Maarten Litmaath) writes:
> I like a `which' that gives the right answer all the time, that is, the
> answer to the following question:
> 	When I type a command, say `foo', which file will be executed?

#!/bin/csh
setenv WD "`pwd`"
ls -dFL `echo "$PATH" | tr : '\012' | sed -e 's:^\.$:'"$WD": -e 's:$:/'"$1": -e 's:^:/.[.]:'`\
  | sed -e 's:/\.\./:/:g' -e 's:^'"$WD"'/:./:g' -e 's/*$//p' | head -1

If this is missing any features you want, just say what they are. On
systems without symbolic links you probably have to leave out the -L;
other than that this should be reasonably portable.

(I agree, btw, that it's worth rewriting something like this in C if the
shell script isn't efficient enough.)

> )It is a mistake to have . (or any other relative directories, if your
> )system supports them) in your path.
> Nonsense.  It's a mistake to put `.' _before_ the standard directories.
> In my PATH `.' is the very last component.

Ah, so the moment you make a typing mistake you execute anybody's
program?

---Dan

pfalstad@phoenix.Princeton.EDU (Paul Falstad) (01/25/91)

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) wrote:

>Same as the first one, but converting . in PATH into the actual cwd:
>
>  setenv WD "`pwd`"
>  echo `echo "$PATH" | tr : '\012' | sed -e 's:^\.$:'"$WD": -e 's:$:/!:1': -e 's:^:/.[.]:'`\
>    | sed 's:/\.\./:/:g'

This is not really a change in optional behavior, it is a bug fix.  Your
which should act the right way if you have . in your path.

>Original:
>
>  echo `echo "$PATH" | tr : '\012' | sed -e 's:$:/!:1': -e 's:^:/.[.]:'`\
>    | sed 's:/\.\./:/:g'

>The same thing, but removing the *:
>
>  ls -dFL `echo "$PATH" | tr : '\012' | sed -e 's:$:/!:1': -e 's:^:/.[.]:'`\
>    | sed -n -e 's:/\.\./:/:g' -e 's/*$//p'

(I could point out that if you have files ending in * in your path, this
acts weird, but I won't.  For the most part it works fine, I'm sure.
I was wrong to imply that this was impossible with standard tools.)

This is kind of confusing.  In order to print only executables, you have
changed the echo to an ls -dFL and added another expression to the
second sed.  It is not at all intuitive what the difference between
these two versions are.  I suppose someone smart enough to deduce what
your original did could figure out what the second one did, but it's not
obvious.  However, with Tom's, the difference is:

< printf "$path\n" if -x ($path="$dir/$file");
---
> printf "$dir/$file\n";

The difference is obvious; you've just removed the test.  With Tom's, to
remove the checking to see if the file is executable or not, you just remove
the test.  In yours, to put in the checking, you change 'echo' to 'ls
-dFL' and add another expression to your sed command.  This is not
obvious.

>The same thing, but showing only the first executable:
>
>  ls -dFL `echo "$PATH" | tr : '\012' | sed -e 's:$:/!:1': -e 's:^:/.[.]:'`\
>    | sed -n -e 's:/\.\./:/:g' -e 's/*$//p' | head -1

This is a bit inefficient; all you've done here is add one more process
to filter the output of the original.  I doubt anyone would choose this
method as a standard implementation for which.

>You can easily combine these to make other behaviors if you want, e.g.,
>to just show the first executable including in ., or whatever.

Certainly not as easily as changing the perl script.  These are shell
hacks, not programs.


The reason I call them hacks, and part of the reason they're confusing
is that they depend on a bug in csh for their operation!  Let's say we
try to figure out how the original (buggy) version works:

>  echo `echo "$PATH" | tr : '\012' | sed -e 's:$:/!:1': -e 's:^:/.[.]:'`\
>    | sed 's:/\.\./:/:g'

I know as a shell writer I should know at first glance what this does,
but I must confess I had to break it down.  Let's see:

1 phoenix:~/News echo "$PATH" | tr : '\012' | sed -e 's:$:/ls': -e 's:^:/.[.]:'

/.[.]/n/uffda/b/pfalstad/scr/ls
/.[.]/n/uffda/b/pfalstad/bin/sun4/ls
/.[.]/usr/princeton/bin/ls
/.[.]/usr/ucb/ls
/.[.]/usr/bin/ls
/.[.]/bin/ls
/.[.]/u/maruchck/scr/ls
/.[.]/u/cs320/bin/ls
/.[.]/u/subbarao/bin/ls
/.[.]/u/maruchck/bin/ls
/.[.]/usr/hosts/ls
/.[.]/usr/princeton/bin/X11/ls
/.[.]/usr/etc/ls
/.[.]/etc/ls
3 phoenix:~/News echo `echo /.[.]/etc/ls`
echo: No match.

4 phoenix:~/News echo `echo '/.[.]/etc/ls'`

5 phoenix:~/News exit

What's going on?  It turns out that your version depends on a bug in
csh, or at least a stupid feature.  I don't think that the output of
`...` substitution should be globbed at all (It's not obvious that it
should be), and if it is, and there is no match, it should print an
error message.  It's this same 'feature' that requires you to put 'set
noglob' and 'unset noglob' around eval `tset -s` in your .login.  This
bug has been fixed in some versions, including itcsh.  The only reason I
could figure out how your alias works is because I've taken a lot of
time studying the standard shells, and have read the csh bug list.
Writing a shell didn't hurt either.  I would never write a script
that used a csh bug for part of its operation and then post it to the
net as an example.

>If you want to put these in a script instead: Replace !:1 with '"$1"',
>and top the script with #!/bin/csh -f.
>
>If you want to accept aliases from .cshrc: Same, but remove the -f.

What do you mean?  You mean, change your implementation so it uses
aliases from .cshrc?  I don't see the difference this makes.

>> (That's only a suggestion.  He probably does like which to have that behavior.)
>
>Obviously.

Wasn't obvious from your article.  You should have fixed your solution
first, and then explained why it's bad to have . in your path.  You
sounded like a lazy programmer trying to get out of making a bug fix.  I
know the feeling. :-)

>> But Tom's solution can easily be changed to have either behavior.
>
>So what? So can any reasonable solution.

You're not really changing the solution, you're just filtering the
output.  Tom's can be filtered as well.

If you want to write a nice version of which that uses standard tools (which
I have no qualms about, I'm no perl groupie), you should use a loop.
It can be done in csh; SunOS /usr/ucb/which is a csh script.  Better
yet, use a decent shell.  If you like your version because it's fast and
it works the way you want it to, that's fine.  But you must admit, it's
hardly an example of good code.  I can't see how any csh hack that can't
easily be translated into a decent shell like sh or ksh can be called
good code.

--
Paul Falstad, pfalstad@phoenix.princeton.edu PLink:HYPNOS GEnie:P.FALSTAD
In the heat of composition I find that I have inadvertently allowed
myself to assume the form of a large centipede.  I am accordingly
dictating the rest to my secretary.
409 shift/reduce, 62 reduce/reduce conflicts.  Beat that!

subbarao@phoenix.Princeton.EDU (Kartik Subbarao) (01/25/91)

>>Obligatory plug for bash: it's worth it.  It's a very nice shell, with
>>full emacs editing and very good vi editing if that's your dialect.
>>It's certainly more fun than tcsh, which I used before, and has a more
>>POSIX-ified behavior.  There are still some bugs, although Chet's
>>version is nearly bug free, and version 1.06 is long overdue.  I liked
>>it so much, I use the shell (or something to that effect).
>

Cough Cough! Ahem Ahem! I *beg* to differ. Rather, I *demand* to differ.
*Obligatory?* Yeah right. After you get frustrated half an hour with its
damn non-destructive backspace, then ditz with it another hour on its 
half-assed command line editor, and you're left with a huge piece of code
that's not worth its weight in ^@'s.  Bourne Again? More like Burned Again.

Get tcsh. Now that's a real shell.

>I mostly agree, although I'm partial to zsh for some strange reason.  :-)

Wonder why :-) Once Paul finishes a decent line editor, I'll use it too.

			

			-Kartik

--
internet# find . -name core -exec cat {} \; |& tee /dev/tty*
subbarao@{phoenix or gauguin}.Princeton.EDU -|Internet
kartik@silvertone.Princeton.EDU (NeXT mail)       -|	
SUBBARAO@PUCC.BITNET			          - Bitnet

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (01/25/91)

In article <5657@idunno.Princeton.EDU> pfalstad@phoenix.Princeton.EDU (Paul Falstad) writes:
> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) wrote:
> >Same as the first one, but converting . in PATH into the actual cwd:
> >  setenv WD "`pwd`"
> >  echo `echo "$PATH" | tr : '\012' | sed -e 's:^\.$:'"$WD": -e 's:$:/!:1': -e 's:^:/.[.]:'`\
> >    | sed 's:/\.\./:/:g'
> This is not really a change in optional behavior, it is a bug fix.  Your
> which should act the right way if you have . in your path.

There was no bug to fix. It is a change in optional behavior. I happen
to think that it's stupid for the output of which to be relative to your
current directory; by that criterion, any version of which that pays
attention to . is wrong. But different people want different behaviors.

> This is kind of confusing.  In order to print only executables, you have
> changed the echo to an ls -dFL and added another expression to the
> second sed.

No. The changes were explained in the order that I did them, one at a
time.

Say you know that foo exists. echo foo just prints foo. ls -dF foo adds
a file type mark. (I said the same thing in the first article.) Do you
understand the first change now?

Now say you have a file list from ls -dF. To extract only the
executables, you check for * at the end of the line. The regexp for this
is \*$. Do you understand the second change now?

> However, with Tom's, the difference is:
> < printf "$path\n" if -x ($path="$dir/$file");
> > printf "$dir/$file\n";

Yeah, so? That's more characters changed than in my version.
Intuitively, though, using $path is analogous to the middle stage with
ls instead of echo, and the -x test is analogous to the * extraction.

(Btw, are you so sure that your change is correct?)

> >The same thing, but showing only the first executable:
> >  ls -dFL `echo "$PATH" | tr : '\012' | sed -e 's:$:/!:1': -e 's:^:/.[.]:'`\
> >    | sed -n -e 's:/\.\./:/:g' -e 's/*$//p' | head -1
> This is a bit inefficient; all you've done here is add one more process
> to filter the output of the original.

You can add it to the sed if you want; I didn't bother.

> I doubt anyone would choose this
> method as a standard implementation for which.

No shit. Standard implementations of commonly used programs are written
in C, because the world doesn't want its computers to be twice as slow.

  [ my commands are shell hacks because they depend on a csh bug ]
  [ that bug is the fact that the result of `` is globbed ]

That isn't a bug; it's a documented feature. You can easily avoid it if
you want.

Paul, something isn't a hack just because it depends on a documented
feature that you don't appreciate.

> You mean, change your implementation so it uses
> aliases from .cshrc?

No, that's not what I said.

> >> (That's only a suggestion.  He probably does like which to have that behavior.)
> >Obviously.
> Wasn't obvious from your article.

Yes, it was; I said so, in plain English.

> You
> sounded like a lazy programmer trying to get out of making a bug fix.

FLAME ON

You and Tom are coming across as so lazy that you'd rather waste
thousands of dollars of money around the world arguing with facts than
spending the two minutes it would take you to figure things out on your
own. Any competent shell programmer can use filters, and I'm not going
to teach you tricks that you can easily figure out for yourself.

FLAME OFF

> >> But Tom's solution can easily be changed to have either behavior.
> >So what? So can any reasonable solution.
> You're not really changing the solution, you're just filtering the
> output.

Paul, given that my solution is composed of filters, doesn't it strike
you as sensible that changing the solution means changing the filters?

> SunOS /usr/ucb/which is a csh script.

Yeah, and slow as per---I mean molasses.

> But you must admit, it's
> hardly an example of good code.

Why? You haven't given any reason for me to admit such a thing.

> I can't see how any csh hack that can't
> easily be translated into a decent shell like sh or ksh can be called
> good code.

``I can't see how any perl hack that can't easily be translated into a
decent language like C can be called good code.'' Who tf cares?

---Dan

pfalstad@burst.Princeton.EDU (Paul Falstad) (01/25/91)

subbarao@phoenix.Princeton.EDU (Kartik Subbarao) wrote:
>Cough Cough! Ahem Ahem! I *beg* to differ. Rather, I *demand* to differ.
[ other b.s. deleted ]

I don't know this person, he just happens to have an account on the same
machine as I do.  Please don't flame him, he didn't mean it.

>>I mostly agree, although I'm partial to zsh for some strange reason.  :-)
>Wonder why :-) Once Paul finishes a decent line editor, I'll use it too.

Don't let that turn you off.

--
Paul Falstad, pfalstad@phoenix.princeton.edu PLink:HYPNOS GEnie:P.FALSTAD
"And she's always on about men following her.  I don't know what she
thinks they're going to do to her.  Vomit on her, Basil, says."-Flowery Twats

subbarao@phoenix.Princeton.EDU (Kartik Subbarao) (01/25/91)

In article <17687:Jan2414:33:5091@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:
>In article <8833@star.cs.vu.nl> maart@cs.vu.nl (Maarten Litmaath) writes:
>> )It is a mistake to have . (or any other relative directories, if your
>> )system supports them) in your path.
>> Nonsense.  It's a mistake to put `.' _before_ the standard directories.
>> In my PATH `.' is the very last component.
>
>Ah, so the moment you make a typing mistake you execute anybody's
>program?

I make most of my mistakes typing commands in a consistent fashion (i.e,
mroe for more, dc for cd, etc..) I simply alias the few consistent mistakes
that I make.

Most of the times when I want to execute stuff "in the current directory",
its when I'm either working on a project, or have ftp'd something from the
net and am in the process of compiling, etc.. I *really* don't feel like
typing './a.out', or './xneatapplication'. 

Also, most people don't go to lengths as to do stupid things like put
trojan horses in /tmp -- even if they did, I really don't care that much. I
operate on the basis that my account is currently in the capability of being 
gotten into by anyone, and so I never have any security problems. I never
leave anything around in my account that I feel is so extremely private
that nobody should see it (UNIX certainly is not the place to keep that
kind of stuff). Most of my account is readable.

The only person who I'd REALLY suggest this for is root. Certainly, for me,
the convenience of NOT having to type `./' everytime that I execute
something in the current directory GREATLY overweighs any worry I have over
some nerd wanting to break into my account. 


			-Kartik
--
internet# find . -name core -exec cat {} \; |& tee /dev/tty*
subbarao@{phoenix or gauguin}.Princeton.EDU -|Internet
kartik@silvertone.Princeton.EDU (NeXT mail)       -|	
SUBBARAO@PUCC.BITNET			          - Bitnet

pfalstad@burst.Princeton.EDU (Paul Falstad) (01/25/91)

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) wrote:
>In article <5657@idunno.Princeton.EDU> pfalstad@phoenix.Princeton.EDU (Paul Falstad) writes:
>> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) wrote:
>There was no bug to fix. It is a change in optional behavior. I happen
>to think that it's stupid for the output of which to be relative to your
>current directory; by that criterion, any version of which that pays
>attention to . is wrong. But different people want different behaviors.

No, you think it's stupid for someone to have . in their path, and I
agree.  But if a person does have . in their path, your version should
work properly.  I think it's stupid for people to play nethack, but it
wouldn't be good to write a shell that dumps core whenever someone types
"nethack."

Unless you're saying that "I will use this version of which because it's
faster and because it works with my path because it doesn't have . in
it."  Then I agree.

>[ explains how it works ]

Yes, I did figure it out, but it took a while.  The perl solution was
obvious, at least to me.

>(Btw, are you so sure that your change is correct?)

No, I didn't bother to test it.  I don't know perl.

>That isn't a bug; it's a documented feature. You can easily avoid it if
>you want.

How?  (genuine question)  Is there a way to make csh not glob the results
of command substitution but have usual globbing work fine?  Also, this
feature is not documented, at least not in my manual.  If I'm wrong
please show me where it's documented.  Any feature that cannot be turned
off is a bug.

>> You mean, change your implementation so it uses
>> aliases from .cshrc?
>
>No, that's not what I said.

What did you say?

>You and Tom are coming across as so lazy that you'd rather waste
>thousands of dollars of money around the world arguing with facts than
>spending the two minutes it would take you to figure things out on your
>own. Any competent shell programmer can use filters, and I'm not going
>to teach you tricks that you can easily figure out for yourself.

I spent the two minutes figuring it out, and now I'm wasting thousands
of dollars of money around the world hoping to prevent others from
having to do the same.

>Yeah, and slow as per---I mean molasses.

I did say SunOS.

>``I can't see how any perl hack that can't easily be translated into a
>decent language like C can be called good code.'' Who tf cares?

I certainly don't.   I'm no perl groupie, as I said.  In fact, my
longest perl script is one line.  I just like flame wars.  :-)  I really
don't give a fuck about this whole discussion, nor does 99% of the net,
but it's fun to hear people having flame wars over such trivialities.  I'm
saving this thread for posterity.  Flame on!

--
Paul Falstad, pfalstad@phoenix.princeton.edu PLink:HYPNOS GEnie:P.FALSTAD
"And she's always on about men following her.  I don't know what she
thinks they're going to do to her.  Vomit on her, Basil, says."-Flowery Twats

tchrist@convex.COM (Tom Christiansen) (01/25/91)

From the keyboard of brnstnd@kramden.acf.nyu.edu (Dan Bernstein):
:Ya want other behaviors? Fine, ya get other behaviors. These all use the
:same strategy as the original.

[ many nice pipe examples that no novice will ever decipher. ]

:> But Tom's solution can easily be changed to have either behavior.
:
:So what? So can any reasonable solution.

And your solution, Dan, has not yet been proven to be such.  Leave the
programming langauge at sh if it will eliminate an irrevlant complaint of
yours.  The principal point is that there is a straightforward algorithm
employed here that a relatively recently initiated unix user can easily
read and understand.  To say "for each dir in path, print the pathname if
there is an exececutable file of the target name there" is much easier to
grok.  It's called top-down programming.  The tr/sed/sed/blah munging is
not as simple, and not as obvious.  In fact, it's several times less
obvious.  Take both to a novice and ask their opinion on this.  I
challenge you.

--tom
--
"Hey, did you hear Stallman has replaced /vmunix with /vmunix.el?  Now
 he can finally have the whole O/S built-in to his editor like he
 always wanted!" --me (Tom Christiansen <tchrist@convex.com>)

tchrist@convex.COM (Tom Christiansen) (01/25/91)

From the keyboard of brnstnd@kramden.acf.nyu.edu (Dan Bernstein):
:> However, with Tom's, the difference is:
:> < printf "$path\n" if -x ($path="$dir/$file");
:> > printf "$dir/$file\n";
:
:Yeah, so? That's more characters changed than in my version.
:Intuitively, though, using $path is analogous to the middle stage with
:ls instead of echo, and the -x test is analogous to the * extraction.

No, it's not in the least bit intuitive.   No series of filters
strung together like that using 4 regexps and multiple evaluation
will ever be as easy to understand as my solution.  On that I stand.

:> >  ls -dFL `echo "$PATH" | tr : '\012' | sed -e 's:$:/!:1': -e 's:^:/.[.]:'`\
:> >    | sed -n -e 's:/\.\./:/:g' -e 's/*$//p' | head -1

It's also slower than sin.

:No shit. Standard implementations of commonly used programs are written
:in C, because the world doesn't want its computers to be twice as slow.

So why didn't you post a solution in C then?  

The perl solution is much faster than your grody hack, if you're honestly
concerned about speed.   I'm also concerned about complexity.

It doesn't make one bit of difference whether a command executed as
infrequently as which takes .03 seconds instead of .06 seconds.

:You and Tom are coming across as so lazy that you'd rather waste
:thousands of dollars of money around the world arguing with facts than
:spending the two minutes it would take you to figure things out on your
:own. Any competent shell programmer can use filters, and I'm not going
:to teach you tricks that you can easily figure out for yourself.

Just what is this claptrap?  I can't make any sense of it.  It has
no relevance on anything going on here.  Dan's just being insulting
and attacking wildly again.  He attempts to persuade by bashing 
you on the head and lobbing insults.  What a wonderful world it
would be if everyone would do this.

--tom
--
"Hey, did you hear Stallman has replaced /vmunix with /vmunix.el?  Now
 he can finally have the whole O/S built-in to his editor like he
 always wanted!" --me (Tom Christiansen <tchrist@convex.com>)

tale@rpi.edu (David C Lawrence) (01/25/91)

In <5612@idunno.Princeton.EDU> pfalstad@phoenix.Princeton.EDU (Paul Falstad):

   The ~ is expanded only for the first component in the PATH, not for the
   remaining components.  Bash handles this fine, of course, but execlp
   does not.

Not only that, ~ also isn't _always_ expanded if first.  Try VAR=~:~.
It only seems to do it if ~ is followed by a username or by /.

Many moons ago I just decided to use this in every login shell
environment I had to set my environment variables:

function tilde { echo "$@" | /usr/bin/tr ' ' : }
PATH=`tilde ~tale/bin /usr/local/gnu/bin /usr/bin/X11 /usr/local/bin /usr/etc /usr/bin /usr/ucb /bin  /usr/5bin ~weltyc/bin .`

Used similary for MANPATH, TEXINPUTS, et cetera.

The "function" part has changed for each flavour of shell, but the
basic method is there.
--
   (setq mail '("tale@cs.rpi.edu" "tale@ai.mit.edu" "tale@rpitsmts.bitnet"))

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (01/26/91)

In article <5688@idunno.Princeton.EDU> pfalstad@burst.Princeton.EDU (Paul Falstad) writes:
> >[ explains how it works ]
> Yes, I did figure it out, but it took a while.  The perl solution was
> obvious, at least to me.
> >(Btw, are you so sure that your change is correct?)
> No, I didn't bother to test it.  I don't know perl.

Well, your ``obvious'' change is wrong. This says something about the
maintainability of the perl solution.

> >That isn't a bug; it's a documented feature. You can easily avoid it if
> >you want.
> How?  (genuine question)  Is there a way to make csh not glob the results
> of command substitution but have usual globbing work fine?

Hint: To stop foo from being globbed, you put double-quotes around it.

> Also, this
> feature is not documented, at least not in my manual.

Frighteningly bad csh manual you have if it doesn't mention double
quotes.

> >You and Tom are coming across as so lazy that you'd rather waste
> >thousands of dollars of money around the world arguing with facts than
> >spending the two minutes it would take you to figure things out on your
> >own. Any competent shell programmer can use filters, and I'm not going
> >to teach you tricks that you can easily figure out for yourself.
> I spent the two minutes figuring it out, and now I'm wasting thousands
> of dollars of money around the world hoping to prevent others from
> having to do the same.

Sorry, but all you've shown in this article is that you don't know how
to use double-quotes to prevent globbing.

---Dan

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (01/26/91)

In article <1991Jan25.080151.11595@convex.com> tchrist@convex.COM (Tom Christiansen) writes:
> From the keyboard of brnstnd@kramden.acf.nyu.edu (Dan Bernstein):
> :Ya want other behaviors? Fine, ya get other behaviors. These all use the
> :same strategy as the original.
> [ many nice pipe examples that no novice will ever decipher. ]

Who tf cares? Maybe you have novices maintaining your software at
Convex, but I don't really care whether a solution is obvious or even
comprehensible to novices. It's much more important that people be able
to understand the interface.

> :> But Tom's solution can easily be changed to have either behavior.
> :So what? So can any reasonable solution.
> And your solution, Dan, has not yet been proven to be such.

Huh? Non sequitur. What does program proving have to do with whether a
program can be changed to give a different behavior?

> Leave the
> programming langauge at sh if it will eliminate an irrevlant complaint of
> yours.

Huh? Wtf is irrevlant? Can anyone understand that sentence?

> To say "for each dir in path, print the pathname if
> there is an exececutable file of the target name there" is much easier to
> grok.

Huh? Much easier than what? My solution translates as ``Add the target
name to every dir in path, glob to select only the files that exist,
print.'' So you're working one element at a time while I'm working with
the entire set of directories at once. This isn't a real difference.

> Take both to a novice and ask their opinion on this.  I
> challenge you.

I don't know any UNIX novices who've learned test yet, and your solution
depends on -x. What do you mean by a novice?

---Dan

chip@tct.uucp (Chip Salzenberg) (01/26/91)

According to brnstnd@kramden.acf.nyu.edu (Dan Bernstein):
>There was no bug to fix. It is a change in optional behavior.

    I have not seen anyone convince Tom Neff (or Dan Bernstein) of
    anything different that the thoughts that they were born with.
             -- an E-correspondent of Kent Paul Dolan

-- 
Chip Salzenberg at Teltronics/TCT     <chip@tct.uucp>, <uunet!pdn!tct!chip>
       "If Usenet exists, then what is its mailing address?"  -- me
             "c/o The Daily Planet, Metropolis."  -- Jeff Daiell

wilkes@mips.COM (John Wilkes) (01/26/91)

In article <5648@idunno.Princeton.EDU> pfalstad@phoenix.Princeton.EDU (Paul Falstad) writes:
>
>Aren't flame wars fun?

"Arguments are full of words and each person is sure he's the only one who
knows what the words mean.  Each word is a basket of eels, as far as I'm
concerned.  Everybody gets to grab just one eel and that's his
interpretation, and he'll fight to the death for it."

			from _Stallion_Gate_ by Martin Cruz Smith

-wilkes  <wilkes@mips.com>

tchrist@convex.COM (Tom Christiansen) (01/26/91)

From the keyboard of brnstnd@kramden.acf.nyu.edu (Dan Bernstein):
:In article <1991Jan25.080151.11595@convex.com> tchrist@convex.COM (Tom Christiansen) writes:
:> From the keyboard of brnstnd@kramden.acf.nyu.edu (Dan Bernstein):
:> :Ya want other behaviors? Fine, ya get other behaviors. These all use the
:> :same strategy as the original.
:> [ many nice pipe examples that no novice will ever decipher. ]
:
:Who tf cares? Maybe you have novices maintaining your software at
:Convex, but I don't really care whether a solution is obvious or even
:comprehensible to novices. It's much more important that people be able
:to understand the interface.

How much mud can the mud-slinger sling?  How many insults can be lobbed by
this sadly disturbed individual?  Dragging in corporate affiliation like
this name is but another childish tactic, and it's not even close to
correct.  I've a much wider perspective at work here than simply where I
work.  Dan's original code had 30 quotes, 9 backslashes, and an
indirection is ugly: this in itself makes it hard to understand by almost
anyone there is.  There are a lot of UNIX users out there, and I see no
reason to make it harder than it needs to be.  I've taught UNIX to 
maybe a thousand new users in the last 5 years, and this is the kind
of stuff that turns them off.

:> :> But Tom's solution can easily be changed to have either behavior.
:> :So what? So can any reasonable solution.
:> And your solution, Dan, has not yet been proven to be such.
:
:Huh? Non sequitur. What does program proving have to do with whether a
:program can be changed to give a different behavior?

Your approach has not been proven to be a reasonable solution.  It's
obfuscated.  You're expressing an alternate algorithm to solve a problem.
It's failing lies in its obfuscation. It doesn't have to be that way.
You can write this in many languages in a much more straightforward
way.  But you want 30 quotes in this.

:> Leave the
:> programming langauge at sh if it will eliminate an irrevlant complaint of
:> yours.
:
:Huh? Wtf is irrevlant? Can anyone understand that sentence?

It means irrelevant, Dan.  Doesn't seem to me like a hard typo to
pattern-match out something that makes sense.  But maybe your gifts
lie in other directions, like senseless attacks.

--tom
--
"Hey, did you hear Stallman has replaced /vmunix with /vmunix.el?  Now
 he can finally have the whole O/S built-in to his editor like he
 always wanted!" --me (Tom Christiansen <tchrist@convex.com>)

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (01/27/91)

In article <1991Jan26.093659.26192@convex.com> tchrist@convex.COM (Tom Christiansen) writes:
> How much mud can the mud-slinger sling?  How many insults can be lobbed by
> this sadly disturbed individual?  Dragging in corporate affiliation like
> this name is but another childish tactic, and it's not even close to
> correct.

Objective facts: Every nasty technique you accuse me of using, you used
first. You started flaming first, you started insulting first, you
started dragging in affiliation first. Any reader can verify these
firsts.

The fact, is, Tom, that every step this discussion has taken towards
USENET hell, you've dragged it down that step.

``Sadly disturbed.'' ``Childish.'' Wow. I think Freud invented the word
``projection'' for Tom's behavior.

> Dan's original code had 30 quotes, 9 backslashes, and an
> indirection is ugly: this in itself makes it hard to understand by almost
> anyone there is.

Are you saying that any code with 30 quotes, 9 backslashes, and
indirection is hard to understand? You haven't presented any logic in
support of your position, so either you're being irrational or you're
making an idiotic generalization. (Of course, anyone who knows how to
type ``alias foo'' can remove almost all the quotes, backslashes, and
indirection before trying to understand the alias, but I take it that
this wizardly technique is too advanced for you.)

> Your approach has not been proven to be a reasonable solution.

Objective fact: You started criticizing other people's code first. You
started criticizing code on subjective grounds (like whether it's
``reasonable'') first.

> You're expressing an alternate algorithm to solve a problem.

As I told you and as you failed to acknowledge, the difference between
my algorithm and yours is that I'm taking the entire path at once while
you're taking one directory at a time. To any mathematician this is a
trivial difference; sorry if it doesn't seem so trivial to you.

> :> Leave the
> :> programming langauge at sh if it will eliminate an irrevlant complaint of
> :> yours.
> :Huh? Wtf is irrevlant? Can anyone understand that sentence?
> It means irrelevant, Dan.  Doesn't seem to me like a hard typo to
> pattern-match out something that makes sense.  But maybe your gifts
> lie in other directions, like senseless attacks.

Objective fact: You gave the first typo flame in this discussion.
(``Data flaw,'' in case you've forgotten.)

(I still don't understand that sentence, btw. The two halves don't seem
connected in any way. I'll suppose for the sake of discussion that I
have made some irrelevant complaint, though you haven't pointed out any
such complaint. Why would leaving the programming language at sh
eliminate a complaint of mine? I've been using csh throughout this
subthread.)

---Dan

bill@bilver.uucp (Bill Vermillion) (01/30/91)

In article <2186:Jan2620:04:0191@kramden.acf.nyu.edu-> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:
->In article <1991Jan26.093659.26192@convex.com> tchrist@convex.COM (Tom Christiansen) writes:
->> How much mud can the mud-slinger sling?  How many insults can be lobbed by
->> this sadly disturbed individual?  Dragging in corporate affiliation like
->> this name is but another childish tactic, and it's not even close to
->> correct.
 
->Objective facts: Every nasty technique you accuse me of using, you used
->first. You started flaming first, you started insulting first, you
->started dragging in affiliation first. Any reader can verify these
->firsts.

Why don't you guys take this flame war to email or at least to alt.flame?
-- 
Bill Vermillion - UUCP: uunet!tarpit!bilver!bill
                      : bill@bilver.UUCP