Terminal: Terminal should always wrap drag-dropped paths in double quotes

Created on 30 Oct 2020  ·  20Comments  ·  Source: microsoft/terminal

Environment

Microsoft Windows [版本 10.0.18363.1139]
Windows Terminal [ powershell]
版本: 1.3.2651.0
python 3.7

Steps to reproduce

1.write the followings code
xx.py
import sys
with open(sys.argv[1]) as f:
pass
2.create a txt as "xxx(1).txt", the name must include"()"
3:open windows terminal powershell, cd to the xx.py directory
input “python xx.py”
drop the txt into terminal
run
4.if the filename contain "(xx)" can not resolve the path.

Expected behavior

it worked in cmd
open the file success

Actual behavior

FileNotFoundError: [Errno 2] No such file or directory: 'C:\Users\xx\Desktop\\input'

Area-TerminalControl Issue-Task Priority-3 Product-Terminal

All 20 comments

it alse crashed a few mins later, if drop the file into powershell,

Based on what I understand, this isn't a terminal issue. For python to recognize the path, you'll need manually escape the path using something like C:\\Users\\xx\\Desktop\\xxx.txt.

The crash may be related to #7804 . But #7804 is an instantaneous crash instead of "a few mins later" one. So I'm not very positive about this.

Does this work in powershell _outside_ of the Terminal? (e.g. in powershell.exe launched directly from the run dialog or Start Menu?)

@alannt777 Okay that doesn't really look like the issue at hand though, that just looks like explorer glitched out and thought you double clicked the file tbh.

@zadjii-msft Looks like it came before I pressed enter and that enter never made into powershell. I will update the GIF anyway.

@zadjii-msft I have updated the GIF. Looks like a PowerShell issue (I did not try this in cmd but the author said that it works)

Repro in (PowerShell) Terminal:

repro in terminal

Same thing happens in conhost.exe with PowerShell:

repro in conhost

(1).txt part of the path is getting ignored by either python/powershell

Most likely it is powershell if it works fine in cmd.exe

Does this work in powershell _outside_ of the Terminal? (e.g. in powershell.exe launched directly from the run dialog or Start Menu?)

It not wor

Based on what I understand, this isn't a terminal issue. For python to recognize the path, you'll need manually escape the path using something like C:\\Users\\xx\\Desktop\\xxx.txt

With open(r”%s” %sys.argv[1]) as f:pass

it not worked as well,and the escape only happened by “/“ or “” ,the file name like xx(xx).txt , the power shell resolved the name as “xx”,del the tail “(xx).txt” .if drop the file into terminal,and add “ at the path beginning and ends, it will be work.

Python relies on the C runtime to parse command line arguments. The CRT has no special handling of brackets -- only quote and backslash, so Python is not to blame here. This issue relates to how the console/terminal drop handler adds the filename to the input buffer, i.e. quoted or unquoted, and the shell's handling of special characters such as brackets in the given context.

Drag-and-drop of filenames is simple in POSIX because the filename can be dropped literally in single quotes. In contrast, Windows has a mix of shells -- including CMD, PowerShell, and bash -- which have different quoting rules. The console/terminal drop handler could quote every dropped file in double quotes, instead of just quoting files that have one or more spaces in them. That handles some but not all cases in CMD and PowerShell. It won't handle, for example, dropping a file named "test $home.txt" in PowerShell or "test %userprofile%.txt" in CMD. Shell variables or environment variables will still be evaluated in a string enclosed in double quotes. The user has to handle such cases manually.

Quotes around the path would fix this problem:

Adding quotes would fix this problem

Possible "fix" for this is:

When a file is dragged into the Terminal, enclose the path in quotes

With open(r”%s” %sys.argv[1]) as f:pass

There is no need to try to escape backslashes. Python does this for you:

image

When a file is dragged into the Terminal, enclose the path in quotes

This is already implemented if the filename contains spaces. I don't think it would be a problem to always do it.

Enclosing a string in double quotes escapes special characters in PowerShell (see about quoting rules), except for "$" variable substitution. Single-quote strings escape variable substitution as well. CMD only supports escaping via double-quote strings, which evaluate "%" variable substitutions. Either type allows passing (1) literally.

MSVC argv and WinAPI CommandLineToArgvW only support double-quote strings. PowerShell and WSL accommodate this by translating single-quote strings to double-quote strings in a command line, e.g. py.exe hello.py 'test(1).txt' gets passed to WinAPI CreateProcessW as py.exe hello.py "test(1).txt".

There is no need to try to escape backslashes. Python does this for you:

The arrow is pointing at the repr (string-literal representation) of the in-memory string "G:Testtest". This isn't related to escaping of the command line. Python just uses the argv array that's parsed by MSVC.

Nb专业讲究

发自我的iPhone

在 2020年10月31日,下午4:44,Eryk Sun notifications@github.com 写道:



When a file is dragged into the Terminal, enclose the path in quotes

This is already implemented if the file contains spaces. I don't think it would be a problem to always do it.

Enclosing a string in double quotes escapes special characters in PowerShell (see about quoting ruleshttps://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_quoting_rules?view=powershell-7), except for "$" variable substitution. Single-quote strings escape variable substitution as well. CMD only supports escaping via double-quote strings, which evaluate "%" variable substitutions. Either type allows passing (1) literally.

MSVC argv and WinAPI CommandLineToArgvW only support double-quote strings. PowerShell and WSL accommodate this by translating single-quote strings to double-quote strings in a command line, e.g. py.exe hello.py 'test(1).txt' gets passed to WinAPI CreateProcessW as py.exe hello.py "test(1).txt".

There is no need to try to escape backslashes. Python does this for you:

The arrow is pointing at the repr (string-literal representation) of the in-memory string "G:Testtest". This isn't related to escaping of the command line. Python just uses the argv array that's parsed by MSVC.


You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHubhttps://github.com/microsoft/terminal/issues/8109#issuecomment-719904515, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AMD77YDGB2ASBHTPQKZ3NCDSNPE6VANCNFSM4TEVZZNQ.

The arrow is pointing at the repr (string-literal representation) of the in-memory string "G:Testtest". This isn't related to escaping of the command line. Python just uses the argv array that's parsed by MSVC.

Anyway, you don't have to escape it manually, right?

Enclosing a string in double quotes escapes special characters in PowerShell (see about quoting rules), except for "$" variable substitution. Single-quote strings escape variable substitution as well. CMD only supports escaping via double-quote strings, which evaluate "%" variable substitutions. Either type allows passing (1) literally.

We could replace $ with `$ and replace % with what I believe is %%

We could replace $ with `$ and replace % with _what I believe is %%_

I think heading down the path of special-casing certain client processes would be confusing to the end user regarding which shells and applications are special cased. Also, %% is for batch scripts. AFAIK, CMD has no intended way to escape % at the interactive prompt. It executes an initial parse to substitute for % variables, which you can disrupt with CMD's ^ escape character, such as using %^SPAM% to 'escape' %SPAM%. This doesn't work if the variable name itself contains ^, such as set "^SPAM=EGGS" for a variable named ^SPAM.

This idea itself seems to be not very applicable and be confusing for the end users

Alright so after a very convoluted discussion, TL;DR:

  • This appears broken, because the filename isn't enclosed in double-quotes, and powershell treats the (1) in the file name as special characters.
  • This could be fixed by always wrapping drag-dropped paths in double quotes _always_. This would be safe for other shells as well as powershell.
  • This could also be worked-around by just manually wrapping the path in double quotes.

I'll make this issue track "always wrap drag-dropped paths in double quotes", and toss it on the backlog. Thanks all!

Can we have some configurable list of characters which must be quoted, for people who prefer it to not always quote?

We could keep this list of characters for common shells, but have it configurable for each profile for any other shells/

Was this page helpful?
0 / 5 - 0 ratings

Related issues

DieselMeister picture DieselMeister  ·  3Comments

wkbrd picture wkbrd  ·  3Comments

ghost picture ghost  ·  3Comments

NickITGuy picture NickITGuy  ·  3Comments

TayYuanGeng picture TayYuanGeng  ·  3Comments