Ben Chuanlong Du's Blog

It is never too late to learn.

Run System Command in Go

Things on this page are fragmentary and immature notes/thoughts of the author. Please read with your own judgement!

Comments

  1. exec.Command takes a shell command and optional arguments passed to the shell command, e.g., exec.Command("ls", "-lha"). It does not work if you pass a shell command with arguments as a single string to exec.Command, e.g., exec.Command("ls -lha") does not work. There are a few situations where it is appealing to pass a shell command with arguments as a single string to exec.Command.

    • You want to run a compound shell command which leverages pipe (|), &&, ||, etc. Even though you can break such a compound shell command into multiple smaller ones and then run each of them using exec.Command, it can be much more convenient to be able to run a compound shell command directly.
    • Use provides a shell command as a single string for your Golang application to run.
      It might not be trivia to parse a string shell command to its array representation.

      Fortunately, there is one way around this problem. You can explicitly call a shell and pass a command (with arguments) to it, e.g., exec.Command("bash", "-c", "ls -lha").

In [6]:
import "fmt"
import "reflect"
import "os"
import "os/exec"
In [2]:
cmd := exec.Command("ls")
In [3]:
cmd
Out[3]:
/usr/bin/ls
In [26]:
reflect.TypeOf(cmd)
Out[26]:
*exec.Cmd
In [27]:
err := cmd.Run()
err
In [28]:
err == nil
Out[28]:
true
In [29]:
out, err := exec.Command("ls").Output()
In [32]:
err == nil
Out[32]:
true
In [30]:
out
Out[30]:
[116 105 112 115 45 111 110 45 103 111 108 97 110 103 46 105 112 121 110 98 10]
In [33]:
string(out[:])
Out[33]:
tips-on-golang.ipynb

Compound Command

In [4]:
exec.Command("ls", "|", "wc", "-l").Output()
Out[4]:
[] exit status 2
In [5]:
exec.Command("bash", "-c", "ls -lha")
Out[5]:
/usr/bin/bash -c ls -lha

Environment Variables

In [5]:
cmd = exec.Command("bash", "-c", "ls -lha")
Out[5]:
/usr/bin/bash -c ls -lha
In [7]:
os.Environ()
Out[7]:
[PATH=/usr/local/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/lib/jvm/java-8-openjdk-amd64/bin LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64 M2_HOME=/usr/share/maven JUPYTERHUB_API_TOKEN=f53fdbc5460c44ffb1bf695cca4caa28 JPY_API_TOKEN=f53fdbc5460c44ffb1bf695cca4caa28 JUPYTERHUB_ADMIN_ACCESS=1 JUPYTERHUB_CLIENT_ID=jupyterhub-user-dclong JUPYTERHUB_HOST= JUPYTERHUB_OAUTH_CALLBACK_URL=/user/dclong/oauth_callback JUPYTERHUB_OAUTH_SCOPES=["access:servers!server=dclong/", "access:servers!user=dclong"] JUPYTERHUB_USER=dclong JUPYTERHUB_SERVER_NAME= JUPYTERHUB_API_URL=http://127.0.0.1:8081/hub/api JUPYTERHUB_ACTIVITY_URL=http://127.0.0.1:8081/hub/api/users/dclong/activity JUPYTERHUB_BASE_URL=/ JUPYTERHUB_SERVICE_PREFIX=/user/dclong/ JUPYTERHUB_SERVICE_URL=http://127.0.0.1:34125/user/dclong/ JUPYTERHUB_ROOT_DIR=/workdir JUPYTERHUB_DEFAULT_URL=/lab USER=dclong HOME=/home/dclong SHELL=/bin/bash JUPYTERHUB_SINGLEUSER_APP=jupyter_server.serverapp.ServerApp GIT_PYTHON_REFRESH=quiet PYTHONUNBUFFERED=1 JPY_PARENT_PID=70]
In [ ]:
cmd.Env = append(os.Environ(),
		"FOO=duplicate_value", // ignored
		"FOO=actual_value",    // this value is used
	)

Get Detailed Error Message

Please refer to How to debug "exit status 1" error when running exec.Command in Golang for detailed discussions.

In [8]:
os.Getenv("PATH")
Out[8]:
/usr/local/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/lib/jvm/java-8-openjdk-amd64/bin
In [10]:
os.LookupEnv("PATH")
Out[10]:
/usr/local/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/lib/jvm/java-8-openjdk-amd64/bintrue
In [ ]:
 

Comments