Running a command from a string with parameters in go

  • A+
Category:Languages

I am trying to run a command with go. The command is in a string.

package main  import (     "log"     "os"     "os/exec"     "strings"      "github.com/davecgh/go-spew/spew" )  func main() {     commandToRun := `echo $HOME`      log.Printf("Running %s/n", commandToRun)      args := strings.Fields(commandToRun)     spew.Dump(args[1:len(args)])     command := exec.Command(args[0], args[1:len(args)]...)     command.Stdout = os.Stdout     command.Stdin = os.Stdin     command.Stderr = os.Stderr     err := command.Run()      if err != nil {         log.Printf("Command finished with error: %v", err)     } } 

The output is:

2018/11/14 09:41:22 Running echo $HOME ([]string) (len=1 cap=1) {  (string) (len=5) "$HOME" } $HOME 

What I'd like to have is:

2018/11/14 09:41:22 Running echo $HOME ([]string) (len=1 cap=1) {  (string) (len=5) "$HOME" } /home/whatever 

Looks like go is sanitizing the string somehow. So the $HOME is not expanded. Is there any way of running the string exactly as if it was typed into the shell?

This is the important part. Ideally I'd like to turn from string to type in the current shell.

EDIT: The example below solve the simplest scenario but doesn't cover the "running the string exactly as if it was typed into the shell" part.

If I switch to expandenv:

commandToRun := os.ExpandEnv(`echo "$HOME"`) 

I get:

2018/11/14 11:45:44 Running echo "/Users/rafael" ([]string) (len=1 cap=1) {  (string) (len=15) "/"/home/whatever/"" } "/home/whatever" 

What I'd get in the shell is:

$ > echo "$HOME" /home/whatever 

without the quotes.

This is close to what I want but not exactly it.

 


$HOME (and all other env variables) are expanded by the shell. You're not executing a shell, so they don't get expanded.

You need to look up the env variable directly in go, with something like:

command := exec.Command("echo", os.Getenv("HOME")) 

or this:

commandToRun := os.ExpandEnv("echo $HOME") command := exec.Command(strings.Fields(commandToRun)...) 

Note that this last approach won't work if $HOME expands to a string containing whitespace, so the os.Getenv method is generally safer/preferred for this use case.

Comment

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