Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: ${name/pattern/repl} with negated pattern



On Thu, 15 May 2014 14:26:41 +0200
Roman Neuhauser <neuhauser@xxxxxxxxxx> wrote:
>     > a=(x/foo y/bar x/baz y/qux)
>     > echo ${a/#^x\/*} # wtf
>     /foo /baz
> 
> what's happening here?

It took me a while to work it out.

/# means "find this pattern at the head of the string and replace it".
By the usual rule it's the longest pattern that matches.  Note it's not
anchored to the end of the string --- I think you need ${a/#%^x\/*} if
you stick with "/", however see the discussion below.

^ means "anything, and I do mean anything, that doesn't match the
following pattern".  You can see that the initial "x" doesn't match the
pattern, because the pattern requires the "/" to match.  However, x/ or
anything longer does match the pattern because of the *.  So the longest
string at the head that doesn't match the pattern is "x".  So it removes
that.

This has no effect on the y/... bits; the whole string of those fails to
match x/*, so they're removed completely.

I think you'd be better off with ${a:#^x/*}, which removes anything that
matches the pattern after from beginning to end, with no funny business
about anchoring.  It still has the oddity that you need to negate the
pattern after, but as far as I can see this always works logically.

I think the way to do it without negating the pattern is to use the (M)
flag, saying substitute the matched part, rather than the rest --- the
matched part here would usually be everything you're throwing away with
this operator.

So try ${(M)a:#x/*}.

pws



Messages sorted by: Reverse Date, Date, Thread, Author