out-string behaviour and strings in general

This topic contains 7 replies, has 3 voices, and was last updated by  Garegin Asatryan 2 years, 4 months ago.

  • Author
    Posts
  • #27779

    Garegin Asatryan
    Participant

    I am still not clear as to how strings work in powershell.
    The commands below are for educational purposes, hence they look contrived.

    If I do
    echo "a b" | ls ls shows the contents of folder "a b".
    But If I do
    echo "a b" | out-string | ls It throws an error
    while adding -stream to out-string make it work. The documentation says this
    "By default, Out-String accumulates the strings and returns them as a single string, but you can use the stream parameter to direct Out-String to return one string at a time. "
    It seems the opposite. Without -Stream it should be one string and yet ls is interpreting it as separate strings.

  • #27780

    Don Jones
    Keymaster

    First, stop using Echo. It doesn't (maybe) do what you think. Try Write instead (write-output).

    And, Out-String is designed to take objects and output a string representation. If you have a string, there's no need to convert it to a string. It might be that the contrived example is obscuring your point of confusion?

    Keep in mind this isn't Cmd.exe, it's an object oriented shell. There's a lot going on under the hood that you may not realize, and that can cause unexpected behavior.

    For example, "a b" is a single string, not two strings. A command that returns multiple objects would be converted to one string without -stream, and each object would be a string with -stream. This relates to the PowerShell pipeline, and how it streams objects one at a time.

    Out-String is designed for a specific purpose, and that isn't really to feed other commands. Out- commands should usually be the last command on the line. Perhaps a different example to approach your question?

  • #27781

    Don Jones
    Keymaster

    (And I should rather say that Echo is perhaps misleading; it's an unusual command to see in PowerShell. You should be using Write-Host or Write-Output, which are clearer about what they're doing. Echo kind of implies one, but it does the other; not knowing your knowledge level, I don't know which you intended.)

  • #27782

    Garegin Asatryan
    Participant

    just to be clear, echo is an alias to write-output, right?(at least get-alias says so)
    The reason I was being a complete fool with out-string was to understand if cmdlets could take plain strings as arguments, instead of the usual objects.
    If "a b" is a single string, why does out-string piped to get-childitem throw an error, while without out-string- it works? The obvious guess is that out-string does something weird to the string to make it not acceptable by get-childitem. The error is below

    ls : Illegal characters in path.
    At line:1 char:28
    + echo "a b" | Out-String | ls
    + ~~
    + CategoryInfo : InvalidArgument: (C:\Users\garegin\a b
    :String) [Get-ChildItem], ArgumentException
    + FullyQualifiedErrorId : ItemExistsArgumentError,Microsoft.PowerShell.Commands.GetChildItemCommand

    ls : Cannot find path 'C:\Users\garegin\a b
    ' because it does not exist.
    At line:1 char:28
    + echo "a b" | Out-String | ls
    + ~~
    + CategoryInfo : ObjectNotFound: (C:\Users\garegin\a b
    :String) [Get-ChildItem], ItemNotFoundException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand

  • #27785

    Max Kozlov
    Participant

    Take a look at this:

    PS D:\> ("a b").Length
    3
    PS D:\> ("a b" | Out-string -stream).Length
    3
    PS D:\> ("a b" | Out-string).Length
    5
    PS D:\> ("a b" | Out-string).ToCharArray() | %{ [int]$_ }
    97
    32
    98
    13
    10

    You See ?
    Out-string Add Carriage return to string because of its nature – [help]"Sends objects to the host as a series of strings."

    Don't mix host oriented cmdlets with others and you do not get such problems

  • #27786

    Max Kozlov
    Participant

    btw, it you do not have 'a b' folder you can see difference in error messages:

    PS C:\> 'a b' | ls
    ls : Cannot find path 'C:\a b' because it does not exist.
    At line:1 char:9
    + 'a b' | ls
    + ~~
    + CategoryInfo : ObjectNotFound: (C:\a b:String) [Get-ChildItem], ItemNotFoundException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand

    PS C:\> 'a b' | out-string | ls
    ls : Illegal characters in path.
    At line:1 char:22
    + 'a b' | out-string | ls
    + ~~
    + CategoryInfo : InvalidArgument: (C:\a b
    :String)
    [Get-ChildItem], ArgumentException
    + FullyQualifiedErrorId : ItemExistsArgumentError,Microsoft.PowerShell.Commands.GetChildItemCommand

    ls : Cannot find path 'C:\a b
    ' because
    it does not exist.
    At line:1 char:22
    + 'a b' | out-string | ls
    + ~~
    + CategoryInfo : ObjectNotFound: (C:\a b
    :String) [Get-ChildItem], ItemNotFoundException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand

  • #27792

    Don Jones
    Keymaster

    To be clear, there's no such thing as a "plain string." Strings are also objects.

    And I wasn't calling you foolish; I didn't understand where the question was going, and I didn't understand you background knowledge or experience. I apologize if it seemed rude – I just didn't know where to start.

    I don't have access to a shell right now, but have you tried a Trace-Command that includes pipeline binding? It'd reveal some more details about what's happening in both instances, and comparing the two might be useful to understand what the shells doing.

  • #27798

    Garegin Asatryan
    Participant

    "I don't have access to a shell right now, but have you tried a Trace-Command that includes pipeline binding? It'd reveal some more details about what's happening in both instances, and comparing the two might be useful to understand what the shells doing. "

    Thanks. I also discovered the .count property to see how many objects are in the pipe.

You must be logged in to reply to this topic.