Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use forward slashes by default in Windows #10509

Closed
chriskuech opened this issue Sep 10, 2019 · 96 comments
Closed

Use forward slashes by default in Windows #10509

chriskuech opened this issue Sep 10, 2019 · 96 comments
Labels
Issue-Enhancement the issue is more of a feature request than a bug Resolution-By Design The reported behavior is by design.

Comments

@chriskuech
Copy link

Summary of the new feature/enhancement

PowerShell aims to be cross-platform, but I have been having many issues operating on paths across both Windows and Linux. I understand the need to support \ in Windows for the foreseeable future, but I would at least like the default path character to be the same on both Windows and *nix, presumably by setting the default path delimiter to /. The current alternative is forcing users to normalize paths themselves with -replace "\\", "/" in their paths.

@chriskuech chriskuech added the Issue-Enhancement the issue is more of a feature request than a bug label Sep 10, 2019
@iSazonov
Copy link
Collaborator

The current alternative is forcing users to normalize paths

PowerShell already does the work for you and you have no need to normalize paths.
PowerShell is very user-friendly here - users can use slashes which they are comfortable regardless of platform.
Best practice is to avoid using literal paths and use path cmdlets.

@iSazonov iSazonov added the Resolution-Answered The question is answered. label Sep 11, 2019
@KirkMunro
Copy link
Contributor

KirkMunro commented Sep 11, 2019

Best practice is to avoid using literal paths and use path cmdlets.

@iSazonov Yes and no.

Sure, if you are combining path segments, you can use path cmdlets. But if you are writing a script that references a relative path with multiple segments, and if you intend for your script to work cross platform, you're not going to do that.

In PowerShell 7 preview 3 on Windows, tab completion completes paths using a backslash. That is the one place where I think we're doing it wrong now that PowerShell is cross platform. There should at least be an option to select the directory separator character you want used on Windows as part of tab completion: either [System.IO.Path]::DirectorySeparatorChar or [System.IO.Path]::AltDirectorySeparatorChar. Given where we are today, I suspect most folks who do any cross platform work would want tab completion of paths to use AltDirectorySeparatorChar on Windows by default, but as far as I know there is no way to make it do that.

@chriskuech: Aside from tab completion of paths, are there other places where you feel AltDirectorySeparatorChar isn't being used where you would like to have an option for it to be used instead of DirectorySeparatorChar? I can't think of any.

@chriskuech
Copy link
Author

chriskuech commented Sep 11, 2019

@KirkMunro , are you saying that there is an (at least partially implemented) way to normalize paths in PowerShell today? If so, will it work on latest 6.x? The use cases I was having an issue with were automatic variables and *-Path commands.

@iSazonov, the proposed solution would not have worked for my scenario because I generated a list of paths on Windows, generated a list of paths on Linux, then attempted to compare them, which failed due to the separators.

The automatic variables consistently lack a trailing directory separator, so PowerShell beautifully allows creating paths with literals. Ex:

$RepoRoot = "$PSScriptRoot/../.."
$SourceRoot = "$RepoRoot/src"
$BuildRoot = "$RepoRoot/.build"

I think this is much more clear than

$RepoRoot = Join-Path $PSScriptRoot "../.."
$SourceRoot = Join-Path $RepoRoot "src"
$BuildRoot = Join-Path $RepoRoot ".build"

so I hope it can work in the future, even if not by default.

@vexx32
Copy link
Collaborator

vexx32 commented Sep 11, 2019

@chriskuech my personal habit has become something like:

$SourceRoot = $RepoRoot | Join-Path -ChildPath 'src'

It's a little clearer but yeah it's not perfect.

@iSazonov
Copy link
Collaborator

Join-Path has AdditionalChildPath which accept string array.

@KirkMunro
Copy link
Contributor

@chriskuech Thanks for the additional information.

I wasn't suggesting that PowerShell partially supports normalization of paths. I was simply calling out that I personally dislike that tab completion uses a backward slash by default on Windows, and a forward slash by default on Linux or macOS.

If I could tweak some setting to change that so that forward slash is used even on Windows paths by default, I would make that change, and this is one place where I think there may be an opportunity to make cross platform PowerShell work easier. Join-Path uses [System.IO.Path]::DirectorySeparatorChar as the path separator as well. Ideally if there were a setting to set the desired path separator when writing scripts (because we should be able to easily write scripts the way we want regardless of the platform we choose to write them on), it would be reflected in both tab completion of paths and Join-Path as well.

