[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Pattern extraction and Wildcard expansion



> and try to execute:
>
>  	; s l*
>
>  Mi intention is to get a list of commands that begin with "l", but there is
>  no output.
>
>  Where is my error?

you've run into a fundamental design issue with es.

in common with rc, es is very careful not to reparse its input.  in
particular, wildcards are expanded once only.  it's perfectly
permissable to have a filename containing a '*' character for example.
a variable containing such a filename as a value will, unlike in the
bourne or korn shells, never be unintentionally expanded when used
later in the script.

what this means is that if you type:

	s x*

the x* gets expanded (or not) there and then.  the function that is
called gets the resulting argument list as a simple list of string.

this makes for a much simpler and more predictable interface.  it
means that, for instance, the s function can count the number of items
in its list reliably.  lazy evaluation of wildcards would mean that a
function:

	fn s pat {
		echo $#pat
		cd /
		echo $#pat
	}

could print two different numbers!  this does happen in bourne shell
derivatives.  for instance, the bourne shell script:

	s() {
		x=$*
		echo $x
		cd /
		echo $x
	}
	s '*'

is likely to print two entirely different things.  this is a huge
source of errors (and security holes) in shell scripts.

i'm actually a little surprised.  i thought that es, of all shells,
might have a globbing (pattern matching) primitive available for user
consumption.  but it appears not.

as far as i'm aware, the best you can do is:

	fn s pat {
		lis = `{for (dir = $path) ls $dir}
		a = <={eval 'result <={~~ $lis ' ^ $pat ^ '}'}
		echo $a^$nl
	}


but that leads you into all sorts of potential trouble if there are
files around containing es metacharacters (e.g.  a file names ';rm -rf
*'...).  not to mention files containing spaces.

if you *really* want to do something like this, you could use a sed
script to mutate the shell wild-card style pattern into a sed-style
pattern, which you could then run over the files.  but even this,
although safer, won't always give correct results.

basically you'd be better off writing a function that took grep-style
patterns than shell-style patterns.  so you might do something like:

	fn s pat {
		{for (dir = $path) ls $dir} |
			grep -e '^' ^ $pat ^ '$'
	}

so you could do:

	s 'l.*'

to get what you wanted.  it's still not perfect, as it won't work with
filenames containing newlines...  but you can't have everything :-)

hope this helps,

  rog.