Skip to content
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

os/exec: Cannot execute command with space in the name on Windows, when there are parameters #17149

Open
calmh opened this issue Sep 18, 2016 · 15 comments

Comments

@calmh
Copy link
Contributor

@calmh calmh commented Sep 18, 2016

Go 1.7.1 on windows-amd64, Windows 10 latest.

Consider a test project:

src/github.com/calmh/wincmdtest/
    main.go
    folder name/
        test.bat

main.go contents:

package main

import (
    "fmt"
    "os/exec"
    "strings"
)

func main() {
    execCmd("./folder name/test.bat")
    execCmd("./folder name/test.bat", "one param")
}

func execCmd(path string, args ...string) {
    fmt.Printf("Running: %q %q\n", path, strings.Join(args, " "))
    cmd := exec.Command(path, args...)
    bs, err := cmd.CombinedOutput()
    fmt.Printf("Output: %s", bs)
    fmt.Printf("Error: %v\n\n", err)
}

folder name/test.bat contents:

@echo off
echo Success

Expected output is two runs with "Success" in them.

Actual:

C:\Users\jb\Go\src\github.com\calmh\wincmdtest>go run main.go
Running: "./folder name/test.bat" ""
Output: Success
Error: <nil>

Running: "./folder name/test.bat" "one param"
Output: '.' is not recognized as an internal or external command,
operable program or batch file.
Error: exit status 1

It appears that having params on a command, where the command contains a space, breaks the parsing of it. I haven't been able to work around this by experimenting with various ways of quoting the command, using backslashes or slashes, etc.

@calmh

This comment has been minimized.

Copy link
Contributor Author

@calmh calmh commented Sep 18, 2016

I started following this down through syscall.StartProcess, but not really being a Windows programmer I ran into unacceptable levels of nope almost immediately so probably won't try to fix this myself, sorry. :(

@ianlancetaylor ianlancetaylor added this to the Go1.8 milestone Sep 19, 2016
@alexbrainman

This comment has been minimized.

Copy link
Member

@alexbrainman alexbrainman commented Sep 22, 2016

It appears that having params on a command, where the command contains a space, breaks the parsing of it.

Go encodes child process parameters in a way that is understood by most programs. Go uses rules similar to what CommandLineToArgvW implements.

Unfortunately, your child process is cmd.exe (cmd.exe is called to execute the batch file you've requested). And cmd.exe parses its input parameters differently.

You can read this very long post http://daviddeley.com/autohotkey/parameters/parameters.htm#WIN about it all.

I haven't been able to work around this by experimenting with various ways of quoting the command, using backslashes or slashes, etc.

You should stop using exec.Command to build your child process command line, and build it yourself (as per rules described in the doco I mentioned). Then you can pass raw command line to your child process by setting exec.Cmd.SysProcAttr to syscall.SysProcAttr with CmdLine set appropriately.

Maybe we could fix this problem by changing Go encoding algorithm to use cmd.exe rules every time we execute batch file.

There is more of the same discussion on issue #15566.

Alex

@mattn

This comment has been minimized.

Copy link
Member

@mattn mattn commented Nov 1, 2016

I guess this should be fixed by small change.

diff --git a/src/syscall/exec_windows.go b/src/syscall/exec_windows.go
index cafce1e..a0e1f56 100644
--- a/src/syscall/exec_windows.go
+++ b/src/syscall/exec_windows.go
@@ -91,6 +91,9 @@ func makeCmdLine(args []string) string {
        }
        s += EscapeArg(v)
    }
+   if s != "" && s[0] == '"' && len(args) > 1 {
+       s = `"` + s + `"`
+   }
    return s
 }

If the first argument contain spaces, and it have arguments (no matter if the argument not contains spaces), whole of string should be quoted.

c:\dev\go-sandbox\space>go run main.go
Running: ".\\folder name\\test.bat" ""
Output: Success
Error: <nil>

Running: ".\\folder name\\test.bat" "one param"
Output: Success
Error: <nil>
@gopherbot

This comment has been minimized.

Copy link

@gopherbot gopherbot commented Nov 1, 2016

CL https://golang.org/cl/32490 mentions this issue.

@rsc

This comment has been minimized.

Copy link
Contributor

@rsc rsc commented Nov 3, 2016

Postponing decisions about this to Go 1.9.

@basepack

This comment has been minimized.

Copy link

@basepack basepack commented Oct 13, 2017

+1 This is still an issue here, also see: docker/machine#3152

@alexbrainman

This comment has been minimized.

Copy link
Member

@alexbrainman alexbrainman commented Oct 16, 2017

@cannect docker/machine#3152 title mentions "powershell", but this issue is about running batch files. How do you know that if we make running batch file work, that it will fix docker/machine#3152 ?
Is there a simple way to reproduce docker/machine#3152 ?

Alex

@basepack

This comment has been minimized.

Copy link

@basepack basepack commented Oct 16, 2017

As you can see here: docker/machine#3152 (comment) there is some confidence we think it is related with this issue.

@alexbrainman

