zsh-users
 help / color / mirror / code / Atom feed
* Fun zsh trick for today
@ 2000-06-10 22:50 Bart Schaefer
  0 siblings, 0 replies; 12+ messages in thread
From: Bart Schaefer @ 2000-06-10 22:50 UTC (permalink / raw)
  To: zsh-users

Some of you are probably familiar with Perl's "grep" function; given a
regular expression and an array, it returns all the elements of the array
that match the expression.  A common Perl idiom is

	open(FILE, "<somefile");
	@result = grep(/pat/, <FILE>);

Where <FILE> slurps somefile into memory as an array of lines.

Did you know that zsh can do that, too?

If you load the mapfile module:

	zmodload -i zsh/mapfile

Then you can write Perl's open(FILE, "<somefile") as

	$mapfile[somefile]

And you can write <FILE> as

	${(f)mapfile[somefile]}

with the caveat that blank lines are stripped out.

(If you're using zsh 3.0.x or can't load the mapfile module, you can do the
same thing with "${(f)$(<somefile)}".  It's just not quite as efficient,
and you have to remember to use the double quotes around it.)

You can write grep(/pat/, array) as

	${(M)array:#*pat*}

with the caveat that pat is a glob pattern -- but with extendedglob set,
zsh's glob patterns are full regular expressions, although with a non-sed-
like syntax because of the different special meaning of '*'.

So finally, @result = grep(/pat/, <FILE>) is

	result=(${(M)${(f)mapfile[somefile]}:#*pat*})

Try, for example, ${(M)#${(f)mapfile[ChangeLog]}:#*Sven*} to see that there
are 1023 mentions of Sven's name in zsh's ChangeLog file.  (I only managed
265 "Bart"s; in fact, there are only 475 lines with the word "zsh"!)

-- 
Bart Schaefer                                 Brass Lantern Enterprises
http://www.well.com/user/barts              http://www.brasslantern.com

Zsh: http://www.zsh.org | PHPerl Project: http://phperl.sourceforge.net   


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Fun zsh trick for today
       [not found] <no.id>
  2000-06-14 13:43 ` Matthias Kopfermann
  2000-06-14 15:33 ` Matthias Kopfermann
@ 2000-06-14 16:31 ` Matthias Kopfermann
  2 siblings, 0 replies; 12+ messages in thread
From: Matthias Kopfermann @ 2000-06-14 16:31 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: Zsh users list

On Wed, Jun 14, 2000 at 04:52:10PM +0100, Peter Stephenson wrote:
>  [ ..] #deleted for saving space 

Thanks, peter! That's what i needed to follow.
Nesting makes me quite dizzy but that may be better after some
decades :)


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Fun zsh trick for today
  2000-06-14 15:33 ` Matthias Kopfermann
@ 2000-06-14 15:52   ` Peter Stephenson
  0 siblings, 0 replies; 12+ messages in thread
From: Peter Stephenson @ 2000-06-14 15:52 UTC (permalink / raw)
  To: Zsh users list

> > 
> > hosts=(${${${${(f)"$(<$HOME/.ssh/known_hosts)"}:#[^0-9]*}%%\ *}%%,*
> > })
> hu %) Could someone explain these hieroglyphs for a simple soul
> like me? %%)

that's why this is deferred till (the unwritten) chapter 5 of the user
guide, instead of the chapter on basic syntax...

$(<$HOME/.ssh/known_hosts)

is a standard substitution: it simply takes the file and sticks it onto the
command line at that point.

"$(<$HOME/.ssh/known_hosts)"

Now it's quoted, it doesn't do word splitting; we have the complete file as
one word.  From now on, we do nested substitutions: you just have to
remember that ${${...}}, or ${${...}}, essentially does nothing but an
ordinary parameter expansion --- the whole point is the extra bits tacked
on with each extra set of braces.  For example, we're now going to do

${(f)"$(<$HOME/.ssh/known_hosts)"}

so we get the same answer, but with the effect of putting the (f) flag at
the start, which splits the result of that into lines.  So we now have the
entire file as an array, one line per element.

${${(f)"$(<$HOME/.ssh/known_hosts)"}:#[0-9]*}

(Clint says the ^ shouldn't be there) says take the array elements (= lines
of the original file) which completely match [0-9]*, i.e. elements
beginning with a digit, and remove them, which is what ${...:#...} is for.

${${${(f)"$(<$HOME/.ssh/known_hosts)"}:#[0-9]*}%%\ *}

takes the result of that, and strips off from the end the largest pattern
matching ' *', i.e. a space followed by anything else, in other words it
leaves the largest initial string with no whitespace, which is a hostname
(this is a standard ${...%%...} which even ordinary shells do, although not
nested).

${${${${(f)"$(<$HOME/.ssh/known_hosts)"}:#[0-9]*}%%\ *}%%,*}

does another strip at the end, this time for everything from the first
comma on.  If there wasn't a comma, nothing changes.  You could have
combined the last two as ${...%%[[:blank:],]*}, or something.

-- 
Peter Stephenson <pws@cambridgesiliconradio.com>
Cambridge Silicon Radio, Unit 300, Science Park, Milton Road,
Cambridge, CB4 0XL, UK                          Tel: +44 (0)1223 392070


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Fun zsh trick for today
       [not found] <no.id>
  2000-06-14 13:43 ` Matthias Kopfermann
@ 2000-06-14 15:33 ` Matthias Kopfermann
  2000-06-14 15:52   ` Peter Stephenson
  2000-06-14 16:31 ` Matthias Kopfermann
  2 siblings, 1 reply; 12+ messages in thread
From: Matthias Kopfermann @ 2000-06-14 15:33 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: Zsh users list

> 
> hosts=(${${${${(f)"$(<$HOME/.ssh/known_hosts)"}:#[^0-9]*}%%\ *}%%,*
> })
hu %) Could someone explain these hieroglyphs for a simple soul
like me? %%)


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Fun zsh trick for today
  2000-06-14 14:09     ` Ollivier Robert
@ 2000-06-14 15:02       ` Fletch
  0 siblings, 0 replies; 12+ messages in thread
From: Fletch @ 2000-06-14 15:02 UTC (permalink / raw)
  To: Ollivier Robert; +Cc: zsh-users

>>>>> "Ollivier" == Ollivier Robert <roberto@eurocontrol.fr> writes:

    Ollivier> According to Clint Adams:
    >> zmodload -i zsh/mapfile
    >> hosts=(${(@)${(@)${(M)${(f)mapfile[$HOME/.ssh/known_hosts]}:#[^0-9]*}%%\
    >> *}%%,*})

    Ollivier> <humour> I'm beginning to see zsh turning up into
    Ollivier> perl-sh... :-) </humour> 


        Well, I've got a patch off of 3.1.6 that embeds a perl
interpreter as a loadable module and let's you call perl subroutines
as zsh functions . . . :)

        I really need to update it work with 3.1.9, though.

-- 
Fletch                | "If you find my answers frightening,       __`'/|
fletch@phydeaux.org   |  Vincent, you should cease askin'          \ o.O'
678 443-6239(w)       |  scary questions." -- Jules                =(___)=
                      |                                               U


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Fun zsh trick for today
  2000-06-14 14:15     ` Peter Stephenson
  2000-06-14 14:21       ` Peter Stephenson
  2000-06-14 14:27       ` Clint Adams
@ 2000-06-14 14:37       ` Bart Schaefer
  2 siblings, 0 replies; 12+ messages in thread
From: Bart Schaefer @ 2000-06-14 14:37 UTC (permalink / raw)
  To: Peter Stephenson, Zsh users list

On Jun 14,  3:15pm, Peter Stephenson wrote:
} Subject: Re: Fun zsh trick for today
}
} Plus you don't need all those (@)'s once parameter substitution already has
} arrays, which (f) provides.  The only trick here is using double quotes to
} get whole lines for splitting.  I think the following should work in 3.0.8
} (can't quite remember if the trick of putting double quotes in the middle
} made its way back

