Golang exec.Command and python weird interaction

Hey everyone, hope you are having a great day.

Recently, I have had one of the most bizarre interactions between software that I have seen recently, and I am pretty sure I haven’t done anything wrong (went over this multiple times, asked peers to review and see perhaps I missed something), so I thought I would share this in case anyone stumbles across this, or perhaps has a better explanation for it!

In a nutshell, when calling from Go using exec.Command to a python script that uses the argparse library to parse the received arguments, for some reason, the arguments have been received correctly by looking at the sys.argv variable, but when parsed using the parse_arguments function of argparse, the arguments have been misinterpreted, specifically when using the aliased shorthanded flag, it added a space that wasn’t there.

# Golang code
# main.go
package main

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

func main() {
  cmd := exec.Command("./test.py", "-p /some/path")
  fmt.Println(cmd.Args)
  output, err := cmd.CombinedOutput()
  if err != nil {
    log.Fatalf("Error: %s", err)
  }

  fmt.Printf("\nOutput received: \n %s", output)
}

And then the python code:

#!/usr/bin/python3
# Python code
# test.py
import argparse

parser = argparse.ArgumentParser()
parser.add_argument('--path', '-p', dest='path')

args = parser.parse_args()
print(f"The path:>>{args.path}<<")

And as you will see, when running the program using Golang, it will add a space to the argument, but when executing it from the terminal, it won’t.

Sidenote: make sure you make test.py executable because we treat it like one, using chmod +x test.py

Running from go:

$ go run main.go

Running from terminal:

$ ./test.py -p /some/path

That’s not strange, but how it works.

Your go is equivalent to running ./test.py "-p /some/path" in bash.you want to pass them separately in go

Apparently, I figured it out right after posting it. I still believe this post deserves its place here, because if I was baffled by this, I believe someone else will be.

Anyhow, the issue here is that when sending arguments to a program using the terminal, it separates the arguments by space, and so the following statement:
./test.py -p /some/path is actually split into these:
./test.py
-p
/some/path

Therefore, when using the exec.Command, we need to send them using the same strategy. What I did, is send them like so:
./test.py
-p /some/path
Which implicates that the -p and /somepath are one argument. To fix the above issue, just treat every word you would separate by space in the terminal as a different argument, as follows:

# Instead of:
cmd := exec.Command("./test.py", "-p /some/path")
# Do:
cmd := exec.Command("./test.py", "-p", "/some/path")
1 Like

You beat me to it! :slight_smile:

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.