This comment has been minimized.

Copy link
Member

@alexbrainman alexbrainman commented Oct 16, 2017

@cannect do you know of a simple way to reproduce docker/machine#3152 ?
How did you personally discovered docker/machine#3152 ? Did you encountered that problem yourself?

Alex

@basepack

This comment has been minimized.

Copy link

@basepack basepack commented Oct 16, 2017

Hi @alexbrainman ,

I had exact the same issues as described in the first post of docker/machine#3152.
I do not have the knowledge to reproduce that issue in Go. But I can tell you my steps:

  • WIndows 10 Pro
  • Docker for Windows
  • Started two docker machines in Windows 10 bash, listed as active in docker-machine ls
  • Looked those docker machines up with: docker-machine ls in Powershell, machines not active. (but they were active of course but not listed as such in Powershell)

Unfortunately I have no experience whatsoever with Go.

@alexbrainman

This comment has been minimized.

Copy link
Member

@alexbrainman alexbrainman commented Oct 22, 2017

@cannect thank you very much for these steps. But I have never used Docker for Windows. How do I install it and use it?

Docker for Windows

How do I install it? What are the steps?

Looked those docker machines up with: docker-machine ls in Powershell, machines not active. (but they were active of course but not listed as such in Powershell)

What are the commands I should run to reproduce this? What did you do? What did you expect to see? What did you see instead?

Thank you

Alex

@bradfitz bradfitz modified the milestones: Go1.10, Go1.11 Nov 29, 2017
@rsc

This comment has been minimized.

Copy link
Contributor

@rsc rsc commented Jun 11, 2018

I agree with #17149 (comment) that the answer here should be to rewrite the path for argv[0] from using slash to backslash. We should try to fix this early in the Go 1.12 cycle.

@benlye

This comment has been minimized.

Copy link

@benlye benlye commented Mar 18, 2019

Any progress on this issue?

I'd like to add that it only seems to be a problem when both the command and the parameter contain spaces. If only one or the other has a space then everything works. I've expanded on @calmh's example to demonstrate:

main.go:

package main

import (
    "fmt"
    "os/exec"
    "strings"
)

func main() {
    execCmd("C:/Users/blye/Go/src/github.com/benlye/cmdtest/folder name/test.bat")
    execCmd("C:/Users/blye/Go/src/github.com/benlye/cmdtest/folder name/test.bat", "oneparam")
    execCmd("C:/Users/blye/Go/src/github.com/benlye/cmdtest/folder name/test.bat", "one param")

    execCmd("C:/Users/blye/Go/src/github.com/benlye/cmdtest/foldername/test.bat")
    execCmd("C:/Users/blye/Go/src/github.com/benlye/cmdtest/foldername/test.bat", "oneparam")
    execCmd("C:/Users/blye/Go/src/github.com/benlye/cmdtest/foldername/test.bat", "one param")
    }

func execCmd(path string, args ...string) {
    fmt.Printf("Running: %q %q\n", path, strings.Join(args, " "))
    cmd := exec.Command(path, args...)
    bs, err := cmd.CombinedOutput()
    fmt.Printf("Output: %s", bs)
    fmt.Printf("Error: %v\n\n", err)
}

Produces only one failure (the 3rd test):

C:\Users\blye\Go\src\github.com\benlye\cmdtest>go run main.go
Running: "C:/Users/blye/Go/src/github.com/benlye/cmdtest/folder name/test.bat" ""
Output: Success
Error: <nil>

Running: "C:/Users/blye/Go/src/github.com/benlye/cmdtest/folder name/test.bat" "oneparam"
Output: Success
Error: <nil>

Running: "C:/Users/blye/Go/src/github.com/benlye/cmdtest/folder name/test.bat" "one param"
Output: 'C:/Users/blye/Go/src/github.com/benlye/cmdtest/folder' is not recognized as an internal or external command,
operable program or batch file.
Error: exit status 1

Running: "C:/Users/blye/Go/src/github.com/benlye/cmdtest/foldername/test.bat" ""
Output: Success
Error: <nil>

Running: "C:/Users/blye/Go/src/github.com/benlye/cmdtest/foldername/test.bat" "oneparam"
Output: Success
Error: <nil>

Running: "C:/Users/blye/Go/src/github.com/benlye/cmdtest/foldername/test.bat" "one param"
Output: Success
Error: <nil>
@alexbrainman

This comment has been minimized.

Copy link
Member

@alexbrainman alexbrainman commented Mar 20, 2019

Any progress on this issue?

I don't believe anyone working on this.

I'd like to add that it only seems to be a problem when both the command and the parameter contain spaces. ...

I am pretty sure we know what the problem is (see #17149 (comment) for details). We just have not decided how to fix it.

Alex

@someblue

This comment has been minimized.

Copy link

@someblue someblue commented Sep 19, 2019

For those stuck by this bug:

As #17149 (comment) mentioned, this problem happened only when both binary path and arguments have space. So you can write a .bat file wrapping all arguments, and then run this .bat directly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
You can’t perform that action at this time.