From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 8882 invoked from network); 14 Jun 2000 15:52:52 -0000 Received: from sunsite.auc.dk (130.225.51.30) by ns1.primenet.com.au with SMTP; 14 Jun 2000 15:52:52 -0000 Received: (qmail 3505 invoked by alias); 14 Jun 2000 15:52:37 -0000 Mailing-List: contact zsh-users-help@sunsite.auc.dk; run by ezmlm Precedence: bulk X-No-Archive: yes X-Seq: 3160 Received: (qmail 3497 invoked from network); 14 Jun 2000 15:52:37 -0000 Date: Wed, 14 Jun 2000 16:52:10 +0100 From: Peter Stephenson Subject: Re: Fun zsh trick for today In-reply-to: "Your message of Wed, 14 Jun 2000 17:33:34 +0200." <20000614173334.A26995@linux-ws.kg-hittfeld.local> To: zsh-users@sunsite.auc.dk (Zsh users list) Message-id: <0FW5007A8IQXIK@la-la.cambridgesiliconradio.com> Content-transfer-encoding: 7BIT > > > > 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 Cambridge Silicon Radio, Unit 300, Science Park, Milton Road, Cambridge, CB4 0XL, UK Tel: +44 (0)1223 392070