다음을 통해 공유


How does Match-String with with Pipelines of objects?

In our newsgroup (Microsoft.Public.Windows.Server.Scripting) , Vasu asked about how match-string works in pipelines:

Here is what I observe:
1. MSH C:\> get-alias
 ..truncated..
Alias           ri                                   remove-item
Alias           rni                                  rename-item
..truncated..

2. MSH C:\> get-alias | match-string ri
ri
MSH C:\>

The question is why did the string "ri" get emitted instead of the alias record.

So what is going on here?

Match-String works on Streams of STRINGS.  When you pass it a string of OBJECTS, the MONAD engine converts those objects to strings before passing them to Match-String.  Thus the following 2 commands are functionaly equivalent:

get-alias | match-string "ri"
get-alias | foreach {"$_"} |match-string "ri"

Converting an object to a string is accomplished by call that object's ToString() method (vs using MONAD's formating subsystem).  Notice the difference - the first uses Monad's formating and the second is the object's ToString() 

MSH> (gal ri)

CommandType Name Definition
----------- ---- ----------
Alias ri remove-item

MSH> (gal ri).ToString()
ri
MSH>

If you wanted Match-String to work on the Monad formatted output, you'll need to get that as a string.  Here is the thing to grok about our outputing.  When your command sequence emits a stream of strings, we emit it without processing.  If  instead, your command sequence emits a stream of objects, then we redirect those objects to the command Out-Default.  Out-Default looks at the type of the object and the registered formating metadata to see if there is a default view for that object type.  A view defines a FORMATTER and the metadata for that command.  Most objects get vectored to either Format-Table or Format-List (though they could go to Format-Wide or Format-Custom).  THESE FORMATTERS DO NOT EMIT STRINGS!  You can see this for yourself by the following:

MSH> gps |ft |group {$_.GetType().name} |ft Count,Name -auto

Count Name
----- ----
1 FormatStartData
1 GroupStartData
53 FormatEntryData
1 GroupEndData
1 FormatEndData

These formating records are then vectored to an OUT-xxx command to be rendered into the appropriate data for a particular output device.  By default, they go to Out-Host but you can pipe this to Out-File, Out-Printer or Out-String.  (NOTE: these OUT-xxx commands are pretty clever, if you pipe formating objects to them, they'll render them.  If you pipe raw object to them, they'll first call the appropriate formatter and then render them.)

So to make match-string work against the string version of Monad's output, you'd do this:

MSH> get-alias | out-string -stream | match-string "ri"
Alias clv clear-variable
Alias gdr get-drive
Alias gv get-variable
Alias ndr new-drive
Alias nv new-variable
Alias rdr remove-drive
Alias ri remove-item
Alias rv remove-variable
...

Notice a couple things 1) you had to say "Out-String -STREAM" (if you didn't say -STREAM you would have gotten a single string) 2) now match-string matches any line that has an "ri" in it not just the ones where the NAME has an "ri" in it.

Think about the last statement 'just the ones where the NAME has an "ri" in it'. One of the things we designed Monad to do was to give you an experience where you think it, you type it, you get it. So let's say it, "I want to GET the ALIASes WHERE the NAME matches the string RI". Now lets type it:

MSH> GET-ALIAS |WHERE {$_.NAME -match "ri"}

CommandType Name Definition
----------- ---- ----------
Alias ri remove-item
Alias write write-object

It take a while to stop thinking in terms of streams of text and start thinking in terms of streams of objects.  The benefit is that once you do this, you begin to ask questions in a way that makes it really easy to answer.

Enjoy!

Jeffrey Snover
Monad Architect

Comments

  • Anonymous
    April 15, 2006
    This is very interesting. Can you elaborate on what happens when one types this:

    MSH> (gal) -match "ri"

    CommandType     Name                       Definition
    -----------     ----                       ----------
    Alias           ri                         remove-item
    Alias           write                      write-object

    Thanks,
    Jacques
  • Anonymous
    April 16, 2006
    (gal) -match "ri" is functionally equivalent to:
    gal |where {""+$_ -match "ri"}

    So what is going on is that every alias is being cast to a string using ToString().  If that string matches "ri", then the alias OBJECT is passed on.

    Jeffrey Snover
  • Anonymous
    April 17, 2006
    Cool. Thanks for the explanation! I missed the "out-string" part.
    Is there a designed output for every object when its ToString method is called (is it the same as in Java where it is the string represenation of an object, which is usually its name).?

    Just out of curiosity, is there a designed way to see things that "don't match" using match-string. I am thinking of something like a 'grep -v'.
  • Anonymous
    April 17, 2006
    > Is there a designed output for every object when its ToString method is called
    Its up the the implementor of the class.  Some people do a good job, others, not so good.

    > is there a designed way to see things that "don't match" using match-string. I am thinking of something like a 'grep -v'.

    No.  Please file a feature request.

    Jeffrey Snover
  • Anonymous
    April 18, 2006
    a construct like this could help :

    (get-alias | out-string -stream) -notmatch "ri"

    but a "don't match" on select-object is still welcome ;-)

    gr //o//
  • Anonymous
    April 24, 2006
    Great post. Just curious though why you didn't rename Out-Default to Format-Default since it is a formatter and not an output device?  Is it because it also uses Out-Host?
  • Anonymous
    April 24, 2006
    out-default deserves a full blog entry of it's own.  It is an amazing puppy.  Basically it is a very intelligent dispatcher that figures out what needs to be done to deliver a good user experience.  Sometimes it does nothing, other times it invokes an outter, other times in invokes a formatter and then an outter.  We consider naming this PERFORM-MAGIC but it turns out that PERFORM is not one of our sanctioned verbs.  :-)

    Jeffrey Snover
  • Anonymous
    January 21, 2009
    PingBack from http://www.keyongtech.com/2927801-msh-match-string-behavior