Those personal needs aside, I wonder if a Compare-Path cmdlet would be useful. It could normalize the path separators, and even compare absolute paths with relative paths by resolving relative paths before the comparison is made if one of the paths is absolute.

@mklement0
Copy link
Contributor

Well, we do get platform-specific normalization in Convert-Path and Resolve-Path:

PS> Convert-Path C:/Windows
C:\Windows # normalized to Windows-native "\"

So, perhaps as an alternative to introducing a Compare-Path cmdlet, Convert-Path and Resolve-Path could be extended to support a -UseSlash switch (name negotiable).

Separately and complementarily, the opt-in preference mechanism for using / on Windows that Kirk suggests could then also apply to Convert-Path and Resolve-Path (in addition to tab completion and Join-Path).

The catch at the moment is that Convert-Path and Resolve-Path only work with existing paths, but that is something well worth changing in its own right, as @Jaykul suggested a looong time ago - see #2993

@lzybkr
Copy link
Member

lzybkr commented Sep 12, 2019

I think it would be nice if path completion used the path separator that appears explicitly in the completion text, and if there is none, then default to the platform native separator.

So on Windows, c:\w completes to c:\Windows\ and c:/w completes to 'c:/Windows/'.

I think this would cover a majority of the annoyances without requiring a configuration option, and is actually preferable because you occasionally might need the other form for whatever reason.

@mklement0
Copy link
Contributor

