Function Get-SomeData {
Clear-Host
$somedata="somedata"
return $somedata
}
$myData = Get-SomeData
$myData[0] # will clear the screen
$myData[1] # "somedata"
$myData.Count # will be 2
Function should return a single value ("somedata")
Function returns an array with the Clear-Host command as the first object
Verified in:
|Name|Value|
|---|---|
|PSVersion|6.2.0|
|PSEdition|Core|
|GitCommitId|6.2.0|
|OS|Linux 4.15.0-47-generic #50-Ubuntu SMP Wed Mar 13 10:44:52 UTC 2019|
|Platform|Unix|
|PSCompatibleVersions|1.0 2.0 3.0 4.0 5.0 5.1.10032.0 6.2.0|
|PSRemotingProtocolVersion|2.3|
|SerializationVersion|1.1.0.1|
|WSManStackVersion|3.0|
(BTW this works as expected in PSCore - Windows)
Clear-Host
on Linux calls the native command /usr/bin/clear
,
// Porting note: non-Windows platforms use `clear`
return @"
& (Get-Command -CommandType Application clear | Select-Object -First 1).Definition
which works by outputting a string with ANSI escape codes:
<esc>[3;J<esc>[H<esc>[2J
They are: clear screen including scrollback, move cursor to top left corner, clear screen. Source.
As a Linux-specific workaround, you could write that string (or the output of clear
) to the host yourself:
Function Get-SomeData {
$Host.UI.Write("`e[3;J`e[H`e[2J")
$somedata="somedata"
return $somedata
}
$myData = Get-SomeData
Sure, I could also (as I've done) fork the logic:
if ($isLinux) { etc }
... but that kind of obviates the point of a cross-platform language, doesn't it? :)
I think what's more concerning to me is why Clear-Host is messing with my variable stack. Whatever the subtle differences (clear screen, clear buffer+screen, etc) it definitely shouldn't be _returning a value_.
But that seems to be what's happening here.
Actually the more elegant fix, in case anyone runs across this, is simply:
$null = Clear-Host
Which will clear the call stack so everything behaves as expected. But it's still code behaving badly.
When I try that fix on Ubuntu 16, the screen is not cleared?
why Clear-Host is messing with my variable stack. Whatever the subtle differences (clear screen, clear buffer+screen, etc) it definitely shouldn't be returning a value.
All command output or free values anywhere in a PowerShell function become part of the return value of the function (that decision was taken to copy sh/bash/ksh/etc. behaviour). Clear-Host
particularly returns a value because it wraps /user/bin/clear
a native command which works by returning a value.
clear
doesn't clear the screen directly, it prints a string expecting the display terminal to clear itself. If you do something to block that, the screen doesn't clear and you get the string instead. The same thing happens in Bash; at a shell prompt:
clear # screen is cleared
clear 1>/tmp/test # screen is not cleared, reset string written to file
result=`clear` #screen is not cleared, output -> variable
echo $result # screen is cleared.
function test { clear; echo "123"; }
test # screen is cleared and 123 is output
result=`test` # screen is not cleared, no visible output
echo $result | wc -c # result variable has 16 characters, not 3
16
echo $result # screen is cleared, 123 is output
that kind of obviates the point of a cross-platform language, doesn't it? :)
It seems to behaves like the platform it's running on. Whether that's badly or not, depends on what behaviour you want 馃
I think it should be a bug because script behavior varies between platforms.
Clear
command issues escapes and PowerShell intercepts this. Perhaps we could re-send by raw interface API.
/cc @mklement0
I agree, @iSazonov.
@HumanEquivalentUnit: True, but since PowerShell, unlike Bash, is able to distinguish between to-terminal output and success-stream output, the fix is to write directly to the terminal:
${function:Clear-Host}
prints the function definition, and on Unix-like platforms you get:
& (Get-Command -CommandType Application clear | Select-Object -First 1).Definition
The above writes implicitly to the success output stream, so wrapping it in [Console]::Write()
fixes the problem:
function Clear-Host {
[Console]::Write((
& (Get-Command -CommandType Application clear | Select-Object -First 1).Definition
))
}
$host.UI.Write()
would work too and is arguably conceptually better, but since /usr/bin/clear
is being called, the code is terminal (console)-specific anyway.
Test:
& { Clear-Host; 'hi' } | Should -Be 'hi'
(Note: In PowerShell Core 7.0.0-preview.4 I get a spurious Suggestion [4,General]: The most similar commands are: New-Object, Tee-Object.
message the first time Should
is run in the session, but this is unrelated and can be ignored).
@mklement0 Many thanks! I pulled PR with your suggestion.
Thanks for the quick turnaround, @iSazonov.
Taking a step back: By _unconditionally_ delegating to /usr/bin/clear
on Unix-like platforms, we've actually already made Clear-Host
_terminal_-specific, which means that it may malfunction / not do anything meaningful in other types of hosts.
To quote @BrucePay from one of the linked issues, at https://github.com/PowerShell/PowerShell/pull/8603#discussion_r246132597:
This isn't going to work for non-console hosts [...] and remoting. On those platforms, you still need to use the
$RawUI
portability APIs. A nice solution would be to actually add a newRawUI.Clear()
API and then implement that usingConsole.Clear()
in the console host but that may end up being a bunch of work...
Case in point: If you currently execute Clear-Host
in a remoting session connected to a Unix machine, it prints the following message to stderr (and does nothing else).
TERM environment variable not set.
@mklement0 I see we have some issues with Clear-Host. but I still don't have the ability to test on Unix-s and can not grab this. (Although we could do RawUI.Clear()
step by step).
:tada:This issue was addressed in #10681, which has now been successfully released as v7.0.0-preview.5
.:tada:
Handy links:
Most helpful comment
@mklement0 Many thanks! I pulled PR with your suggestion.