Repository navigation
Description
I've put the script section first, instead of the description of the issue, because my examples aforementioned utilize values from this script to demonstrate the problem.
Prerequisites
- Write a descriptive title.
- Make sure you are able to repro it on the latest released version
- Search the existing issues.
- Refer to the FAQ.
- Refer to Differences between Windows PowerShell 5.1 and PowerShell.
Expected behaviour
Originally, this issue was going to be about how PowerShell can't handle certain legal UTF-8 characters in inode paths. However, after creating a test script:
#!/usr/bin/env -S pwsh -File
# Prerequisites
# -------------
# ~~~pwsh
# #Requires -PSEdition 'Core'
# #Requires -Version 7
# ~~~
Set-Location -LiteralPath "$HOME"
# Example Directory
# -----------------
# Creates an example directory.
$DirectoryPath = 'TabPrefixed ExampleDirectory.dir'
$PrintPath = "$DirectoryPath"
Write-Output (Show-Markdown -InputObject "The path is ``$PrintPath``.")
New-Item `
-Path "$HOME" `
-Name "$DirectoryPath" `
-ItemType 'directory'
# Example File
# ------------
# Creates an example file.
$FilePath = 'TabPrefixed ExampleFile.txt'
$PrintPath = "$FilePath"
Write-Output (Show-Markdown -InputObject "The path is ``$PrintPath``.")
New-Item `
-Path ("$HOME" + [IO.Path]::DirectorySeparatorChar + "$DirectoryPath") `
-Name "$FilePath" `
-ItemType 'file' `
-Value 'Example text.'
# Path Acquisition
# ----------------
# Lists both.
$FullFilePath = (`
Get-ChildItem `
-LiteralPath (
"$HOME" + [IO.Path]::DirectorySeparatorChar +
"$DirectoryPath" + [IO.Path]::DirectorySeparatorChar +
"$FilePath")
)[0] | Select-Object -ExpandProperty 'FullName'
# File Content Acquisition
# ------------------------
# This should fail.
$PrintPath = "$FullFilePath"
Write-Output (Show-Markdown -InputObject "The path is ``$PrintPath``.")
Get-Content -LiteralPath "$FullFilePath"
Write-Output $?I realized that it could. Instead, I've narrowed it to a fault in how PowerShell, via Konsole and VSCode's terminals, interprets certain characters (like - tabs) as control codes.
Steps to reproduce
Try pasting your equivalent to the undermentioned command:
#!/usr/bin/env pwsh
Get-Content -LiteralPath '/home/RokeJulianLockhart/TabPrefixed ExampleDirectory.dir/TabPrefixed ExampleFile.txt'...into the shell after successfully invoking it.
This value is able to be acquired by the undermentioned command:
#!/usr/bin/env pwsh
(Get-ChildItem -LiteralPath "$DirectoryPath")[0].FullNameActual behavior
-
The undermentioned is a command that has been pasted:
#!/usr/bin/env pwsh Get-Content -LiteralPath "/home/RokeJulianLockhart/Documents/pyside6/prefix^Iexample.txt/example.txt"
Note within it, the "
prefix^Iexample". The original content does not contain that control code. -
Alternatively, sometimes, it appears to paste the path correctly, but doesn't recognise the value unless passed in a script:
-
PS /home/RokeJulianLockhart> (Get-ChildItem -LiteralPath "$DirectoryPath")[0].FullName /home/RokeJulianLockhart/TabPrefixed ExampleDirectory.dir/TabPrefixed ExampleFile.txt
-
PS /home/RokeJulianLockhart> Get-Content -LiteralPath '/home/RokeJulianLockhart/TabPrefixed ExampleDirectory.dir/TabPrefixed ExampleFile.txt' Get-Content: Cannot find path '/home/RokeJulianLockhart/TabPrefixed ExampleDirectory.dir/TabPrefixed ExampleFile.txt' because it does not exist.
-
PS /home/RokeJulianLockhart> Get-Content -LiteralPath "$FullFilePath" Example text.
-
PS /home/RokeJulianLockhart> Write-Output "$FullFilePath" /home/RokeJulianLockhart/TabPrefixed ExampleDirectory.dir/TabPrefixed ExampleFile.txt
-
Error details
-
#!/usr/bin/env pwsh Get-Error
-
Exception : Type : System.Management.Automation.ItemNotFoundException ErrorRecord : Exception : Type : System.Management.Automation.ParentContainsErrorRecordException Message : Cannot find path '/home/RokeJulianLockhart/TabPrefixed ExampleDirectory.dir/TabPrefixed ExampleFile.txt' because it does not exist. HResult : -2146233087 TargetObject : /home/RokeJulianLockhart/TabPrefixed ExampleDirectory.dir/TabPrefixed ExampleFile.txt CategoryInfo : ObjectNotFound: (/home/RokeJulianLoc… ExampleFile.txt:String) [], ParentContainsErrorRecordException FullyQualifiedErrorId : PathNotFound ItemName : /home/RokeJulianLockhart/TabPrefixed ExampleDirectory.dir/TabPrefixed ExampleFile.txt SessionStateCategory : Drive TargetSite : Name : ResolveDriveQualifiedPath DeclaringType : [System.Management.Automation.LocationGlobber] MemberType : Method Module : System.Management.Automation.dll Message : Cannot find path '/home/RokeJulianLockhart/TabPrefixed ExampleDirectory.dir/TabPrefixed ExampleFile.txt' because it does not exist. Source : System.Management.Automation HResult : -2146233087 StackTrace : at System.Management.Automation.LocationGlobber.ResolveDriveQualifiedPath(String path, CmdletProviderContext context, Boolean allowNonexistingPaths, CmdletProvider& providerInstance) at System.Management.Automation.LocationGlobber.GetGlobbedMonadPathsFromMonadPath(String path, Boolean allowNonexistingPaths, CmdletProviderContext context, CmdletProvider& providerInstance) at System.Management.Automation.PathIntrinsics.GetResolvedPSPathFromPSPath(String path, CmdletProviderContext context) at Microsoft.PowerShell.Commands.ContentCommandBase.ResolvePaths(String[] pathsToResolve, Boolean allowNonexistingPaths, Boolean allowEmptyResult, CmdletProviderContext currentCommandContext) TargetObject : /home/RokeJulianLockhart/TabPrefixed ExampleDirectory.dir/TabPrefixed ExampleFile.txt CategoryInfo : ObjectNotFound: (/home/RokeJulianLoc… ExampleFile.txt:String) [Get-Content], ItemNotFoundException FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetContentCommand InvocationInfo : MyCommand : Get-Content ScriptLineNumber : 1 OffsetInLine : 1 HistoryId : 12 Line : Get-Content -LiteralPath '/home/RokeJulianLockhart/TabPrefixed ExampleDirectory.dir/TabPrefixed ExampleFile.txt' Statement : Get-Content -LiteralPath '/home/RokeJulianLockhart/TabPrefixed ExampleDirectory.dir/TabPrefixed ExampleFile.txt' PositionMessage : At line:1 char:1 + Get-Content -LiteralPath '/home/RokeJulianLockhart/TabPrefixed Exa … + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ InvocationName : Get-Content CommandOrigin : Internal ScriptStackTrace : at <ScriptBlock>, <No file>: line 1 PipelineIterationInfo : 0 1
Forgot to Export-CLIXML.
Environment data
-
#!/usr/bin/env pwsh $PSVersionTable | ConvertTo-YAML
-
OS: Fedora Linux 40 (KDE Plasma) SerializationVersion: Major: 1 Minor: 1 Build: 0 Revision: 1 MajorRevision: 0 MinorRevision: 1 PSRemotingProtocolVersion: Major: 2 Minor: 3 Build: -1 Revision: -1 MajorRevision: -1 MinorRevision: -1 Platform: Unix WSManStackVersion: Major: 3 Minor: 0 Build: -1 Revision: -1 MajorRevision: -1 MinorRevision: -1 GitCommitId: 7.4.3 PSEdition: Core PSVersion: Major: 7 Minor: 4 Patch: 3 PreReleaseLabel: BuildLabel:
Activity
237dmitry commentedon Jul 10, 2024
How it could be represented? As in bash?
beedell-roke commentedon Jul 10, 2024
237dmitry, I've asked about that at SE SuperUser, and the answer is such that it does appear feasible. Especially, for PowerShell, these utilities don't even need to be able to detect other shells' syntaxes (like
lsdoes). Certainly, I can't think of any other solution this, else I would have filed this as an FR (rather than the BR it is).Ideally, either
-LiteralPathshould actually accept verbatim the characters (and never automatically convert pasted paths into partially-escaped ones, like it very occasionally does) or we should automatically escape duplicated paths in every situation. Either would be easily comprehensible to the user.237dmitry commentedon Jul 10, 2024
Yes, I think so. Maybe with
`tor\treplacement.beedell-roke commentedon Jul 10, 2024
237dmitry, my point is merely that the user shouldn't need to manually modify the path before pasting it, since they don't need to in scripts.
kasini3000 commentedon Jul 10, 2024
1 Usually, saving the script as UTF8 encoding with BOM header can solve the problem of file names with special encoding in the script. But this is not compatible with “#!"
2 I usually use mkdir - p 'directory name with utf8 encoding'
beedell-roke commentedon Jul 11, 2024
kasini3000:
That's a good point - I've been using UTF-8 with a BOM for my PS1 scripts, which hasn't been problematic because I use VSCode's configuration to determine the debugger. Perhaps I didn't notice it in my scripts because of that.rhubarb-geek-nz, indeed,
PSReadLineseems like the better place for this, because it's certainly context-dependent - I think having this behaviour work in-LiteralPatharguments would usually be enough - and because, as you state, there are limitations to a terminal GUI.Can someone transfer this? Otherwise, I'll create a new issue there.-LiteralPatharguments as verbatim characters. PSReadLine#4072 (comment)mklement0 commentedon Jul 11, 2024
For context:
The concept of a character-encoding such as UTF-8 doesn't apply to in-memory strings getting pasted.
Technically, a tab character is in the ASCII subrange of the Unicode "alphabet", and is a so-called C0 control character.
Pasting into a terminal in most environments is done by simulated typing, unfortunately. In such environments pasting something with a tab causes that tab char. to be interpreted as a request for tab-completion, thereby effectively discarding the tab while possibly altering what is pasted.
While the old-style
conhost.execonsole windows on Windows do support direct pasting, they seemingly discard tab characters.macOS terminals either quietly convert a pasted tab to a space (Terminal.app) or prompt for whether the tabs should be pasted (iTerm.app), but the pasting then again happens via simulated typing.
I'm unclear on whether PSReadLine even has the option to override these behaviors.
As for tab-completing a filename with embedded tabs (not supported on Windows), as observed on macOS:
bashcompletes with a literal tab char., properly escaped^Iand not escaped, which could be considered a bug (to make it work, the^Imust either be`-escaped, or the whole argument must be quoted; that is, PowerShell itself doesn't recognize the need to quote such a path).beedell-roke commentedon Jul 11, 2024
Michael Klement (@mklement0), that's a brilliantly comprehensive explanation. Would you consider this issue a duplicate of PowerShell/PSReadLine#1471 (comment), or should I file a separate issue at that repository? Alternatively, considering that you doubt that
PSReadLineis able to override this, can you advise whether there might there be merit to leaving this open here?Additionally, microsoft/terminal#9034 (comment) appears to indicate that this might need to be supported by the terminal too, and I don't know whether VSCode and Konsole support bracketed paste anyway.
mklement0 commentedon Jul 11, 2024
Thanks, @RokeJulianLockhart.
PowerShell/PSReadLine#1471 (comment) may be a duplicate - I'm not certain if tabs would be retained as-is as part of a bracketed paste.
I see that you opened a new PSReadLine issue: I suggest updating it with the above information.
It looks like the Windows Terminal PR you linked to was merged quite a while ago, so I assume the feature is already in place.
237dmitry commentedon Jul 11, 2024
When using
Get-Clipboard, tab characters are not replaced with spaces.:daxian-dbw commentedon Jul 11, 2024
@RokeJulianLockhart As shown in the screenshot below, you copied the text from the terminal output before pasting to
Get-Content -LiteralPath. I believe when you copy the terminal output, you already lost the tab characters\t. Can you please double check if that's the case? You can check by pasting to VSCode editor after copying from the terminal output, and see if the tab has been replaced with spaces already.mklement0 commentedon Jul 11, 2024
Dongbo Wang (@daxian-dbw), while it is true that tab chars. are lost when copying output from VSCode's integrated terminal (they become spaces), the problem exists even if you paste a string with bona fide tab characters.
daxian-dbw commentedon Jul 12, 2024
Yes, I understand. Tab is intentionally replaced with 4 space characters (see the code), and it was a by design change: PowerShell/PSReadLine#144.
I just want to point out that the scenario described by this issue -- copy the terminal output and paste in your command -- won't work even if PSReadLine doesn't alter the Tab character. And I don't think it's worth breaking the current behavior.
mklement0 commentedon Jul 12, 2024
Dongbo Wang (@daxian-dbw):
Good to know about PSReadLine's tabs-to-spaces conversion.
That may be true for VSCode, but it isn't true for other terminal emulators, such as on macOS - on copying, they do preserve literal tab chars. in the selection.
Let me try to summarize:
PSReadLine converts each literal tab char. pasted into 4 spaces by design; Bash's readline library appears to do a similar thing (1 space). Additionally, terminal applications such as iTerm.app on macOS themselves offer modifying the pasted text if it contains tab chars., before passing it to the target shell.
PowerShell's tab-completion completes file names with embedded tab chars. as such, but renders them as
^I(which is just a display problem). However, it neglects to quote such file names, which is arguably a bug (but, again, an edge case).FenixxAngel commentedon Jul 13, 2024
beedell-roke commentedon Jul 14, 2024
beedell-roke commentedon Oct 22, 2024
Dongbo Wang (@daxian-dbw), my sincere apologies for the wait to respond. I've been spending some time diagnosing some related problems, like microsoft/debugpy#1671 (comment), and then migrating wholesale away from tabs in file names. 1
Irrespective, it certainly does appear to be replaced, and solely by
pwsh- notbash:To demonstrate that I'm not mistakenly utilizing the content pasted to the CLI:
2024-10-22.17-57-45.mp4
Footnotes
stackoverflow.com/revisions/79048760/10↩beedell-roke commentedon Oct 22, 2024
237dmitry, I'd try
Get-Clipboard, but I'm blocked by Pscx/Pscx#103 (comment), and #26832 (comment).Consequently, are you using Windows? If so, I'm surprised you can use tabs in filenames, considering that they're explicitly illegal in filenames created via the Win32 API (as all early UTF-8/ASCII whitespace characters are).Those are merely symbols duplicated into the clipboard - apologies.beedell-roke commentedon Oct 22, 2024
Michael Klement (@mklement0), thanks for the advice, especially per PowerShell/PSReadLine#4072 (comment). Do you suggest that I merely duplicate the content of #24037 (comment) into the technical implementation section? I ask because I doubt that I am able to accurately rephrase it.
mklement0 commentedon Oct 22, 2024
I suggest opening a new PSReadLine issue that succinctly describes the problem; feel free to adapt / copy the text from my comment in the process.
beedell-roke commentedon Feb 4, 2025
Michael Klement (@mklement0), this is a lot to get my head around. Summarily, should I request that
PSReadLinenot escape tab characters (unless at the start of a line)?mklement0 commentedon Feb 4, 2025
@RokeJulianLockhart, you could ask that PSReadLine paste tabs as-is, though given @daxian-dbw's comment above, I'm not sure such a change will be considered.
If it were to be considered, note that PowerShell/PSReadLine#1471 must be implemented first, because, without paste bracketing, pasting involves simulated typing, so that a tab char. as part of a pasted string would trigger tab-completion
(this is what's currently happening on macOS and Linux).
beedell-roke commentedon Feb 4, 2025
Michael Klement (@mklement0), thanks. Filed at PowerShell/PSReadLine#4447 (comment).
bonneville-nathan commentedon Nov 5, 2026
I may have a similar issue. I don't have the time to make a full issue out of it, but the gist is that when the working directory is inside a URN directory on my company network, pasting a move action into Powershell (which I have to do since I can't execute scripts) Powershell does not interpret the paths I've pasted as valid paths.
However, if I don't execute the script, I can arrow key to the first path, erase the extension, and hit tab to autocomplete the file, Powershell interprets this fine.
beedell-roke commentedon Nov 5, 2026
bonneville-nathan commentedon Nov 5, 2026
Good tip! Thanks!