zsh-users
 help / color / mirror / code / Atom feed
* Zsh functionality similar to Perl 'map'?
@ 2009-11-20 16:03 Benjamin R. Haskell
  2009-11-20 19:23 ` Bart Schaefer
  2009-11-20 20:31 ` Philippe Troin
  0 siblings, 2 replies; 3+ messages in thread
From: Benjamin R. Haskell @ 2009-11-20 16:03 UTC (permalink / raw)
  To: Zsh Users

I frequently find myself diff'ing files that have minor differences I'd 
like to filter out.  E.g. this gem from my historyfile:

diff -ur =(LD_LIBRARY_PATH=/opt/chromium.org/lib ldd /opt/chromium.org/chrome-linux/chrome | perl -lpwe 's/\(.*\)//' | sort | uniq) =(ldd /opt/chromium.org/chrome-linux/chrome | perl -lpwe 's/\(.*\)//' | sort | uniq)

(That is: find the differences in the loaded libraries for the Linux 
version of Chromium, depending on whether LD_LIBRARY_PATH contains 
/opt/chromium.org/lib)

These diffs follow the general pattern:

diff -ur =(do-something-1 | filter) =(do-something-2 | filter)

My question is: is there a nice way to 'map' this, so I don't have to 
type/edit the '| filter' portion twice?  The filter portion often changes, 
and is usually incrementally developed.

(E.g. in the Chromium case, I have the consecutive commands:
diff -ur =(LD_LIBRARY_PATH=/opt/chromium.org/lib ldd /opt/chromium.org/chrome-linux/chrome) =(ldd /opt/chromium.org/chrome-linux/chrome)
diff -ur =(LD_LIBRARY_PATH=/opt/chromium.org/lib ldd /opt/chromium.org/chrome-linux/chrome | perl -lpwe 's/\(.*\)//') =(ldd /opt/chromium.org/chrome-linux/chrome | perl -lpwe 's/\(.*\)//')
diff -ur =(LD_LIBRARY_PATH=/opt/chromium.org/lib ldd /opt/chromium.org/chrome-linux/chrome | perl -lpwe 's/\(.*\)//' | sort | uniq) =(ldd /opt/chromium.org/chrome-linux/chrome | perl -lpwe 's/\(.*\)//' | sort | uniq)
)

I suspect most people's preferred solutions will involve functions... 
something along the lines of:

function filter () { perl -lpwe 's/\(.*\)//' | sort | uniq } ; diff -ur =(blah-1 | filter) =(blah-2 | filter)

But I was wondering if there was another way that didn't disrupt the flow 
as much.  (I dislike that the filter function ends up getting 'fronted', 
to use the linguistic term.  It's kind of like saying, "A butter knife, he 
spread the jam with it and the jelly with it," when I'd rather say, "He 
spread the jam and the jelly with a butter knife," or even "He spread 
with a butter knife the jam and the jelly.")

Plus, this isn't the best or most-general example.  Often the '| filter' 
part is actually run on two different files, rather than piped-in.  (So:
diff -ur =(filter file1) =(filter file2)
)

Ideally, it'd end up as something like:

diff -ur =({do-something1,do-something2} | filter)
or
diff -ur =(filter {file1,file2})

...and, yes, I know that's a *huge* stretch.  And, maybe my Perl bias for 
map'ping everything is showing, but still, figured I'd ask.

Thanks,
Ben


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

* Re: Zsh functionality similar to Perl 'map'?
  2009-11-20 16:03 Zsh functionality similar to Perl 'map'? Benjamin R. Haskell
@ 2009-11-20 19:23 ` Bart Schaefer
  2009-11-20 20:31 ` Philippe Troin
  1 sibling, 0 replies; 3+ messages in thread
From: Bart Schaefer @ 2009-11-20 19:23 UTC (permalink / raw)
  To: Zsh Users

On Nov 20, 11:03am, Benjamin R. Haskell wrote:
}
} Ideally, it'd end up as something like:
} 
} diff -ur =({do-something1,do-something2} | filter)
} or
} diff -ur =(filter {file1,file2})
} 
} ...and, yes, I know that's a *huge* stretch.  And, maybe my Perl bias for 
} map'ping everything is showing, but still, figured I'd ask.

Have a look at http://www.zsh.org/mla/users/2006/msg00832.html

There's a trick to replacing $(...) with =(...).  If I write

    setopt extendedglob
    x=(a b c)
    cat ${x/(#b)(*)/=(echo foo $match)}

I get 

    foo match
    foo match
    foo match

because $match is being expanded before it has been set by the (#b)
operator.  It's entirely possible this is a bug.  The workaround is to
single-quote the contents as in =('...'):

    cat ${x/(#b)(*)/=('echo foo $match')}

    foo a
    foo b
    foo c

I haven't delved into whether this is explainable with the normal
order-of-expansion rules.  Anyway, throwing this all together in a
very non-obvious way, you can write:

diff -ur ${${(A)reply::={file1,file2}}/(#b)(*)/=('filter $match')}

Where the parts you care about manipulating are names in {file1,file2}
and of course the filter.  "reply" is used as a dummy array variable
for the ::= assigment, pick any name that won't clobber something you
are interested in.  Quoting of spaces or other special characters in
the file names may be a fairly unpleasant exercise.


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

* Re: Zsh functionality similar to Perl 'map'?
  2009-11-20 16:03 Zsh functionality similar to Perl 'map'? Benjamin R. Haskell
  2009-11-20 19:23 ` Bart Schaefer
@ 2009-11-20 20:31 ` Philippe Troin
  1 sibling, 0 replies; 3+ messages in thread
From: Philippe Troin @ 2009-11-20 20:31 UTC (permalink / raw)
  To: Benjamin R. Haskell; +Cc: Zsh Users

"Benjamin R. Haskell" <zsh@benizi.com> writes:

> I frequently find myself diff'ing files that have minor differences I'd 
> like to filter out.  E.g. this gem from my historyfile:
> 
> diff -ur =(LD_LIBRARY_PATH=/opt/chromium.org/lib ldd /opt/chromium.org/chrome-linux/chrome | perl -lpwe 's/\(.*\)//' | sort | uniq) =(ldd /opt/chromium.org/chrome-linux/chrome | perl -lpwe 's/\(.*\)//' | sort | uniq)
> 
> (That is: find the differences in the loaded libraries for the Linux 
> version of Chromium, depending on whether LD_LIBRARY_PATH contains 
> /opt/chromium.org/lib)
> 
> These diffs follow the general pattern:
> 
> diff -ur =(do-something-1 | filter) =(do-something-2 | filter)
> 
> My question is: is there a nice way to 'map' this, so I don't have to 
> type/edit the '| filter' portion twice?  The filter portion often changes, 
> and is usually incrementally developed.
> 
> (E.g. in the Chromium case, I have the consecutive commands:
> diff -ur =(LD_LIBRARY_PATH=/opt/chromium.org/lib ldd /opt/chromium.org/chrome-linux/chrome) =(ldd /opt/chromium.org/chrome-linux/chrome)
> diff -ur =(LD_LIBRARY_PATH=/opt/chromium.org/lib ldd /opt/chromium.org/chrome-linux/chrome | perl -lpwe 's/\(.*\)//') =(ldd /opt/chromium.org/chrome-linux/chrome | perl -lpwe 's/\(.*\)//')
> diff -ur =(LD_LIBRARY_PATH=/opt/chromium.org/lib ldd /opt/chromium.org/chrome-linux/chrome | perl -lpwe 's/\(.*\)//' | sort | uniq) =(ldd /opt/chromium.org/chrome-linux/chrome | perl -lpwe 's/\(.*\)//' | sort | uniq)
> )
> 
> I suspect most people's preferred solutions will involve functions... 
> something along the lines of:
> 
> function filter () { perl -lpwe 's/\(.*\)//' | sort | uniq } ; diff -ur =(blah-1 | filter) =(blah-2 | filter)
> 
> But I was wondering if there was another way that didn't disrupt the flow 
> as much.  (I dislike that the filter function ends up getting 'fronted', 
> to use the linguistic term.  It's kind of like saying, "A butter knife, he 
> spread the jam with it and the jelly with it," when I'd rather say, "He 
> spread the jam and the jelly with a butter knife," or even "He spread 
> with a butter knife the jam and the jelly.")
> 
> Plus, this isn't the best or most-general example.  Often the '| filter' 
> part is actually run on two different files, rather than piped-in.  (So:
> diff -ur =(filter file1) =(filter file2)
> )

You could always do this:

filterdiff () {
    emulate -L zsh
    local i a
    local -a opts
    local -a args
    while [[ $# > 0 ]]
    do
        a=$1 
        shift
        case $a in
            (--)  args=($args $*) 
                  break 
                  ;;
            (-?*) opts=($opts $a)
                  ;;
            (*)   args=($args $a)
                  ;;
        esac
    done
    if (( $#args != 3 ))
    then
        print "usage: $0 [options] <filter> <file1> <file2>" >&2
        return 1
    fi
    diff $opts -- <( eval $args[1] < $args[2] ) <( eval $args[1] < $args[3] )
}

Use it like this:

  filterdiff 'tr a-z A-Z | tac' /etc/passwd /etc/hosts

You have to quote the filter of course...
 
> Ideally, it'd end up as something like:
> 
> diff -ur =({do-something1,do-something2} | filter)
> or
> diff -ur =(filter {file1,file2})
> 
> ...and, yes, I know that's a *huge* stretch.  And, maybe my Perl bias for 
> map'ping everything is showing, but still, figured I'd ask.

I'm afraid this fancy syntax won't be possible.  Well, you could by
hacking the completion system, but that would be unmaintainable 

Phil.


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

end of thread, other threads:[~2009-11-20 20:38 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-11-20 16:03 Zsh functionality similar to Perl 'map'? Benjamin R. Haskell
2009-11-20 19:23 ` Bart Schaefer
2009-11-20 20:31 ` Philippe Troin

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).