@lzybkr, I like the idea, also in light of a concern regarding a configuration- / preference-variable-based solution that I neglected to mention: the scoping issue; with the usual dynamic scoping, code that makes fixed assumptions about path separators may break (which has echoes of PowerShell/PowerShell-RFC#7).

@vexx32
Copy link
Collaborator

vexx32 commented Sep 12, 2019

@lzybkr and when both slashes are used? C:\Program Files/A -> ?

@lzybkr
Copy link
Member

lzybkr commented Sep 12, 2019

So many options - random, alternate each one, always forward slash b/c it's the one true path separator, etc.

More seriously, maybe just pick the last one used, that is probably typed by the user whereas others might not be.

@mklement0

This comment has been minimized.

@ghost
Copy link

ghost commented Sep 14, 2019

This issue has been marked as answered and has not had any activity for 1 day. It has been closed for housekeeping purposes.

@ghost ghost closed this as completed Sep 14, 2019
@KirkMunro
Copy link
Contributor

@iSazonov: This isn't really answered, and should be reopened to allow the ongoing discussion to continue working this out. The OP hasn't even had a chance to respond to questions asked back to him.

@chriskuech
Copy link
Author

I think I addressed all the questions to me, but let me know if I didn't. I too am not sure why this issue is closed. It wasn't meant as a discussion thread, rather a feature request.

The root issue at hand:

  • Should a cross-platform tool have non-cross-platform behavior by default?
  • If so, should there be a way to globally run PowerShell in a "cross-platform" mode?

I think forcing devs to manually normalize strings with cmdlets is a definite wrong move. I don't see any scenarios where using / by default would cause issues on Windows because PowerShell, as previously mentioned, is very good about handling both kinds of slashes. Unless anyone can provide compelling situations where this would cause error, why not just use / by default? Perhaps this issue needs to move to an RFC.

As more people migrate to the cloud, more and more people develop PowerShell code on Windows and run it on Linux. There will certainly be a point in the future (if not already passed) where the number of users preferring true cross-platform behavior exceeds any who feel strongly about keeping \ on Windows.

@KirkMunro
Copy link
Contributor

@chriskuech: My bad, I didn't specifically pose the question to you. I was wondering if you felt a Conpare-Path cmdlet would help you out. That question aside though, I would like to see normalization options as well.

@chriskuech
Copy link
Author

@KirkMunro I'm not sure Compare-Path would help, because in the original use case (comparing paths on Linux and Windows), the root file system is different, so I have to call Resolve-Path -Relative. At that point the comparison use case is just a one-liner: | ? {($_ -replace "\\", "/") -in $ExpectedPaths}.

However, I am very hesitant to endorse any cmdlet-based solution, as it doesn't solve the root issue and will either disallow string interpolation for paths or require code changes to every path string definition. Specifically, Compare-Path won't fix all my logged paths with mixed slashes.

@iSazonov
Copy link
Collaborator

@KirkMunro @mklement0 The issue is not locked and everyone can pull comments.
We have a lot of issues without new comments and progress. Open status has lost its meaning.
As a maintainer, I intend to be more exacting in order to encourage discussions to become more rigorous specifications that can easily turn into PRs.
As for the issue, it turns into infinite - initial request was "use forward slash on Windows", then "compare paths". What is next? Remoting? It is open to continue but will be closed.
While only one real proposal from Jason was above (to enhance completion) and we could open a tracking issue and close it by real PR.

@chriskuech
Copy link
Author

To be clear, the issue is still "use forward slash on Windows". "Compare paths" was only brought up as one (of multiple) motivating examples.

Proposal
Implement true cross-platform behavior, where the path delimiter defaults to / on all platforms unless the user is tab-completing a path already containing \. I would expect this to be hidden as an experimental feature for now, but I should at least be able to enable a "maximize cross-platform behavior" feature in my code for optimizing the dev experience of Windows devs targeting Linux.

If this is unreasonable, I would like to know why and if there is documentation guiding when PowerShell design diverges across platforms.

@KirkMunro
Copy link
Contributor

@iSazonov: Maintainers of the PS repo shouldn't be dismissive to users issues without discussion. You originally replied without taking the time to understand the needs of the OP, marking the issue as answered, but the issue was not posted as a question, it was posted as a feature request, and as can be seen by the discussion it is clearly not "answered".

@KirkMunro
Copy link
Contributor

KirkMunro commented Sep 16, 2019

Open status has lost its meaning.

Who says? That's absolutely not true. An open issue is open, and a closed issue is closed. Those two distinctions have very clear meaning. I only look at closed issues if they are my own and I want to go back to check something. On a rare occasion I may go searching closed issues for discussions on a certain topic. But 90% or more of my time in issues is in open issues, as it should be. The only thing blurring the line between the two and making open issues lose their meaning is summarily closing them before they are resolved, like you have done with this issue.

(The discussion) is open to continue but will be closed.

Based on this approach to managing issues, you're forcing people to lose the distinction between open and closed, such that they have to search all issues rather than focus on the open issues, which means checking the 2K open issues plus the 4K closed issues for discussions relevant to them instead of just focusing on the open issues. That is a broken, flawed issue management strategy.

As for the issue, it turns into infinite - initial request was "use forward slash on Windows", then "compare paths". What is next? Remoting?

That is ridiculous. The discussion is focused on dealing with Windows having a backslash as the default when you are writing scripts for cross platform. It has remained focused on that topic. You're trying to make it sound like it isn't focused at all.

@iSazonov, I agree that there are too many open issues; however, the fact that there are too many open issues does not mean we should be dismissive and shut conversation down prematurely on new issues. We must continue to encourage feedback and be open to discussion about PowerShell in open issues, and only close them once they are truly resolved. The volume of open issues must be dealt with differently.

@iSazonov iSazonov removed the Resolution-Answered The question is answered. label Sep 16, 2019
@iSazonov iSazonov reopened this Sep 16, 2019
@he852100
Copy link

Loyal linux users?Incomprehensible advice.
You can convince Microsoft. Ask them to use backslashes as system file paths.

@chriskuech chriskuech changed the title Use forward slashes by default in Windows Use back slashes by default in Windows Dec 24, 2019
@yecril71pl
Copy link
Contributor

(If changing the .NET properties were an option, I'd choose [io.path]::PathVariableSeparator and [io.path]::PathSeparator)

[io.path]::SearchPathSeparator would be OK with me.

@mklement0
Copy link
Contributor

We could always have Get-PSPathSeparator for that purpose

The problem is that this is both syntactically awkward ('a', 'b' -join (Get-PSPathSeparator)) and inefficient (cmdlet call).

Conceptually, the path separator is a constant (an automatic variable in PowerShell terms), and with the proposed configurability we're turning it into preference variable. Either way, a variable is the expected - and efficient - form.

@yecril71pl
Copy link
Contributor

Conceptually, the path separator is a constant (an automatic variable in PowerShell terms), and with the proposed configurability we're turning it into preference variable. Either way, a variable is the expected - and efficient - form.

A variable that you cannot change to is not a variable. It is an observable, equivalent to a parameterless function. I have no data regarding the (in)efficiency of a cmdlet call in PowerShell but if it is a problem for built-in cmdlets, it is a problem that should be solved.

@mklement0
Copy link
Contributor

mklement0 commented Dec 15, 2020

Even what is conceptually a constant in PowerShell is surfaced as a variable, such as $true and $false, for instance (and here we will have a bona fide variable) - and it makes the most sense to surface the path separator as that - just like, by analogy, [IO.Path]::DirectorySeparatorChar is a property, not a method.

@mklement0
Copy link
Contributor

mklement0 commented Dec 15, 2020

What would offer a solution is if we had a calculated automatic read-only variable, analogous to a ScriptProperty ETS member, which we could combine with Boolean preference variable $PSUseSlash (name negotiable, as discussed).

In fact, we already have such automatic variables, e.g., $PWD, so I guess we could make that happen for an all-scopes automatic $PSPathSeparator variable too, whose logic would be:

  • On Windows, if a $PSUseSlash preference variable is visible in the current scope and is set to $true, return /
  • Otherwise, return the platform-native separator.

That is, $PSPathSeparator would become an independent read-only variable that reflects the effective path separator with respect to tab-completion, Convert-Path, Join-Path, Split-Path. Even in the absence of $PSUseSlash it would be useful for referring to the platform-native separator.

$PSUseSlash would then not be predefined at all, and could easily be created with $private:PSUseSlash = $true to avoid affecting child scopes, as needed.

@KirkMunro
Copy link
Contributor

@mklement0 $PSPathSeparator seems unnecessary long. We already have $OFS in PowerShell to identify the output field separator. I think it would be better to use a terse variable name for ease of use in scripts.

Do we really need two variables for this? I've read the reasoning you have provided, but pairing up variables for this single purpose seems unnecessary to me. My preference would be to have $OPS (output path separator, named appropriately to match the output field separator variable), and define it such that assigning any value other than \ or / results in it being reset to the default value for that OS. You can still use the private: scope qualifier to assign a value that is only in a specific scope, and you can use the variable easily in scripts (e.g. -join $OPS).

I haven't put a ton of thought into this, but up front I feel going with a terse name and avoiding having to work with multiple variables is better for scripters in this case.

@mklement0
Copy link
Contributor

mklement0 commented Dec 23, 2020

@KirkMunro, I'd be fine with $OPS, but note that you still need two variables, namely if you want $OPS to always reflect the effective or platform-native separator, so that you can always rely on being able to use $OPS explicitly.

$OFS, by contrast is not defined by default, even though its effective value is a space.

In short:

  • If we follow the single-variable, define-on-demand $OFS model, we lose the ability to rely on $OPS to always reflect the effective - opt-in or platform-native - separator.

  • If we want the latter, we need a dynamic all-scopes variable that refers to a separate, define-on-demand, possibly private preference variable and defaults to the platform-native separator in its absence.

@yecril71pl
Copy link
Contributor

(e.g. -join $OPS)

This particular example should be deprecated to Join-Path.

@KirkMunro
Copy link
Contributor

$OFS, by contrast is not defined by default, even though its effective value is a space.

I've never liked this, tbh, and wonder what is gained by having that variable undefined by default. I would like $OPS to be defined by default so that I can rely on it being there when running scripts that use it.

Also, if I ever want to know the platform-native separator, I can just invoke [System.IO.Path]::DirectorySeparatorChar, right? I don't need to have a variable to wrap that field.

(e.g. -join $OPS)

This particular example should be deprecated to Join-Path.

No, it should not.

Using Join-Path with -Path, -ChildPath, and -AdditionalChildPath parameters is cumbersome in scripts. When you want to join a bunch of different segments, -join is much easier to type, and I would argue it's easier to understand as well.

@yecril71pl
Copy link
Contributor

Using Join-Path with -Path, -ChildPath, and -AdditionalChildPath parameters is cumbersome in scripts.

Indeed. That is why you should specify them as positional parameters instead.

@mklement0
Copy link
Contributor

mklement0 commented Dec 23, 2020

Also, if I ever want to know the platform-native separator, I can just invoke [System.IO.Path]::DirectorySeparatorChar

Yes, but that's not only a keyboardful, if you will, but also hard to remember.

I've never liked this, tbh, and wonder what is gained by having that variable undefined by default.

Agreed, and that's why $OPS would be a dynamic all-scopes variable, and only the actual, separate preference variable that opts into using / on Windows too would be undefined by default (tentatively named $PSUseSlash in previous comments).

The sole reason this is necessary is the absence of lexical scoping in PowerShell.

While the problem of a preference variable affecting all child scopes due to dynamic scoping applies to all preference variables (in the case of the global scope even affecting all modules), with the one at hand it would be especially problematic, because:

  • You'll primarily set it in the global scope, for interactive use.
  • Since all code run in that session is then affected, it can break (e.g., certain COM APIs (e.g., Shell.Application, Excel.Application) and some cmd.exe commands only work with \, and, last but not least, user code that operates on the fixed assumption that \ is the path separator).

Hence the need to have an undefined by default variable, that you can easily make private: $private:PSUseSlash = $true. Of course, if you do want all child scopes to use /, you're free to use $PSUseSlash = $true in any scope.

Again, the all-scopes $OPS automatic variable would then either respect a $PSUseSlash variable visible to the current scope, and report [System.IO.Path]::DirectorySeparatorChar otherwise.

@rkitover
Copy link
Contributor

@mklement0 Hey, do you have any interest in following up on your ideas? I and I'm sure many others would love to see better forward slash support on Windows.

@mklement0
Copy link
Contributor

Thanks, @rkitover - while I think pursuing this is worthwhile, I hope someone else takes this on.

@doctordns

This comment has been minimized.

@iSazonov
Copy link
Collaborator

iSazonov commented Dec 23, 2021

@doctordns Don't use street and prison jargon in this respected community
https://github.com/PowerShell/PowerShell/blob/master/CODE_OF_CONDUCT.md

GitHub
PowerShell for every system! Contribute to PowerShell/PowerShell development by creating an account on GitHub.

@mklement0

This comment has been minimized.

@doctordns

This comment has been minimized.

@yecril71pl

This comment has been minimized.

@aaronfranke
Copy link

Yes, there's no need to have "Slash" in the name. PSPathSeparatorChar or similar makes sense to me.

@iSazonov
Copy link
Collaborator

iSazonov commented Dec 24, 2021

Please re-consider your reaction.

@iSazonov , I think @doctordns' point was that a name being considered in this discussion for an official preference variable might be offensive to some, and he explained why.

Such discussions are not acceptable here.
Official linguistic sources do not consider the term offensive. You can find thousands of uses of the term in GitHub repositories and directly in the code.
The correct procedure is described in the CoC. If anyone has a different opinion, follow the CoC. https://github.com/PowerShell/PowerShell/blob/master/CODE_OF_CONDUCT.md

GitHub
PowerShell for every system! Contribute to PowerShell/PowerShell development by creating an account on GitHub.

@yecril71pl

This comment has been minimized.

@doctordns

This comment has been minimized.

@mklement0

This comment has been minimized.

@iSazonov
Copy link
Collaborator

To be clear, my objection was not to the warning, but to the sordid details.
This is categorically unacceptable in the repository.
A gentle warning is enough for PowerShell Committee to take it into account in case they discuss the issue. (For the record, Microsoft already has a list of forbidden terms.)

Once again, please stop discussing in this direction and switch to constructive suggestions.
If someone wants to clean up all of GitHub from millions of uses of the term, they can find the contacts of Microsoft responsible group at CoC.
Please read FAQ there to understand the resolution process. Notice, the process is private - maybe it will give you an understanding of why you shouldn't discuss it publicly here.
If you still prefer otherwise, please use other forums. Here focus on PowerShell development.
Thanks for understanding!

@mklement0
Copy link
Contributor

To be clear, my objection was not to the warning, but to the sordid details.

There were no sordid details - unless you consider a clinical term for a bodily function "sordid".

And it should be self-evident that some description of the potentially offensive meaning of the term in question is necessary.

To also be clear: I have no stake in this discussion (to me the term isn't offensive), but I find this baffling overreaction to a concern voiced by a user in good faith disconcerting.


As for the actual discussion at hand:

FWIW, the current references in the help topics don't use the term in isolation (and I'm not aware of code elements using it at all) - they use backslash and forward slash (again, not a personal concern of mine).

As for constructive suggestions: the discussion already encompasses that too - see @aaronfranke's comment.

I understand your argument that the word is commonly used and should therefore be regarded as acceptable, and perhaps that is ultimately the proper resolution to this discussion.

But there should be always be room for such a discussion (as long as the language used in the discussion doesn't violate the CoC, which I think was definitely not the case here).

@rkeithhill
Copy link
Collaborator

Or we could just skip using that "word" altogether Prince style, and use images instead: 🤣

image

OK, had my fun, backing away from the keyboard.

@PowerShell PowerShell locked and limited conversation to collaborators Dec 25, 2021
@iSazonov iSazonov converted this issue into discussion #16671 Dec 25, 2021

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
Issue-Enhancement the issue is more of a feature request than a bug Resolution-By Design The reported behavior is by design.
Projects
None yet
Development

No branches or pull requests