[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Pattern extraction and Wildcard expansion
- To: hawkwind.utcs.toronto.edu
- Subject: Re: Pattern extraction and Wildcard expansion
- From: rog
- Date: Thu, 14 Dec 2000 19:03:03 -0500
> 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.