tags:

views:

144

answers:

4

Hello,

I don't understand why there's a difference on string concatenations in this script. I really don't understand where the whitespace is coming from? Can you tell me what's wrong?

$table = @{
"aaa"=1
}

$x = "qqq"
$y = "rrr"

$table.GetEnumerator() | ForEach-Object { 
Write-Host $_.Key$x            #THIS PRINTS "aaa qqq"
}


Write-Host $x$y   #THIS PRINTS : "qqqrrr"
A: 

What happens if you concatenate the key and the $x?

$_.Key + $x

Write-Host seems to have a syntax where you can input variables and it will separate them: Write-Host (a,b,c) -separator "_"

Perhaps what you're using is shorthand for that?

Joe Philllips
$table.GetEnumerator()|%{ $_.Key + $x} yields aaaqqq. So it's definitely not whitespace after the key. I think Write-Host puts that in to ease reading. But then I don't really know why it doesn't with $x$y
Joey
+2  A: 

It doesn't happen just for hashtable keys. Look at this for instance:

PS > Write-Host $x.Length$y
3 rrr

But $x.Length$y is not a valid expression:

PS > $x.Length$y
Unexpected token 'y' in expression or statement.
At line:1 char:11
+ $x.Length$y <<<<

So what must be happening is that powershell is interpreting $x.Length$y as two separate expressions before passing them to Write-Host, and since there are two of them, Write-Host separates them with a separator.

So what is happening here then?:

PS > Write-Host $x$y
qqqrrr

$x$y isn't a valid expression either:

PS > $x$y
Unexpected token 'y' in expression or statement.
At line:1 char:4
+ $x$y <<<<

However, with double quotes it is a valid string:

PS > "$x$y"
qqqrrr

Powershell must be converting $x$y to a string before passing it to Write-Host as a single argument.

Basically however that is all just guesswork. It sounds plausible to me. The short answer is that you can concatenate your strings together yourself to get rid of the space:

Write-Host ($_.Key + $x)
dangph
I agree with your thoughts and I think that is as close as we will get without one of the PowerShell team commenting.
JasonMArcher
+1  A: 

IMHO, the Powershell parser is taking

Write-Host $_.Key$a

And tokenizing it into two expressions by splitting on the '$'. In effect, issuing two commands to the pipeline:

Write-Host $_.Key
$x

I think this is mostly because you are accessing a property and expanding it into a string next to a variable that when evaluated becomes a string.

The way you should be doing this is:

PS C:\Users\jpogran> $table = @{
>> "aaa"=1
>> }
>>
PS C:\Users\jpogran> $x = "qqq"
PS C:\Users\jpogran> $y = "rrr"
PS C:\Users\jpogran> $table

Name                           Value
----                           -----
aaa                            1
PS C:\Users\jpogran> $table.Getenumerator() | %{ Write-host "$($_.key)$x" }
aaaqqq

The '$()' tells the Powershell parser you want that property on that object expanded, and the value put into the string next to whatever comes after/before.

james

James Pogran
+6  A: 

When processing arguments to a command, the PowerShell parser splits adjacent expressions into discrete arguments if the first fragment is a recognizable expression as is the case with $(). Because PowerShell is object-based, we try to preserve object integrity until we absolutely have to render to a string. If you want to force string expansion put double-quotes around the entire argument sequence as one of the other posters suggested. Note that an argument with a leading character like a$x will be treated as if it was a double-quoted string "a$x". This is because the leading characters are not recognized as a valid expression so we default to treating it as an expandable string.

-bruce

Bruce Payette, Windows PowerShell Team, Microsoft Corp.

Bruce Payette
thanks for your answer Bruce. I learned a lot from it.
teebot.be