Skip to content

Is it worth adding an additional line continuation mechanism? #2819

Closed

Description

@rkeithhill

Line continuation in PowerShell suffers from at least two problems:

  1. The backtick char is hard to see in PowerShell script:
Get-Module pester ` 
| Foreach { Get-ChildItem $_.ModuleBase -recurse about_*.txt} `  
| Foreach {$_.BaseName -replace '\.help',''} | Select-Object -Unique | Sort-Object

Escaping a char like _ makes the line continuation more obvious:

Get-Module pester `_ 
| Foreach { Get-ChildItem $_.ModuleBase -recurse about_*.txt} `_  
| Foreach {$_.BaseName -replace '\.help',''} | Select-Object -Unique | Sort-Object
  1. The current line continuation mechanism is an escape of a newline (invisible) character. As a result, line continuation is broken if the user has any sort of whitespace (space or tabs) after the backtick since <backtick><space>|<tab> does not signify line continuation.

The second issue is impossible to see via casual inspection of script and is common when you copy/paste script from a website. By using an escaped char like <backtick>_ there is no longer any issue with whitespace after this line continuation char. That whitespace can safely be ignored by the parser. For an example of this problem, copy the first script sample above and paste into a PowerShell console. It will fail to run because there are spaces after the backticks. :-)

FWIW I'm not sure escaping _ is the best choice but I do think escaping a "visible" character has the benefit of being more obvious. I would love to ditch the escaping and just use a dedicated continuation character like _ (which VB uses) but that is tough with PowerShell where I can have a function named _.

Another option might be to use a double escape:

Get-Module pester `` 
| Foreach { Get-ChildItem $_.ModuleBase -recurse about_*.txt} ``  
| Foreach {$_.BaseName -replace '\.help',''} | Select-Object -Unique | Sort-Object

I believe such a change would not interfere with the existing line continuation mechanism so existing scripts would continue to work.

Migrated from #2751

