miller@uwovax.uwo.ca (Greg Miller) (09/12/90)
Hi! I have been having great problems in setting up an alias within csh. I want to test for the presence of a file, and if it exists then to execute some statements e.g. if ( { test -s /usr/spool/mail/miller } ) then; echo "" ; echo "New mail" ;\ echo "" ; endif The above does not work because when executed the endif statement is not reached. The problem appears to be related to the brackets associated with the expression in the condition. Could somebody please tell me what I am doing wrong and how to do this in a one line command that can be aliased? Thanks! J G Miller telephone: (519) 679-2111 extension 6325 Room 024, Chemistry Building InterNet: <a4346@uwocc1.uwo.CA> University of Western Ontario NetNorth: <A4346@UWOCC1.BITNET> LONDON, Ontario, N6A 5B7 mailpath: {uunet!watmath,utai}!ria!a4346 -------------------------------------------------------------------------------
miller@uwovax.uwo.ca (Greg Miller) (09/12/90)
In article <6929.26ed0b53@uwovax.uwo.ca>, miller@uwovax.uwo.ca (Greg Miller) writes: > Hi! > > I have been having great problems in setting up an alias within csh. > > I want to test for the presence of a file, and if it exists then > to execute some statements e.g. > > > if ( { test -s /usr/spool/mail/miller } ) then; echo "" ; echo "New mail" ;\ > echo "" ; endif > Further to my original post, I have since found that the problem is not associated with the brackets around the expression but is related to the execution of test. If the file is present, the condition is met and the statements are executed. If the file is zero length, the condition is not true, then the sequence of commands are not executed but the if statement is not terminated. And ideas on why this bizarre behavior and how to get it to work properly? J G Miller
chris@mimsy.umd.edu (Chris Torek) (09/14/90)
In article <6932.26ed237f@uwovax.uwo.ca> miller@uwovax.uwo.ca (Greg Miller) writes: >Followup-To: j g miller <miller@ria.ccs.uwo.ca> (No wonder there have been no followups. None of `j', `g', `miller', or `<miller@ria.ccs.uwo.ca>' are valid newsgroup names....) >if ( { test -s /usr/spool/mail/miller } ) then; echo "" ; echo "New mail" ;\ > echo "" ; endif >If the file is present, the condition is met and the statements are >executed. > >If the file is zero length, the condition is not true, then >the sequence of commands are not executed but the if statement >is not terminated. Correct. >Any ideas on why this bizarre behavior This is the C shell we are talking about. Do not expect anything resembling sanity. >and how to get it to work properly? Do not use an alias. The C shell's `parser' looks for a *line* whose first word is `else' or `endif' after the C shell executes a false `if (expr) then'. While scanning for such a line it notes lines that have the form if<whitespace>.*<whitespace>then and increments a `false if' counter. You can thus stick all sorts of syntactic trash between a false `if' and its corresponding `endif'; only when the test in the `if' becomes true will the C shell actually notice that the trash is indeed invalid. For instance: if (0) then if (look, unclosed { and !funny characters then endif echo this does not get echoed endif echo but this does It *is* possible to jam a newline into an alias, but if you do you will quickly run afoul of other C shell bugs. For instance: % alias t 'if (0) then\ echo foo\ endif\ echo bar' % t ? ? % Nothing gets echoed. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 405 2750) Domain: chris@cs.umd.edu Path: uunet!mimsy!chris
schaefer@ogicse.ogi.edu (Barton E. Schaefer) (09/18/90)
In article <6929.26ed0b53@uwovax.uwo.ca> J G Miller <miller@ria.ccs.uwo.CA> writes: } } I have been having great problems in setting up an alias within csh. } } if ( { test -s /usr/spool/mail/miller } ) then; echo "" ; echo "New mail" ;\ } echo "" ; endif } } Could somebody please tell me what I am doing wrong and how to do } this in a one line command that can be aliased? In article <6932.26ed237f@uwovax.uwo.ca> he goes on: } In article <6929.26ed0b53@uwovax.uwo.ca>, miller@uwovax.uwo.ca (Greg Miller) writes: } } Further to my original post, I have since found that the problem is } not associated with the brackets around the expression but is } related to the execution of test. Chris Torek has already explained that it is csh brain-damage, not a problem with "the execution of test", that causes this. } And ideas on why this bizarre behavior and how to get it to } work properly? Don't use any "then", "else" or "endif". The csh "if" syntax also allows if condition simple-command where simple-command can't be a parenthesized subshell or control statement (while, foreach) of any kind, and can't contain separators e.g. `|' or `;' are out. First problem: You want three lines of output, but you can't use three echo commands. Solution (`%' is the csh prompt): __________ % setenv NEW_MAIL_MESSAGE '\ New mail\ ' % printenv NEW_MAIL_MESSAGE New mail % __________ So in the alias, you use: if { test -s /usr/spool/mail/miller } printenv NEW_MAIL_MESSAGE Note that the ( ) around the { } were redundant. In general, the way to put conditionals into csh aliases is to use a series of simple-if statements like the one above. Here's an example from my .cshrc. The backslashes are for readability in this posting only -- if you actually want to use this, you have to remove the backslash-newline-tab sequences and make the pp alias into one long line. Ah, the vagaries of csh .... # Default pushd to home directory (like cd) # if there is no top-of-stack to swap with. alias pp 'set pd=(\!*:q);\ if ($#pd == 0) set pd=(`dirs` ~);\ if ($#pd > 1) shift pd;\ pushd $pd[1] >& /dev/null;\ if ($#pd > 1) popd +2 >& /dev/null;\ unset pd;\ dirs' -- Bart Schaefer schaefer@cse.ogi.edu
per@erix.ericsson.se (Per Hedeland) (09/19/90)
In article <26553@mimsy.umd.edu> chris@mimsy.umd.edu (Chris Torek) writes: >In article <6932.26ed237f@uwovax.uwo.ca> miller@uwovax.uwo.ca >>if ( { test -s /usr/spool/mail/miller } ) then; echo "" ; echo "New mail" ;\ >> echo "" ; endif >This is the C shell we are talking about. Do not expect anything >resembling sanity. Quite. Following the eternal wisdom of the net, I have learned not only "if you want to do a non-trivial csh script, use sh" but also "if you want to do a non-trivial csh command, use sh". Thus, a working one-liner could be: sh -c 'if test -s /usr/spool/mail/miller; then echo ""; echo "New mail"; echo ""; fi' However, turning this into an alias with csh's idea of quoting is awkward if at all possible, and you might just as well make it a script. Actually, IMHO the best solution is to use the other conditional construct, that happens to be common to sh and csh, and apparently unbroken in the latter: test -s /usr/spool/mail/miller && (echo ""; echo "New mail"; echo "") or as an alias: alias mailtest 'test -s /usr/spool/mail/miller && (echo ""; echo "New mail"; echo "")' --Per Hedeland per@erix.ericsson.se or per%erix.ericsson.se@uunet.uu.net or ...uunet!erix.ericsson.se!per
brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (09/19/90)
In article <1990Sep18.223605.29379@eua.ericsson.se> per@erix.ericsson.se (Per Hedeland) writes: > sh -c 'if test -s /usr/spool/mail/miller; then echo ""; echo "New mail"; echo ""; fi' > However, turning this into an alias with csh's idea of quoting is awkward if > at all possible, Don't give up! If it's not intuitively obvious to you that alias mailtest 'sh -c '\''if test -s /usr/spool/mail/miller; then echo ""; echo "New mail"; echo ""; fi'\' has the right effect, simply use the makealias and quote aliases presented below. ---Dan 1. How do I quote a string in csh? 2. How do I double-quote a string in csh? 3. How do I make an alias? 4. How do I get the value of a variable into a command? 5. How do I use a string variable in a sed command? 1. How do I quote a string in csh? Use the quote alias: alias a alias a quote "/bin/sed 's/\\!/\\\\\!/g' | /bin/sed 's/'\\\''/'\\\'\\\\\\\'\\\''/g' | /bin/sed 's/^/'\''/' | /bin/sed 's/"\$"/'\''/'" Make sure the alias is all on one line. All quote does is replace ! by \!, replace ' by '\'', and place single quotes at the beginning and end of the text. For example, % quote BEGIN { printf "'" } (you type this, followed by control-D) 'BEGIN { printf "'\''" } ' (this is the correctly quoted version) quote's output will also work under sh. 2. How do I double-quote a string in csh? The only interpretation inside a single-quoted string is ! and \!. A double-quoted string allows (in fact, forces) $ and ` interpretation as well. Here's the dquote alias: a dquote "/bin/sed 's/\\!/\\\\\!/g' | /bin/sed 's/"\""/"\""\\"\"\""/g' | /bin/sed 's/^/"\""/' | /bin/sed 's/"\$"/"\""/'" If you want to prevent interpretation of a $ inside the double-quoted string, replace it by "\$"; similarly for `. Of course, it may be simpler in this case to just use single-quoting and replace $foo by '"$foo"' when you do want it interpreted. 3. How do I make an alias? Say you've just typed an amazing command that you want to save as an alias. Use makealias: a makealias "quote | /bin/sed 's/^/alias \!:1 /' \!:2*" For example, % foobie 'bletch b' oing (wow, amazing!) % makealias fb foobie 'bletch b' oing (you retype the command, followed by control-D) alias fb 'foobie '\''bletch b'\'' oing' Redirect makealias's output to a file (makealias foo > /tmp/test) and later copy it to .login, or redirect directly to .login (makealias foo >> /tmp/.login). (Use .cshrc if you want your aliases in subshells.) If you want an alias to take arguments, replace a fixed string in the alias definition by \!:1 (first argument), \!:2* (second argument through end), etc. There are many more ! substitutions listed in the csh manual. 4. How do I get the value of a variable into a command? The shells have set but not show. Here's several ways to print the value of a variable, $ans, on stdout. ``Working echo'' means one whose worst vice is a -n option meaning suppress newlines; if your echo interprets escape sequences, it doesn't qualify. ``Amazing echo'' means one that doesn't interpret its arguments at all. sh, with printenv: export ans; printenv ans sh, with a working echo: (echo -n "$ans"; echo '') sh, with an amazing echo: echo "$ans" csh, with a working /bin/echo: (/bin/echo -n "$ans"; /bin/echo '') csh, with an amazing /bin/echo: /bin/echo "$ans" csh, with a working builtin echo: echo "$ans" NOTE: csh parses builtins strangely, so this works even if ans is "-n...". sh, on any machine: sed "+$ans" 2>&1 | sed 's/^Unrecognized command: +//' CAVEAT: Does not work if $ans contains newlines. csh, on any machine: sed "+$ans" |& sed 's/^Unrecognized command: +//' ANTI-CAVEAT: Because csh is csh, this one works if $ans contains newlines. The last two hacks are a useful trick to get that variable into the output stream, which is difficult if both echo and printenv are screwed. + can be any character upon which sed chokes. Other similar replacements include using ls imaginatively and then stripping off the `file not found', etc. 5. How do I use a string variable in a sed command? Say you want to replace all occurrences of the string $ans by XXX. sed "s/$ans/XXX/g" won't work if $ans contains interesting characters. You have to munge $ans into $pattern so that sed "s/$pattern/XXX/g" will act as if it had a literal $ans in the first position. Under sh with printenv, export ans ; pattern="`printenv ans | sed 's-\([\.\*\[\\\^\$\/]\)-\\\\\1-g'`" will do the job. In other cases, rewrite this along the lines of #4 above. For example, under csh with a working builtin echo, try alias literal 'sed '\''s-\([\.\*\[\\\^\$\/]\)-\\\1-g'\' alias show 'echo "$\!:1"' The acid test, of course, is show ans | sed "s/`show ans | literal`/XXX/g" which, no matter what $ans is, will output XXX. ---Dan
dkeisen@Gang-of-Four.Stanford.EDU (Dave Eisen) (09/20/90)
In article <1990Sep18.223605.29379@eua.ericsson.se> per@erix.ericsson.se (Per Hedeland) writes: >IMHO the best solution is to use the other conditional construct, that >happens to be common to sh and csh, and apparently unbroken in the latter: > >test -s /usr/spool/mail/miller && (echo ""; echo "New mail"; echo "") > Speak for your own C-shell. In SCO Xenix, the C-shell thinks it really is C: test -s /usr/spool/mail/miller returns 0 (assuming the file is nonempty) so the C-shell doesn't evaluate the second half of the conditional expression. && and || both work exactly the opposite of how one would expect them to work (and of how they do in fact work in the Bourne shell). -- Dave Eisen Home: (415) 323-9757 dkeisen@Gang-of-Four.Stanford.EDU Office: (415) 967-5644 1447 N. Shoreline Blvd. Mountain View, CA 94043
lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) (09/21/90)
In article <1990Sep20.090627.20515@Neon.Stanford.EDU> dkeisen@Gang-of-Four.Stanford.EDU (Dave Eisen) writes: : In article <1990Sep18.223605.29379@eua.ericsson.se> per@erix.ericsson.se (Per Hedeland) writes: : >IMHO the best solution is to use the other conditional construct, that : >happens to be common to sh and csh, and apparently unbroken in the latter: : > : >test -s /usr/spool/mail/miller && (echo ""; echo "New mail"; echo "") : > : : Speak for your own C-shell. : : In SCO Xenix, the C-shell thinks it really is C: : : test -s /usr/spool/mail/miller : : returns 0 (assuming the file is nonempty) so the C-shell doesn't : evaluate the second half of the conditional expression. : : && and || both work exactly the opposite of how one would expect them to : work (and of how they do in fact work in the Bourne shell). So use a binary editor, go in and swap the || and &&. Or rm /bin/csh. Such malprogramming should not go unpunished. Larry Wall lwall@jpl-devvax.jpl.nasa.gov
per@erix.ericsson.se (Per Hedeland) (09/21/90)
In article <1990Sep20.090627.20515@Neon.Stanford.EDU>, dkeisen@Gang-of-Four.Stanford.EDU (Dave Eisen) writes: |> Speak for your own C-shell. I spoke for *the* C-shell, as found in the BSD distribution (I wouldn't dream of claiming any ownership:-). If someone distributes a shell where the meaning of && and || is reversed, it certainly isn't the C-shell, just as a compiler for a language that reverses the meaning of those two isn't a C compiler. |> In SCO Xenix, the C-shell thinks it really is C: |> |> test -s /usr/spool/mail/miller |> |> returns 0 (assuming the file is nonempty) so the C-shell doesn't |> evaluate the second half of the conditional expression. I don't buy the "really is C" "justification" - I think that the proper point of view is that in C, as in Bourne shell and C-shell, the expression following && is evaluated if the preceding expression is *true* - the fact that C (and the C-shell in 'if' etc) happens to define "true" as non-zero and the shells and utilities define it as (return code) zero may be confusing but is nonetheless irrelevant. Of course, the csh man page doesn't talk about "true" in this context, but rather "fails" and "succeeds" - surely not even SCO thinks that return code zero from a Unix program is a failure indication? --Per Hedeland per@erix.ericsson.se or per%erix.ericsson.se@uunet.uu.net or ...uunet!erix.ericsson.se!per
karl_kleinpaste@cis.ohio-state.edu (09/21/90)
dkeisen@Gang-of-Four.Stanford.EDU writes:
&& and || both work exactly the opposite of how one would expect them to
work (and of how they do in fact work in the Bourne shell).
Yet another vendor shipping a positively prehistoric incantation of
csh.
The version of csh which had inverted sense of || and && existed in
the vicinity of 2.8BSD. This dates it in the vicinity of 1981 or
1982. It has long been fixed in more recent versions. However, that
version is by far the easiest thing to port to SysV (until Rel4) since
it lacked any concept of the "new" tty driver, jobs, and a variety of
other things.
All these vendors (SCO, Microsoft, Microport, Everex) shipping ancient
csh should invest a little time in upgrading their sources for csh to
include features in recent versions. For example, all these versions
lack (as I recall) the eval builtin and the directory stack as well.
(I was at a Waldenbooks the other night and came across a book on SCO
Xenix. In the chapter [an entire chapter!] describing csh, one of the
first things shown is a set of aliases to simulate the builtin
directory stack of a proper csh.) There's no excuse for taking this
LCD approach to csh -- yes, csh is pretty grotesque, but the very
least the vendors could do is pick up an old csh that can be ported,
and a new csh with bugs fixed and common features in place, and merge
the two to create something reasonable.
I did exactly such a thing with exactly such a csh (2.8BSD version) 6
years ago. It isn't tough; it isn't even particularly time-consuming.
The directory stack and the eval builtin code can be inhaled whole.
--karl
once-semi-proud creator
of a SysVRel1-compatible
job-controllified csh
based on 2.8BSD csh
(SIGTSTP emulated on SIGQUIT)
chris@mimsy.umd.edu (Chris Torek) (09/21/90)
[on && and || in csh] In article <1990Sep21.093645.16163@eua.ericsson.se> per@erix.ericsson.se (Per Hedeland) writes: >I spoke for *the* C-shell, as found in the BSD distribution (I wouldn't >dream of claiming any ownership:-). If someone distributes a shell where the >meaning of && and || is reversed, it certainly isn't the C-shell ... Hm, well, there never was `the' C shell, but rather several different C shells, at least as of the first VAX distribution. (The sources for csh included an assembly-language _doprnt function, and clearly this was different from the version on the PDP-11 2BSD distribution.) At any rate, there are two major variants of the C shell, one lacking job control. The one without job control (which was the one in the 3BSD VAX distribution) also had the bug with && and || being reversed. No doubt this is the one that was used as a base for the Xenix C shell. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 405 2750) Domain: chris@cs.umd.edu Path: uunet!mimsy!chris
jbw@bucsf.bu.edu (Joseph Wells) (09/23/90)
In <12211@ogicse.ogi.edu> schaefer@ogicse.ogi.edu (Barton E. Schaefer) writes: Don't use any "then", "else" or "endif". The csh "if" syntax also allows if condition simple-command where simple-command can't be a parenthesized subshell or control statement (while, foreach) of any kind, and can't contain separators e.g. `|' or `;' are out. [stuff deleted] In general, the way to put conditionals into csh aliases is to use a series of simple-if statements like the one above. Actually, you can get the complete power of the if-then-else-endif statement in a csh alias by using the "simple if" in combination with the || and && operators. You can translate this pseudo-code (not csh) statement: if "condition" then "statement1" else "statement2" endif into this csh statement which will work inside an alias: if "condition" set status=1 && "statement2" || "statement1" or this one: if (! "condition") set status=1 && "statement1" || "statement2" As an example, here is a simple alias for listing the command history in different ways: alias h \ " if ('\!*' != '') set status=1 && hi \\ || if ('\!*' !~ [1-9]*) set status=1 && hi -\!* \\ || history | grep -i '\!*' | tail" alias hi 'history | grep ............ | tail' If you just type "h", it lists the last ten non-trivial history entries. If you type "h 3", it lists the last three such entries. If you type "h ls", it lists the last 10 history entries that contain the string "ls". This technique won't work correctly if the "condition" has a side effect that sets "status" to be non-zero. Enjoy, -- Joe Wells <jbw@bu.edu>