Go:正确运行带参数的外部程序

huangapple go评论70阅读模式
英文:

Go : Correctly running external program with arguments

问题

晚上好,
我正在将一些用Python编写的工具转换为Go,以便更好地理解它。

我需要程序调用一个外部的.exe文件,并传入一些参数,以便正确格式化一些数据。在Windows shell中,我可以这样做:C:\path_to_exe\file.exe arg1 arg2 "C:\path_to_output\output.txt"

我认为在Go中正确的方法是使用exec.Command,但我没有得到任何有意义的结果。

out, err := exec.Command("cmd", "C:\\path\\tools\\util\\Utility.exe C:\\file_Location \"select * from TABLE\" C:\\output_path\\output.txt").Output()

fmt.Printf("\n", string(out))

if err != nil {
    println(" Error running decomp ", err)
}

这似乎是在运行命令,因为我收到的输出是:

%!(EXTRA string=Microsoft Windows [Version 10.0.22000.739]
(c) Microsoft Corporation. All rights reserved.
Process finished with the exit code 0

为了好玩,我尝试分解参数,但结果是一样的:

out, err := exec.Command("cmd", exPath, utilPath, statement, textOutputPath+"test.txt").Output()

我期望执行的程序能够根据输入解析正确的文件,并输出指定的txt文件。但我没有得到.txt文件,而且Go程序运行得比解析应该花费的时间要快。

我一定是漏掉了什么,有人可以提供一些关于正确使用exec.Command的见解吗?因为我能找到的每个示例似乎都表明这应该可以工作。

英文:

Good evening,
I'm working on converting some tools written in python to Go in order to better understand it.

I need the program to call an external .exe with some arguments in order for it to correctly format some data. In the windows shell I can do C:\path_to_exe\file.exe arg1 arg2 "C:\path_to_output\output.txt"

I believe the correct method to do this in Go would be using exec.Command, but I'm not getting any...meaningful results.

out, err := exec.Command("cmd", "C:\\path\\tools\\util\\Utility.exe C:\\file_Location \"select * from TABLE\" C:\\output_path\\output.txt").Output()

			fmt.Printf("\n", string(out))

			if err != nil {
				println(" Error running decomp ", err)
			}

This appears to be running command, as the output I am receiving is:

%!(EXTRA string=Microsoft Windows [Version 10.0.22000.739]
(c) Microsoft Corporation. All rights reserved.
Process finished with the exit code 0

Just for giggles I tried breaking up the arguments, but the same result was achieved

out, err := exec.Command("cmd", exPath, utilPath, statement, textOutputPath+"test.txt").Output()

I'm expecting the executed program to run, parse the correct file based on the input, and output the specified txt file. I am left with no .txt file, and the go program runs much faster then the parsing should take.

There must be something I'm missing, could someone please provide some insight on the correct usage of exec.Command, because every example I can find appears to show that this should work.

答案1

得分: 2

为什么你要生成cmd.exe并让它运行你的utility.exe呢?

你可以直接生成utility

例如,假设你有两个二进制文件,hellosay-hello,它们位于同一个目录中,编译自以下代码:

  • hello.gohello:

    package main
    
    import (
      "fmt"
      "os"
    )
    
    func main() {
    
      argv := os.Args[1:]
      if len(argv) == 0 {
        argv = []string{"world"}
      }
    
      for _, arg := range argv {
        fmt.Printf("Hello, %s!\n", arg)
      }
    
    }
    
  • say-hello.gosay-hello:

    package main
    
    import (
      "fmt"
      "os"
      "os/exec"
    )
    
    func main() {
      process := exec.Command("./hello", os.Args[1:]...)
      process.Stdin = os.Stdin
      process.Stdout = os.Stdout
      process.Stderr = os.Stderr
    
      if err := process.Run(); err != nil {
        fmt.Printf("Command failed with exit code %d\n", process.ProcessState.ExitCode())
        fmt.Println(err)
      }
    }
    

然后你可以运行以下命令:

$ ./say-hello Arawn Gywdion Sarah Hannah

并得到预期的输出:

Hello, Arawn!
Hello, Gwydion!
Hello, Sarah!
Hello, Hannah!
英文:

Why are you spawning cmd.exe and having it run your utility.exe?

You can just spawn utility on its own.

For instance, suppose you have two binaries, hello and say-hello living in the same directory, compiled from

  • hello.go → hello:

    package main
    
    import (
      "fmt"
      "os"
    )
    
    func main() {
    
      argv := os.Args[1:]
      if len(argv) == 0 {
        argv = []string{"world"}
      }
    
      for _, arg := range argv {
        fmt.Printf("Hello, %s!\n", arg)
      }
    
    }
    
  • say-hello.go → say-hello:

    package main
    
    import (
      "fmt"
      "os"
      "os/exec"
    )
    
    func main() {
      process := exec.Command("./hello", os.Args[1:]...)
      process.Stdin = os.Stdin
      process.Stdout = os.Stdout
      process.Stderr = os.Stderr
    
      if err := process.Run(); err != nil {
        fmt.Printf("Command failed with exit code %d\n", process.ProcessState.ExitCode())
        fmt.Println(err)
      }
    }
    

You can then run the command:

$ ./say-hello Arawn Gywdion Sarah Hannah

And get back the expected

Hello, Arawn!
Hello, Gwydion!
Hello, Sarah!
Hello, Hannah!

答案2

得分: 1

根据你的问题中的输出,看起来代码运行正确。

以下是一些建议:

  • 在运行命令之前,将命令作为字符串打印出来,以检查是否符合你的要求。
  • 当字符串包含反斜杠和引号时,使用反引号可能会很有用。
  • fmt.Printf 没有提供任何格式,因此在输出中会出现 EXTRA
  • 使用 println 打印错误时不会将其转换为字符串,所以在这种情况下也应该使用 fmt.Printf
package main

import (
	"fmt"
	"os/exec"
)

func main() {
	cmd := exec.Command("cmd", `C:\path\tools\util\Utility.exe C:\file_Location "select * from TABLE" C:\output_path\output.txt`)
	fmt.Printf("%s\n", cmd.String())
	out, err := cmd.Output()
	fmt.Printf("%s\n", string(out))
	if err != nil {
		fmt.Printf(" Error running decomp %s\n", err)
	}
}

Playground: https://go.dev/play/p/3t0aOxAZRtU

英文:

It appears to be working correctly according to the outputs in your question.

A few suggestions:

  • It might be useful to print the command out as a string before running it, to check it's what you want.
  • You may find backticks useful when you have a string containing backslashes and quotation marks.
  • You have not supplied any format to fmt.Printf, hence the EXTRA in that output.
  • Using println to print the error will not stringify it, so use fmt.Printf for that too.
package main

import (
	"fmt"
	"os/exec"
)

func main() {
	cmd := exec.Command("cmd", `C:\path\tools\util\Utility.exe C:\file_Location "select * from TABLE" C:\output_path\output.txt`)
	fmt.Printf("%s\n", cmd.String())
	out, err := cmd.Output()
	fmt.Printf("%s\n", string(out))
	if err != nil {
		fmt.Printf(" Error running decomp %s\n", err)
	}
}

Playground: https://go.dev/play/p/3t0aOxAZRtU

huangapple
  • 本文由 发表于 2022年6月30日 09:39:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/72809459.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定