Skip to content

PSCore: Linux - Clear-Host injects data into function return value #10181

Closed

Description

Steps to reproduce

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

Expected behavior

Function should return a single value ("somedata")

Actual behavior

Function returns an array with the Clear-Host command as the first object

Environment data

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

Activity

  1. added
    Issue-Questionideally support can be provided via other mechanisms, but sometimes folks do open an issue to get a
    on Jul 19, 2019
  2. tobyscales commented on Jul 19, 2019

    @tobyscales
    Author

    (BTW this works as expected in PSCore - Windows)

  3. HumanEquivalentUnit commented on Jul 28, 2019

    @HumanEquivalentUnit
    Contributor

    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.

    #8554 and #8603 and #8606 and #8609 are related issues, and it looks like there's some debate about whether it's PowerShell or .Net's responsibility, what the default bahviour should be, and how it should interact with "clearing" remote sessions or newly implemented hosts.

    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
    
  4. tobyscales commented on Jul 31, 2019

    @tobyscales
    Author

    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.

  5. tobyscales commented on Jul 31, 2019

    @tobyscales
    Author

    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.

  6. HumanEquivalentUnit commented on Aug 1, 2019

    @HumanEquivalentUnit
    Contributor

    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 🤔

  7. iSazonov commented on Oct 2, 2019

    @iSazonov
    Collaborator

    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 Michael Klement (@mklement0)

  8. added
    Issue-BugIssue has been identified as a bug in the product
    and removed
    Issue-Questionideally support can be provided via other mechanisms, but sometimes folks do open an issue to get a
    on Oct 2, 2019
  9. mklement0 commented on Oct 2, 2019

    @mklement0
    Contributor

    I agree, Ilya (@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).

  10. iSazonov commented on Oct 2, 2019

    @iSazonov
    Collaborator

    Michael Klement (@mklement0) Many thanks! I pulled PR with your suggestion.

  11. mklement0 commented on Oct 2, 2019

    @mklement0
    Contributor

    Thanks for the quick turnaround, Ilya (@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 Bruce Payette (@BrucePay) from one of the linked issues, at #8603 (comment):

    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 new RawUI.Clear() API and then implement that using Console.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.
    
  12. iSazonov commented on Oct 2, 2019

    @iSazonov
    Collaborator

    Michael Klement (@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).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions