-
-
Notifications
You must be signed in to change notification settings - Fork 309
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
"Command not found" error when running a batch script with space in path with an argument with space #1812
Comments
|
You don't need to quote strings passed to other programs; at least on a Unix OS. You last example is essentially a no-op. Compare the following:
The last example outputs nothing because your subcommand outputs nothing. The
Why do you think you need to quote the string? I know that historically Windows is rather odd in that programs historically received a single string that included all arguments passed to the program. That is, Windows cmd.exe did not parse the arguments and pass them separately to the program. Cmd.exe instead passed everything after the command name as a single string to the program and it was the responsibility of the program to parse that string into individual arguments. Is that still true? If it is why does shells like Elvish and Cygwin/MSYS2 Bash not seem to have any problem passing arguments to external programs? I'm guessing it's because the code for launching external programs on Windows implicitly escapes individual arguments (according to the usual Windows conventions) and concatenates the resulting strings before launching the external program. Which would mean there isn't any need for you to explicitly quote |
Expanding on a point in my previous comment, you wrote:
I'm not sure what you mean by "worked". The subcommand produces no output because
So you were invoking the |
In all of your examples, none of your paths had a space. On Windows, my user name has one, thus, anything below my home folder, has a space in the path. Passing that to an external program - like VSCode in this case - means that I must quote the path. Otherwise, it won't work. That is why I was trying to find a solution. My suspicion - and I could be wrong - is that by passing it through All I know is that if I used |
Right this must be a windows things, I tried to pass a file with a path with a space in it to vs code and it works fine on macOS. |
I assume the simple two quote characters doesn't work, i.e. var y = '/path with/space'
code ''$y'' For var y = '/path with/space'
code (to-string $y) EDIT: The output is different between > var y = 'Library/Application Support/Auctavo β/649844.padl'
> echo $y
Library/Application Support/Auctavo β/649844.padl
> to-string $y
▶ 'Library/Application Support/Auctavo β/649844.padl'
> put $y
▶ 'Library/Application Support/Auctavo β/649844.padl' |
This is a Windows thing 😞 I'm actually a bit surprised that it took so long for someone to file an issue :) The gist of the issue is that:
Here's an article that goes into more details: The wild west of Windows command line parsing On the one hand, this is not an Elvish problem. On the other hand, Elvish as the shell should obviously do something to help users handle this mess - one way I imagine is some builtin commands that help you do the quoting for certain subclasses of programs, which can then be used to create wrappers that behave as expected in argument passing behavior, like this: fn code {|args|
e:code (windows:quote-args-for-quirky-programs-1 $args)
} This assumes that programs can be sorted into a finite number of "quirk classes" (and there would be windows:quote-args-for-quirky-programs-2, windows:quote-args-for-quirky-programs-3, and so on). I don't know whether that's true or not. |
Hmm OK, this is more complicated than I thought actually. When you pass an argument with spaces to So adding an argument with spaces somehow causes the parsing of the command path to misbehave 🤔 |
I had been under the assumption that, even on Windows, Further, while reading over the replies, I remembered something; I checked on my system:
And then inspected that:
So, it would probably run @echo off
setlocal
set VSCODE_DEV=
set ELECTRON_RUN_AS_NODE=1
"%~dp0..\Code.exe" "%~dp0..\resources\app\out\cli.js" %*
IF %ERRORLEVEL% NEQ 0 EXIT /b %ERRORLEVEL%
endlocal My batch-fu is rusty as heck, but from what I remember, But how come my example from above then does work? I tried to reproduce that by prepending the actual call to package main
import (
"fmt"
"os"
)
func main() {
fmt.Println(len(os.Args), os.Args)
} (Basic build with Next, the reproduction: @echo off
setlocal
"%~dp0.\printer.exe" %*
IF %ERRORLEVEL% NEQ 0 EXIT /b %ERRORLEVEL%
endlocal And finally, the call:
So, clearly, at least in this Go example, the space of Hopefuly this can contribute to finding out what's up here. =) |
Hmm, I believe the error comes before the This is my reproduction: ~> cmd /c md 'C:\a b'
~> echo 'echo foobar' > 'C:\a b\foobar.bat'
~> set @paths = 'C:\a b' $@paths
~> foobar
C:\Users\xiaqq>echo foobar
foobar
~> foobar 'a b'
'C:\a' 不是内部或外部命令,也不是可运行的程序
或批处理文件。
Exception: foobar exited with 1
[tty 45]:1:1-12: foobar 'a b' The last invocation Both PowerShell and cmd deal with Also interestingly, this doesn't happen with binary executables: ~> echo (slurp < print-args.go)
package main
import (
"fmt"
"os"
)
func main() {
fmt.Println(len(os.Args), "arguments")
for i, arg := range os.Args {
fmt.Printf("#%d: %q\n", i, arg)
}
}
~> go build -o 'C:\a b\print-args.exe' print-args.go
~> print-args 'a b'
2 arguments
#0: "C:\\a b\\print-args.exe"
#1: "a b" To recap, the issue seems to be that when all the following are true:
When we try to run the command, something (Elvish? Go stdlib? Windows?) causes the command path to be split, and this results in a "command not found" error. |
Hmm OK, it's golang/go#17149 |
The issue is a bit long, here's my summary of what's relevant for Elvish:
For simplicity, you don't need to go through Go's API to reproduce the issue, you can observe it by running some commands from cmd itself [1]: REM this OK
cmd /c "C:\a b\foobar.bat" foo
REM this is NOT OK for some reason
cmd /c "C:\a b\foobar.bat" "foo bar"
REM but this is OK
cmd /c ""C:\a b\foobar.bat" "foo bar"" I'm not quite sure how the additional pair of quotes work; it doesn't seem to be covered in https://daviddeley.com/autohotkey/parameters/parameters.htm#WINCMDRULES. But maybe I should read this page a few more times. Another issue is that [1] It might not be obvious how this works. Although cmd does some processing of the command line, importantly it doesn't remove any quotes, so if you avoid special characters, your code is used verbatim as the command line to |
Note that the Go issue has been open for more than seven years. Elvish should try to correctly handle this situation if doing so can be accomplished at little cost, but it is preferable to rely on the Go stdlib being updated to handle this scenario. In other words, given all of the other improvements to Elvish that could be implemented my preference is that we simply wait for the Go stdlib to be improved to handle this particular Windows quirk. The limited Elvish developer resources are better spent on issues that are unique to Elvish rather than working around shortcomings of the packages, including the Go stdlib, Elvish depends on if those shortcomings affect very few users of Elvish. |
I appreciate the feedback, but it's up to me or whoever is interested in contributing to decide what to do. |
So, to condense it down: Basically, Thanks for all the additional info. This is such an interesting and weird issue. x) |
Yeah.
You probably can't fix this from "userland" and need to change how Elvish calls into The two suggested workarounds in the Go issue both require modifying the Go stdlib so they are both non-starters. Another workaround suggested multiple times is to manually supply the However, none of these actually solve the problem of escaping metacharacters like Interestingly, although PowerShell handles spaces correctly, it doesn't handle metacharacters correctly. It'd be nice and a bit hilarious if Elvish can support Windows better than PowerShell (at least in this one aspect). |
Hello!
I am going up and down the docs, but I can not seem to make this work:
My username has a space, so the path to my
rc.elv
has one, naturally. But how do I quote, or escape, a variable? I triedre:quote
as well but that didn't help.Any idea?
The text was updated successfully, but these errors were encountered: