[GRASS-dev] Re: grass-dev Digest, Vol 3, Issue 8

When I get back, should I go through and get rid of all occurrences of eval
exec?

I noticed that Cedric introduced a different form "exec $cmd [list arg arg
art...]

Is this even better or unnecessary?

Michael
__________________________________________
Michael Barton, Professor of Anthropology
School of Human Evolution & Social Change
Center for Social Dynamics & Complexity
Arizona State University

phone: 480-965-6213
fax: 480-965-7671
www: http://www.public.asu.edu/~cmbarton

From: <grass-dev-request@grass.itc.it>
Reply-To: <grass-dev@grass.itc.it>
Date: Wed, 5 Jul 2006 08:35:59 +0200
To: <grass-dev@grass.itc.it>
Subject: grass-dev Digest, Vol 3, Issue 8

The above should be:

exec gdal_translate $path.ppm $path.tif -of GTIFF
exec rm $path.ppm

I strongly suspect that the same issue applies to most (if not all) of
the other occurrences of "eval exec ..." in gis.m (a quick "grep"
finds 50 of them).

Michael Barton wrote:

When I get back, should I go through and get rid of all occurrences of eval
exec?

I noticed that Cedric introduced a different form "exec $cmd [list arg arg
art...]

If you have individual arguments, there should be no eval, just:

  exec $cmd $arg1 $arg2

etc.

If you have a list of arguments, then the correct idiom is:

  eval [concat [list exec $cmd $arg1 $arg2] $otherargs]
or:
  eval exec [concat [list $cmd $arg1 $arg2] $otherargs]
or:
  eval exec $cmd [concat [list $arg1 $arg2] $otherargs]

Although the last one is only correct if it is known that $cmd cannot
contain spaces; don't use it if $cmd might be an absolute pathname (on
Windows, it might be in the "Program Files" directory).

The main point here is that eval will treat each argument as a list.
If any of the arguments /aren't/ lists, they have to be inserted into
a list so that they aren't themselves treated as lists and broken into
multiple elements if they contain spaces.

An example:

  set mapname "elevation.dem"
  set filename "/cygdrive/c/Documents and Settings/glynn/My Documents/elev.ppm"
  exec r.out.ppm input=$mapname output=$filename

The actual command will be:

  argv[0] = 'r.out.ppm'
  argv[1] = 'input=elevation.dem'
  argv[2] = 'output=/cygdrive/c/Documents and Settings/glynn/My Documents/elev.ppm'

No problem there, but with "eval exec ...":

  eval exec r.out.ppm input=$mapname output=$filename

$filename would get split into multiple arguments:

  argv[0] = 'r.out.ppm'
  argv[1] = 'input=elevation.dem'
  argv[2] = 'output=/cygdrive/c/Documents'
  argv[3] = 'and'
  argv[4] = 'Settings/glynn/My'
  argv[5] = 'Documents/elev.ppm'

A similar issue applies to shell scripts; several of the scripts in
etc/gm/scripts use "eval exec ..." unnecessarily, e.g. r.recode.file:

  eval `exec r.recode input=$GIS_OPT_INPUT output=$GIS_OPT_OUTPUT < $GIS_OPT_RULES_FILE`

This will fail if $GIS_OPT_RULES_FILE contains spaces. The correct
formulation is:

  exec r.recode "input=$GIS_OPT_INPUT" "output=$GIS_OPT_OUTPUT" < "$GIS_OPT_RULES_FILE"

Also, note the use of double quotes around each argument; this
prevents it being split if the variable contains spaces (this is one
signficant difference between shell syntax and Tcl syntax; Tcl won't
split variable expansions unless forced to through the use of eval).

Quotes aren't strictly necessary for the input= and output= options,
because map names aren't allowed to contain spaces. But it won't hurt
either, and it's good practice to put quotes around all variable
expansions unless you specifically want the expansion to be split into
words.

They are necessary for the redirect filename, as that could contain
spaces.

However, this won't work work for the scripts which construct a
command using e.g. cmd="$cmd something=$GIS_OPT_SOMETHING", because
Bourne-shell doesn't have any support for lists (recent versions of
bash have arrays, but those are highly non-portable). There isn't any
robust solution to that issue, although using single quotes will help.

--
Glynn Clements <glynn@gclements.plus.com>