Activity

  1. MaximoTrinidad commented on Dec 1, 2016

    @MaximoTrinidad

    Why? I like the used of the backtick. I've been doing this for a long time and I like it. So, why change something that works?

    By the way, a script with code having backtick copy/paste to a console work. I use it all the time.

    :)

  2. rkeithhill commented on Dec 1, 2016

    @rkeithhill
    CollaboratorAuthor

    If you read the proposal all the way through, it mentions that this would not change the existing mechanism. You can't because that would break too many scripts.

    This issue is meant to discuss if it is worth adding another mechanism for line continuation. I know, right? Having more than one way to do something in PowerShell is SHOCKING I tell you. Completely unheard of. ;-)

  3. KirkMunro commented on Dec 1, 2016

    @KirkMunro
    Contributor

    How about adding ... as an optional continuation token? 🤔

    Sure, there could be a function with that name, but it would kinda make sense...
    (pun intended)

  4. KevinMarquette commented on Dec 1, 2016

    @KevinMarquette
    Contributor

    The general best practice is to not use the backtick for line continuation. Some times you can just restructure your command like this:

    Get-Module pester | 
        Foreach-Object { Get-ChildItem $_.ModuleBase -recurse about_*.txt} | 
        Foreach-Object {$_.BaseName -replace '\.help',''} | 
        Select-Object -Unique | 
        Sort-Object
    

    This is also where Here-Strings and Splatting come in handy. I tend to teach people these alternate approaches instead of introducing the backtick.

  5. rkeithhill commented on Dec 1, 2016

    @rkeithhill
    CollaboratorAuthor

    Kevin Marquette (@KevinMarquette) Keep in mind that neither breaking on | or using splatting is an option when invoking a native executable with a lot of lengthy parameters. That said, when I can avoid backtick I too try to avoid it.

  6. KevinMarquette commented on Dec 1, 2016

    @KevinMarquette
    Contributor

    There are options for that too.

    $MSIArguments = @(
        "/i"
        ('"{0}"' -f $file.fullname)
        "/qn"
        "/norestart"
        "/L*v"
        $logFile
    )               
    Start-Process "msiexec.exe" -ArgumentList $MSIArguments
    
  7. KevinMarquette commented on Dec 1, 2016

    @KevinMarquette
    Contributor

    I should clarify that I am not opposed to having a much better way to express line continuation.

  8. added
    WG-Languageparser, language semantics
    Issue-Discussionthe issue may not have a clear classification yet. The issue may generate an RFC or may be reclassif
    on Dec 1, 2016
  9. stej commented on Dec 1, 2016

    @stej

    I personally don't feel it's necessary to add a new language construct. Instead of that first what came on my mind was better text editors support.

    A lot of tokens is highlighted in editors, so why not backtick (with Cyan, Salmon, or any other nice color)? And the rest of the line behind the backtick might be in other color with meaning "warning, this might be wrong".

  10. djgrijalva commented on Dec 1, 2016

    @djgrijalva

    Backticks are the devil. We all have widescreen monitors nowadays and know how to use the horizontal scroll bar :). Joking aside, I have found long running lines could be broken into separate lines entirely and often run faster since they are avoiding the pipeline. Multiple pipes just equal slow and lazy IMO.

  11. rkeithhill commented on Dec 1, 2016

    @rkeithhill
    CollaboratorAuthor

    Eska látor! (@stej) there is help for this in Visual Studio Code. I put this setting in my user settings file:

     "files.trimTrailingWhitespace": true,

    And PSScriptAnalyzer has a rule PSMisleadingBacktick that will catch these. But not everyone uses VSCode or PSScriptAnalyzer.

  12. MaximoTrinidad commented on Dec 1, 2016

    @MaximoTrinidad

    Nice one Keith Hill (@rkeithhill)!

    I'm using VS Code for lightweight coding and I like it. Thanks for sharing the "files.trimTrailingWhitespace": true setting.

    :)

  13. Jaykul commented on Dec 1, 2016

    @Jaykul
    Contributor

    You most certainly can splat to native commands.
    The catch is that native switch commands don't accept "true" values ;-)

    E.g.

    tf vc status /format:detailed

    Could just as easily be:

    $fmt = @{"format"="detailed"}
    $cmd = "vc","status"
    tf @cmd @fmt
    

    I don't like line continuation characters. I wish we didn't have the one we have (Yay C# -- Boo VB).

    One problem with line continuation characters is that the only reason for them to exist is to enable people to stay within some arbitrary line width. Next thing you know you've got people trying to make a 249 character file path somehow fit on 80 character lines by splitting it into many strings and appending them together -- as if that actually improved readability.

  14. DWSR commented on Dec 1, 2016

    @DWSR

    The reason that I like staying within some "arbitrary line width" is because a lot of devs run portrait monitors. Having a 100 or 120 character limit means that my code fits in the width of the window.

    I would love to have a switch to enable a line terminator as opposed to implementing yet another continuation character.

  15. LarryWeiss commented on Dec 1, 2016

    @LarryWeiss

    Is there any language that has the concept of "line continuation" that has done it in a way that is better?

    PowerShell's "line continuation" at first implied to me that the line was simply spliced together with the next one (as if the line ending was ignored). But that's not turned out to be the way it works. Try
    'Power`
    Shell'

  16. JamesWTruher commented on Dec 1, 2016

    @JamesWTruher
    Collaborator

    It's pretty hard to create a good shell that doesn't have some way to split command lines because they can get pretty long. I chose backtick because it was similar to \ (and I couldn't choose \ for obvious reasons). Comparing PS to C# is a bit disingenuous they target different usage patterns - C# has a single statement end operator - requiring ; at the end of every command would be a pretty rotten interactive shell experience.
    Bruce and I did think a lot about this in the early days, and tried to be faithful to Unix shell traditions and concepts, even if we weren't always faithful to their implementation, given all the platform considerations.

  17. rkeithhill commented on Dec 1, 2016

    @rkeithhill
    CollaboratorAuthor

    LarryWeiss

    Is there any language that has the concept of "line continuation" that has done it in a way that is better?

    On the visibility front yes. Bash and Python use \ for line continuation. But neither tolerates whitespace after \. VB, which uses _, does tolerate whitespace after _.

  18. JamesWTruher commented on Dec 1, 2016

    @JamesWTruher
    Collaborator

    some of those characters still have trouble in a windows environment where you're executing a command. _ is an allowed character for a filename - would I need to escape _ in this context?
    get-content _

  19. rkeithhill commented on Dec 1, 2016

    @rkeithhill
    CollaboratorAuthor

    Agreed. That's where an escaped character would be better.

  20. spaghettidba commented on Dec 4, 2016

    @spaghettidba

    FWIW, a number of international keyboards don't even have the backtick key. In the Italian keyboard it's ALT+TN96 or nothing. FWIW again, many laptops don't have TN at all, so there is NO way to type a backtick

  21. iSazonov commented on Dec 6, 2016

    @iSazonov
    Collaborator

    What about ## ?

  22. mklement0 commented on May 14, 2017

    @mklement0
    Contributor

    `` is promising - the only existing code it would break is commands (argument-mode statements) that:

    • print a single `, individually escaped,
    • as the last argument

    E.g., Write-Host You should not end a sentence with a `` . Existing code doing that strikes me as not too likely.

    Gianluca Sartori (@spaghettidba) brings up a good point, but it is outweighed by the long tradition of ignoring other languages and keyboard layouts in computing :) (e.g., \, @)

    Ilya (@iSazonov): It's quite likely that ## is used in existing code for comments, and even if you limited recognition to ##<newline> sequences, the potential for confusion with a comment is great.

    [Tangent alert]

    LarryWeiss: Re line continuation in other languages (to add to Keith Hill (@rkeithhill)'s comment):

    Good point; to elaborate on the fundamental difference between POSIX-compatible shells such as Bash and PowerShell with respect to line continuation:

    • In Bash, \<newline> is removed from the lines of a command / inside a double-quoted string; this allows splitting command lines at arbitrary points and composing single-line strings spread across several lines inside double quotes.

    • In PowerShell, `<newline> preserves the newline; this requires splitting to occur between arguments and makes use inside a (double-quoted) string pointless, because a <newline> by itself will do; to get line continuation with a string in a POSIX sense, you must use the workaround of an array of substrings with unary -join.

    Note that in both environments there is no line continuation in single-quoted strings, where all content is treated literally (with the exception of '' in PS) - so, strictly speaking, your example doesn't apply (inside '...', both the ` and the <newline> are retained, and, as with double-quoted strings, just <newline> will do).

  23. rkeithhill commented on Jun 6, 2019

    @rkeithhill
    CollaboratorAuthor

    Two years later, I think I'm going to close this. The current situation is "somewhat" sub-optimal but I'm thinking the line-terminator sequence is not worth changing at this point.

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

    Issue-Discussionthe issue may not have a clear classification yet. The issue may generate an RFC or may be reclassifResolution-AnsweredThe question is answered.WG-Languageparser, language semantics

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions