How to correctly pass dynamically built command arguments to exec.Command in Go?

3 weeks ago 34
ARTICLE AD BOX

I am building a CLI tool for docker compose to selectively exclude some containers from running/stopping operations (from a docker-compose.yaml having many containers, user can specify the containers to exclude via an --exclude flag). The tool parses a docker-compose.yaml file and builds a command string dynamically based on which containers should be excluded.

For example: running docker compose up --exclude nginx_test would up all the containers in the docker-compose.yaml excluding a test nginx_test service.

This is how I am parsing the list of containers and excluding them:

docker_containers_string := "" if docker_command != "up" { docker_containers_string = fmt.Sprintf("docker compose %s ", docker_command) } else { docker_containers_string = "docker compose up -d " } for name := range config.Services { fmt.Println("[DEBUG] Found container in the provided docker-compose.yaml: ", name) if slices.Contains(excluded_container_list, name) { fmt.Println("[INFO] excluded_container_list contains this container: ", name) } else { docker_containers_string += fmt.Sprintf("%s ", name) } } fmt.Println("[DEBUG] Executing the command", docker_containers_string) docker_containers_string_splitted := strings.Split(docker_containers_string, " ") fmt.Printf("[DEBUG] Go-syntax representation: %#v\n", docker_containers_string_splitted) cmd := exec.Command(docker_containers_string_splitted[0], docker_containers_string_splitted...) output, err := cmd.CombinedOutput() if err != nil { fmt.Printf("[DEBUG] Error executing command: %v\n", err) fmt.Printf("[DEBUG] The output of the executed command is: %s\n ", string(output)) return } fmt.Println(string(output))

But when the elements of the docker_containers_string_splitted are passed to the exec.Command like this:

cmd := exec.Command(docker_containers_string_splitted[0], docker_containers_string_splitted...)

I get an exception from docker. This is the full traceback:

abhimanyu@Abhimanyus-MacBook-Air dockexclude % ./dockexclude.o up --exclude nginx2 [DEBUG] Up all the containers excluding: [nginx2] [DEBUG] Found container in the provided docker-compose.yaml: nginx [DEBUG] Found container in the provided docker-compose.yaml: nginx2 [INFO] excluded_container_list contains this container: nginx2 [DEBUG] Executing the command docker compose up -d nginx [DEBUG] Go-syntax representation: []string{"docker", "compose", "up", "-d", "nginx", ""} [DEBUG] Error executing command: exit status 125 [DEBUG] The output of the executed command is: unknown shorthand flag: 'd' in -d Usage: docker [OPTIONS] COMMAND [ARG...] Run 'docker --help' for more information

But when I run this:

cmd := exec.Command("docker", "compose", "up", "-d", "nginx")

This is the full traceback:

abhimanyu@Abhimanyus-MacBook-Air dockexclude % ./dockexclude.o up --exclude nginx2 [DEBUG] Up all the containers excluding: [nginx2] [DEBUG] Found container in the provided docker-compose.yaml: nginx [DEBUG] Found container in the provided docker-compose.yaml: nginx2 [INFO] excluded_container_list contains this container: nginx2 [DEBUG] Executing the command docker compose up -d nginx [DEBUG] Go-syntax representation: []string{"docker", "compose", "up", "-d", "nginx", ""} Network dockexclude_default Creating Network dockexclude_default Created Container nginx Creating Container nginx Created Container nginx Starting Container nginx Started

This is my docker-compose.yaml:

services: nginx: container_name: nginx image: nginx ports: - "8081:80" restart: unless-stopped nginx2: container_name: nginx2 image: nginx ports: - "8082:80" restart: unless-stopped

What should be the correct method to pass dynamically built command arguments to exec.Command?

Read Entire Article