Path: utzoo!utgpu!cs.utexas.edu!sdd.hp.com!zaphod.mps.ohio-state.edu!julius.cs.uiuc.edu!news.cs.indiana.edu!rutgers!njin!princeton!phoenix.Princeton.EDU!pfalstad From: pfalstad@phoenix.Princeton.EDU (Paul Falstad) Newsgroups: alt.sources.d Subject: Re: Multiple executables in path Message-ID: <5657@idunno.Princeton.EDU> Date: 24 Jan 91 17:18:34 GMT References: <8833@star.cs.vu.nl> <5648@idunno.Princeton.EDU> <17501:Jan2414:21:3991@kramden.acf.nyu.edu> Sender: news@idunno.Princeton.EDU Organization: The E. Henry Thripshaw Fan Club Lines: 143 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!