I apologize for this if it is expected behavior however based on the documentation, I believe that setting width should cause the output to be truncated.
-Width
Specifies the number of characters in each line of output. Any additional characters are truncated, not wrapped. If you omit this parameter, the width is determined by the characteristics of the host program. The default value for the Windows PowerShell console is 80 (characters).
$x=''; 1..100 | %{ $x += 'x' }; $x | Out-String -Width 10
# string should be truncated to 10 characters
xxxxxxxxxx
# String is not truncated
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
> $PSVersionTable
$PSVersionTable
Name Value
---- -----
PSVersion 6.0.2
PSEdition Core
GitCommitId v6.0.2
OS Darwin 17.6.0 Darwin Kernel Version 17.6.0: Fri Apr 13 19:57:44 PDT 2018; root:xnu-4570.60.17.0.1~3/RELEASE_X86_64
Platform Unix
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
WSManStackVersion 3.0
Hi @jasonchester When you use the -Width parameter on Out-String you're overriding the screen width used when _formatting objects_. For example, dir *.md | Out-String -Width 20 will give you output that looks like:
PS > ls *.md | out-string -width 20
Directory: D:\gi
t\PowerShell_bru
cepay
Mode LastWriteTim
e
---- ------------
-a---- 5/20/18
11:30 AM
-a---- 5/20/18
11:30 AM
-a---- 5/20/18
11:30 AM
But that only applies to objects that are being formatted. Strings are treated as "already formatted" so they just pass through to the output unchanged. This is why your example, which uses a string, doesn't appear to work.
Oh - and if you want to create a long string, multiplication works on strings:
PS > "x" * 100
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
This is not clear from the current documentation. We should update the documentation to make this distinction more clear.
@brucepay, Thanks for the quick answer, the explanation about out string applying to un-formatted inputs but not strings was exactly what I was missing.
More importantly, thanks for the string multiplication tip. I鈥檒l use that for sure.
Do you have any posh-fu for truncating strings to a specified length? I am planning to use Write-ProgressEx to display the progress of a script executing batches of gremlin queries. I am setting the status of the loop to the gremlin query but it is longer than my display is wide so it ends up wrapping which makes it much harder to scan as it scrolls by.
Of course there is "...".Substring(0,$width) but, it just doesn't feel very posh in my pipeline which is gets even more cluttered when combined with the (get-host).stuff.ui.junk.width needed to handle console resizing gracefully
@jasonchester you need this: https://github.com/PowerShell/PowerShell/pull/6753
@jasonchester Yes - this proposal #6753 _Add string cmdlets that emulate operator functionality on pipeline_ should be what you want. If you can, please take a few minutes to read the proposal and provide feedback on scenarios, etc. Thanks!
For now, to truncate strings in the pipeline, you could use foreach with the substring() method as follows:
PS > "foobar", "foobaz", "foobuz" | foreach substring 0 3
foo
foo
foo
Unfortunately Substring() throws if the string isn't long enough. An alternate approach would be a function like this:
function TruncateStr ($len) { process { -join (([string]$_)[0..$len]) }}
This little function will take strings from the pipeline and truncate them to the desired length. If the string isn't long enough, there's no error - the string is just passed through.
@BrucePay: Small correction: [0..$len] -> [0..($len-1)].
Tangent alert:
Out of curiosity I compared the performance of various approaches and made the following surprising discoveries:
Even letting .Substring() fail and handling the exception with try / catch makes for faster execution than placing conditionals around it (and the latter are in turn faster than the -join (([string]$_)[0..($len-1)]) approach).
Unexpectedly, in Windows PowerShell and PS Core v6.0.2 the following arcane regex solution is fastest: $_ -replace "(?<=.{$len}).+"
In PS Core v6.1.0-preview2 - the current preview - the regex solution is more than _twice as slow as before_ (and then slowest overall) - any ideas why? A change in PowerShell or in CoreFx? See #6976.
Test code (uses script Time-Command):
$len = 3 # how many chars. to return
$count = 1000 # how many runs to average
'foooooooooooooooo' | Time-Command -Count $count `
{ $_.Substring(0, [Math]::Min($len, $_.Length)) },
{ try { $_.Substring(0, $len) } catch { $_ } },
{ if ($_.Length -lt $len) { $_ } else { $_.Substring(0, $len) }},
{ -join (([string]$_)[0..($len-1)]) },
{ $_ -replace "(?<=.{$len}).+" }
Here are example results from a W10 VM (note that Core is slower in general, and note how the regex solution went from fastest to slowest between v6.0.2 and v6.1.0-preview.2):
# Windows PowerShell v5.1 on W10
Command TimeSpan
------- --------
$_ -replace "(?<=.{$len}).+" 00:00:00.0000226
try { $_.Substring(0, $len) } catch { $_ } 00:00:00.0000256
$_.Substring(0, [Math]::Min($len, $_.Length)) 00:00:00.0000283
if ($_.Length -lt $len) { $_ } else { $_.Substring(0, $len) } 00:00:00.0000294
-join (([string]$_)[0..($len-1)]) 00:00:00.0000346
# PS Core v6.0.2 on W10
Command TimeSpan
------- --------
$_ -replace "(?<=.{$len}).+" 00:00:00.0000327
try { $_.Substring(0, $len) } catch { $_ } 00:00:00.0000424
$_.Substring(0, [Math]::Min($len, $_.Length)) 00:00:00.0000479
if ($_.Length -lt $len) { $_ } else { $_.Substring(0, $len) } 00:00:00.0000511
-join (([string]$_)[0..($len-1)]) 00:00:00.0000591
# PS Core v6.1.0-preview.2 on W10
Command TimeSpan
------- --------
try { $_.Substring(0, $len) } catch { $_ } 00:00:00.0000429
$_.Substring(0, [Math]::Min($len, $_.Length)) 00:00:00.0000473
if ($_.Length -lt $len) { $_ } else { $_.Substring(0, $len) } 00:00:00.0000486
-join (([string]$_)[0..($len-1)]) 00:00:00.0000595
$_ -replace "(?<=.{$len}).+" 00:00:00.0000959
Docs fixed in PR https://github.com/PowerShell/PowerShell-Docs/pull/2759
Most helpful comment
@BrucePay: Small correction:
[0..$len]->[0..($len-1)].Tangent alert:
Out of curiosity I compared the performance of various approaches and made the following surprising discoveries:
Even letting
.Substring()fail and handling the exception withtry/catchmakes for faster execution than placing conditionals around it (and the latter are in turn faster than the-join (([string]$_)[0..($len-1)])approach).Unexpectedly, in Windows PowerShell and PS Core v6.0.2 the following arcane regex solution is fastest:
$_ -replace "(?<=.{$len}).+"In PS Core v6.1.0-preview2 - the current preview - the regex solution is more than _twice as slow as before_ (and then slowest overall) - any ideas why? A change in PowerShell or in CoreFx? See #6976.
Test code (uses script
Time-Command):Here are example results from a W10 VM (note that Core is slower in general, and note how the regex solution went from fastest to slowest between v6.0.2 and v6.1.0-preview.2):