[comp.unix.questions] csh question -- aliasing, quoting and the like

gjoost@westc.UUCP (Gertjan van Oosten) (09/19/89)

The problem concerns csh-aliases (aliasi ??? - David Addison in
'Moonlighting').
(There really should be a newsgroup for this -- comp.csh.questions??
 Let's start a vote!!)
The basic problem is as follows: I want an alias to kill all processes
called 'roy'.

Outline:

% alias killroy 'kill `ps ax | grep -w roy | grep -v grep | awk '{print $1}'`'

The problem comes down to having single quotes within single quotes. The
single quotes around the 'awk' argument can't be double quotes, because they
would lead to the evaluation of '$1'. Escaping the '$' is no use within
double quotes.
Not being able to figure out how (and if) this 'quoting problem' can be
dealt with, the following solution was found (whitespace added for clarity):

% alias killroy 'set var=\$1 ; kill `ps ax | grep -w roy | grep -v grep |
                                     awk "{print $var}"` ; unset var'

This works, but has its drawbacks, one of them being that 'var' may be set
before executing the command; it will be unset afterwards. This can be
solved by introducing a subshell:

% alias killroy '(set var=\$1 ; kill `ps ax | grep -w roy | grep -v grep |
                                      awk "{print $var}"`)'

So far, so good.
Now comes the real problem: I want to kill all processes called 'roy' on
machine 'host'.

Outline ('rsh' is 'remote shell', not 'restricted shell' (who uses
restricted shells, anyway?)):

% alias killroy 'rsh host kill `ps ax | grep -w roy | grep -v grep |
                                awk '{print $1}'`'

The easy way out is to add another alias:

% alias killhostroy 'rsh host killroy'

This is based on '~/.cshrc' being interpreted by 'rsh' before executing the
command; thus the 'killroy'-alias should be executed in '~/.cshrc'.
Another solution would be:

% alias killroy 'rsh host set var=\$1 ";" kill `ps ax | grep -w roy |
                                                grep -v grep |
                                                awk "{print $var}"`'

if `ps ax | ...` were executed on machine 'host'. However, this is not the
case: it is executed locally.

Aaargh. (Not Camargue...:-))

Does anyone out there have a more elegant (jus 'telegant - M.M.) solution?
Could somebody please enlighten me?
+----------------------------------------------------------------------+
| Gertjan van Oosten                                mcvax!westc!gjoost |
|                         West Consulting bv                           |
| Phoenixstraat 49          P.O. Box 3318           Tel: +31-15-123190 |
| 2611 AL  Delft            2601 DH  Delft          Fax: +31-15-147889 |
|                          The Netherlands                             |
+----------------------------------------------------------------------+
 No  Points   Name                                                     Hp [max]
  1    6141  HC-V was killed on level 6 by a hill orc.                  -  [66]

maart@cs.vu.nl (Maarten Litmaath) (09/20/89)

gjoost@westc.UUCP (Gertjan van Oosten) writes:
\...
\% alias killroy 'kill `ps ax | grep -w roy | grep -v grep | awk '{print $1}'`'

The `string' is broken into words as follows:

	'kill `ps ax | grep -w roy | grep -v grep | awk '{print

	$1}'`'

i.e. parts of the string aren't quoted.
Solution:

	'kill ... awk '\''{print $1}'\''`'
	^             ^  ^          ^  ^ ^
	+-------------+  +----------+  +-+

\...
\% alias killroy 'rsh host kill `ps ax | grep -w roy | grep -v grep |
\                                awk '{print $1}'`'

This would become:

	alias	killroy \
	'rsh host kill '\''`ps ... awk '\'\\\'\''{print $1}'\'\\\'\''`'\'

Er, say that again?
Of course this isn't the optimal solution, regarding the number of quotes and
backslashes; it is, however, a GENERAL solution.
The following trick might be helpful:

	set	q	= \'
	set	b	= \\
	set	q1	= $b$q
	set	b1	= $b$b
	set	q2	= $b1$q1
	# etc.

	alias	killroy \
	'rsh host kill '$q'`ps ... awk '$q$q1$q'{print $1}'$q$q1$q'`'$q
	                 ^               ^    ^             ^    ^    ^
	                 +---------------+    +-------------+    +----+

i.e. $q is a real quote, $q1 will be a real quote one interpretation level
deeper and so on.
-- 
   creat(2) shouldn't have been create(2): |Maarten Litmaath @ VU Amsterdam:
      it shouldn't have existed at all.    |maart@cs.vu.nl, mcvax!botter!maart

rostamia@umbc5.umbc.edu (Rouben Rostamian) (09/20/89)

In article <498@westc.UUCP> gjoost@westc.UUCP (Gertjan van Oosten) writes:
>The basic problem is as follows: I want an alias to kill all processes
>called 'roy'.
>
>% alias killroy 'kill `ps ax | grep -w roy | grep -v grep | awk '{print $1}'`'
>
>The problem comes down to having single quotes within single quotes. The
>single quotes around the 'awk' argument can't be double quotes, because they
>would lead to the evaluation of '$1'. Escaping the '$' is no use within
>double quotes.
...The rest of the article omitted.

General idea first:
Suppose A, B, C, are fragments of shell expressions, and suppose that you
wish to enclose the expression  - A 'B' C - in a pair of single quotes.
[Note: I use hyphens to delineate the expressions; they are NOT parts of the
the expressions.]

The obvious solution - 'A 'B' C' - will not do, because in effect it creates
the quoted strings - 'A ' -  and  - ' C' -, and squeezes an unquoted - B - in
between.  This is important, so make sure you see this before reading on!

Now that you see this, the rest is easy:  What you want is - 'A '\''B'\'' C' -
which is parsed as  'A '  +   \'   + 'B'   +   \'  +   ' C'.   Get it?

Now back to your problem.  Applying the general idea above, you can see
that the statement:

alias killroy  \
  'kill '\`'ps ax | grep -w roy | grep -v grep | awk ' \''{print $1}'\'\`

does the trick.  In fact, the pair of quotes surrounding "kill" are not
necessary and may be dropped.

An alternative solution, somewhat uglier, is to drop all unnecessary single
quotes and to "escape" all special characters
in sight:

alias killroy  \
   kill \` ps ax \| grep -w roy \| grep -v grep \| awk \'\{print \$1\}\'\`

I hope that this helps.

Rouben Rostamian                               Phone: 301 455-2458
Department of Mathematics                      e-mail:
University of Maryland Baltimore Counnty       Rostamian@umbc.bitnet
Baltimore, MD 21228                            rostamia@umbc3.umbc.edu

CCDN@levels.sait.edu.au (DAVID NEWALL) (09/21/89)

In article <498@westc.UUCP>, gjoost@westc.UUCP (Gertjan van Oosten) writes:
> The basic problem is as follows: I want an alias to kill all processes
> called 'roy'.
>
> % alias killroy 'kill `ps ax | grep -w roy | grep -v grep | awk '{print $1}'`'
>
> The problem comes down to having single quotes within single quotes.

What's wrong with cut?  Use cut before you go diving for awk.

% alias killroy 'kill `ps ax | grep -w roy | grep -v grep | cut -c1-5`'


David Newall                     Phone:  +61 8 343 3160
Unix Systems Programmer          Fax:    +61 8 349 6939
Academic Computing Service       E-mail: ccdn@levels.sait.oz.au
SA Institute of Technology       Post:   The Levels, South Australia, 5095

guy@auspex.auspex.com (Guy Harris) (09/24/89)

>What's wrong with cut?

It's not present on all flavors of UNIX, although I think
publicly-available reimplementations do exist.