The quotes in the middle is in 3.0.7, as part of the "minimal forwards
compatibility" effort.

There is a small bug with them in both versions, though; you can't take
the length of the quoted part:

zagzig[57] echo ${#"${(f)$(<file)}"}
zsh: bad substitution
zagzig[60] echo ${#${"${(f)$(<ChangeLog)}"}}
8017

It works with ${=...} and ${~...}, but not with ${#...}.

-- 
Bart Schaefer                                 Brass Lantern Enterprises
http://www.well.com/user/barts              http://www.brasslantern.com

Zsh: http://www.zsh.org | PHPerl Project: http://phperl.sourceforge.net   


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Fun zsh trick for today
  2000-06-14 14:15     ` Peter Stephenson
  2000-06-14 14:21       ` Peter Stephenson
@ 2000-06-14 14:27       ` Clint Adams
  2000-06-14 14:37       ` Bart Schaefer
  2 siblings, 0 replies; 12+ messages in thread
From: Clint Adams @ 2000-06-14 14:27 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: Zsh users list

> hosts=(${${${${(f)"$(<$HOME/.ssh/known_hosts)"}:#[^0-9]*}%%\ *}%%,*})

This has the opposite effect as desired (i.e., it returns an array
containing only those entries beginning with digits).  This does what I
want (except for omitting things like 3stop.com):

hosts=(${${${${(f)"$(<$HOME/.ssh/known_hosts)"}:#[0-9]*}%%\ *}%%,*})


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Fun zsh trick for today
  2000-06-14 14:15     ` Peter Stephenson
@ 2000-06-14 14:21       ` Peter Stephenson
  2000-06-14 14:27       ` Clint Adams
  2000-06-14 14:37       ` Bart Schaefer
  2 siblings, 0 replies; 12+ messages in thread
From: Peter Stephenson @ 2000-06-14 14:21 UTC (permalink / raw)
  To: Zsh users list

I wrote:
> or
> 
> hosts=("${(@)${(@)${(@M)${(@f)"$(<$HOME/.ssh/known_hosts)"}:#[^0-9]*}%%\ *}%%
> ,*
> }")
                                ^                          ^
erk, sorry, remove the double quotes in the middle in this case.

-- 
Peter Stephenson <pws@cambridgesiliconradio.com>
Cambridge Silicon Radio, Unit 300, Science Park, Milton Road,
Cambridge, CB4 0XL, UK                          Tel: +44 (0)1223 392070


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Fun zsh trick for today
  2000-06-14 13:57   ` Clint Adams
  2000-06-14 14:09     ` Ollivier Robert
@ 2000-06-14 14:15     ` Peter Stephenson
  2000-06-14 14:21       ` Peter Stephenson
                         ` (2 more replies)
  1 sibling, 3 replies; 12+ messages in thread
From: Peter Stephenson @ 2000-06-14 14:15 UTC (permalink / raw)
  To: Zsh users list

> I'm no Bart-guru, but here's an application of his trick that I find useful
> for the new completion system:
> 
> zmodload -i zsh/mapfile
> hosts=(${(@)${(@)${(M)${(f)mapfile[$HOME/.ssh/known_hosts]}:#[^0-9]*}%%\ *}%%
> ,*})
> zstyle ':completion:*:hosts' hosts $hosts

In something like this there's really no gain over doing it using more
ordinary zsh methods, i.e. with $(<...), which doesn't require a module.
Plus you don't need all those (@)'s once parameter substitution already has
arrays, which (f) provides.  The only trick here is using double quotes to
get whole lines for splitting.  I think the following should work in 3.0.8
(can't quite remember if the trick of putting double quotes in the middle
made its way back --- if not, put quotes around the lot and put (@)'s at
the front of all the parameter substitutions).

hosts=(${${${${(f)"$(<$HOME/.ssh/known_hosts)"}:#[^0-9]*}%%\ *}%%,*
})

or

hosts=("${(@)${(@)${(@M)${(@f)"$(<$HOME/.ssh/known_hosts)"}:#[^0-9]*}%%\ *}%%,*
}")

-- 
Peter Stephenson <pws@cambridgesiliconradio.com>
Cambridge Silicon Radio, Unit 300, Science Park, Milton Road,
Cambridge, CB4 0XL, UK                          Tel: +44 (0)1223 392070


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Fun zsh trick for today
  2000-06-14 13:57   ` Clint Adams
@ 2000-06-14 14:09     ` Ollivier Robert
  2000-06-14 15:02       ` Fletch
  2000-06-14 14:15     ` Peter Stephenson
  1 sibling, 1 reply; 12+ messages in thread
From: Ollivier Robert @ 2000-06-14 14:09 UTC (permalink / raw)
  To: zsh-users

According to Clint Adams:
> zmodload -i zsh/mapfile
> hosts=(${(@)${(@)${(M)${(f)mapfile[$HOME/.ssh/known_hosts]}:#[^0-9]*}%%\ *}%%,*})

<humour>
I'm beginning to see zsh turning up into perl-sh... :-)
</humour>
-- 
Ollivier ROBERT -=- Eurocontrol EEC/TEC -=- roberto@eurocontrol.fr
The Postman hits! The Postman hits! You have new mail.


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Fun zsh trick for today
  2000-06-14 13:43 ` Matthias Kopfermann
@ 2000-06-14 13:57   ` Clint Adams
  2000-06-14 14:09     ` Ollivier Robert
  2000-06-14 14:15     ` Peter Stephenson
  0 siblings, 2 replies; 12+ messages in thread
From: Clint Adams @ 2000-06-14 13:57 UTC (permalink / raw)
  To: Matthias Kopfermann; +Cc: Bart Schaefer, zsh-users

> i think, this would be a great feature of the mailinglist, if
> bart or sven or some other guru would give such nice tricks once
> a week or something.
> it makes happy user, at least it made me happy :)

I'm no Bart-guru, but here's an application of his trick that I find useful
for the new completion system:

zmodload -i zsh/mapfile
hosts=(${(@)${(@)${(M)${(f)mapfile[$HOME/.ssh/known_hosts]}:#[^0-9]*}%%\ *}%%,*})
zstyle ':completion:*:hosts' hosts $hosts


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: Fun zsh trick for today
       [not found] <no.id>
@ 2000-06-14 13:43 ` Matthias Kopfermann
  2000-06-14 13:57   ` Clint Adams
  2000-06-14 15:33 ` Matthias Kopfermann
  2000-06-14 16:31 ` Matthias Kopfermann
  2 siblings, 1 reply; 12+ messages in thread
From: Matthias Kopfermann @ 2000-06-14 13:43 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: zsh-users

On Sat, Jun 10, 2000 at 10:50:51PM +0000, Bart Schaefer wrote:
>[ ... amazing information deleted ]

i think, this would be a great feature of the mailinglist, if
bart or sven or some other guru would give such nice tricks once
a week or something.
it makes happy user, at least it made me happy :)

Matthias


^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2000-06-14 16:32 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2000-06-10 22:50 Fun zsh trick for today Bart Schaefer
     [not found] <no.id>
2000-06-14 13:43 ` Matthias Kopfermann
2000-06-14 13:57   ` Clint Adams
2000-06-14 14:09     ` Ollivier Robert
2000-06-14 15:02       ` Fletch
2000-06-14 14:15     ` Peter Stephenson
2000-06-14 14:21       ` Peter Stephenson
2000-06-14 14:27       ` Clint Adams
2000-06-14 14:37       ` Bart Schaefer
2000-06-14 15:33 ` Matthias Kopfermann
2000-06-14 15:52   ` Peter Stephenson
2000-06-14 16:31 ` Matthias Kopfermann

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).