Creating a CLI Application in Go: A Comprehensive Guide

Table of Contents

  1. Introduction
  2. Prerequisites
  3. Setting Up
  4. Creating the CLI Application
  5. Adding Command-Line Flags
  6. Processing User Input
  7. Executing Commands
  8. Finalizing the Application
  9. Conclusion

Introduction

In this tutorial, we will learn how to create a command-line interface (CLI) application using Go programming language. The CLI application will allow users to execute various commands and perform tasks based on user input. By the end of this tutorial, you will be able to create your own CLI applications using Go.

Prerequisites

Before you begin, you should have a basic understanding of Go programming language and have Go installed on your system. If you haven’t installed Go yet, you can download and install it from the official website: https://golang.org/dl/.

Setting Up

To get started, create a new directory for your CLI application and navigate to that directory using the command line. Once you are in the directory, open a text editor of your choice to write your Go code.

Create a new file named main.go and open it in the text editor.

Creating the CLI Application

Let’s start by creating the basic structure of our CLI application. In the main.go file, add the following code:

package main

import (
    "fmt"
    "os"
)

func main() {
    fmt.Println("Welcome to MyCLIApp!")
}

In this code, we import the fmt and os packages, which are required for basic input/output operations and handling command-line arguments.

The main function is the entry point of our application. It simply prints a welcome message to the console.

To run the application, open the terminal, navigate to the directory containing main.go, and run the following command:

go run main.go

You should see the welcome message printed in the console.

Adding Command-Line Flags

Now, let’s add some command-line flags to our CLI application. Command-line flags allow users to specify options and parameters when executing the application.

Update the code in main.go as follows:

package main

import (
    "flag"
    "fmt"
    "os"
)

func main() {
    name := flag.String("name", "Guest", "The name of the user")
    age := flag.Int("age", 0, "The age of the user")
    flag.Parse()

    fmt.Printf("Welcome, %s! You are %d years old.\n", *name, *age)
}

In this code, we import the flag package, which provides a convenient way to define and handle command-line flags.

We define two flags: name and age. The String and Int functions return pointers to string and int types, respectively, which hold the values of the corresponding command-line flags.

The flag.Parse() function is used to parse the command-line arguments and assign their values to the defined flags.

To run the updated application, open the terminal and run the following command:

go run main.go -name John -age 25

You should see the personalized welcome message printed in the console, based on the provided name and age values.

Processing User Input

Next, let’s enhance our CLI application to process user input and execute commands accordingly.

Update the code in main.go as follows:

package main

import (
    "bufio"
    "fmt"
    "os"
    "strings"
)

func main() {
    reader := bufio.NewReader(os.Stdin)
    for {
        fmt.Print("Enter command: ")
        input, _ := reader.ReadString('\n')
        input = strings.TrimSuffix(input, "\n")

        if input == "exit" {
            fmt.Println("Goodbye!")
            break
        }

        // Add code to handle commands here
    }
}

In this code, we import the bufio package to read user input from the terminal.

We create a reader object using bufio.NewReader(os.Stdin) to read input from the standard input (terminal).

Inside the for loop, we prompt the user to enter a command and read the input using reader.ReadString('\n'). We remove the trailing newline character using strings.TrimSuffix(input, "\n").

If the user enters “exit”, the application prints a goodbye message and exits the loop.

Now we need to add code to handle different commands. Let’s add support for a hello command.

Update the code in main.go as follows:

package main

import (
    "bufio"
    "fmt"
    "os"
    "strings"
)

func main() {
    reader := bufio.NewReader(os.Stdin)
    for {
        fmt.Print("Enter command: ")
        input, _ := reader.ReadString('\n')
        input = strings.TrimSuffix(input, "\n")

        if input == "exit" {
            fmt.Println("Goodbye!")
            break
        }

        if input == "hello" {
            fmt.Println("Hello, world!")
        }
    }
}

Now, when the user enters “hello” as a command, the application will print “Hello, world!” as the output.

Executing Commands

Let’s extend the functionality of our CLI application by allowing the execution of custom commands.

Update the code in main.go as follows:

package main

import (
    "bufio"
    "fmt"
    "os"
    "os/exec"
    "strings"
)

func main() {
    reader := bufio.NewReader(os.Stdin)
    for {
        fmt.Print("Enter command: ")
        input, _ := reader.ReadString('\n')
        input = strings.TrimSuffix(input, "\n")

        if input == "exit" {
            fmt.Println("Goodbye!")
            break
        }

        parts := strings.Fields(input)
        command := parts[0]
        args := parts[1:len(parts)]

        cmd := exec.Command(command, args...)
        cmd.Stdout = os.Stdout
        cmd.Stderr = os.Stderr
        err := cmd.Run()
        if err != nil {
            fmt.Println("Error executing command:", err)
        }
    }
}

In this code, we import the os/exec package to execute external commands.

When the user enters a command, we split it into multiple parts using strings.Fields(input). The first part becomes the command to execute, and the rest become its arguments.

We create a cmd object using exec.Command(command, args...) and set its Stdout and Stderr to the standard output and standard error, respectively. We also handle any errors that occur during the command execution.

Now, our CLI application can execute system commands entered by the user.

Finalizing the Application

To finalize our CLI application, let’s add additional error handling and improve the user interface.

Update the code in main.go as follows:

package main

import (
    "bufio"
    "fmt"
    "os"
    "os/exec"
    "strings"
)

func main() {
    reader := bufio.NewReader(os.Stdin)
    for {
        fmt.Print("Enter command: ")
        input, _ := reader.ReadString('\n')
        input = strings.TrimSuffix(input, "\n")

        if input == "exit" {
            fmt.Println("Goodbye!")
            break
        }

        parts := strings.Fields(input)
        if len(parts) == 0 {
            continue
        }

        command := parts[0]
        args := parts[1:]

        cmd := exec.Command(command, args...)
        cmd.Stdout = os.Stdout
        cmd.Stderr = os.Stderr
        err := cmd.Run()
        if err != nil {
            fmt.Println("Error executing command:", err)
        }
    }
}

In this code, we add additional error handling by checking the length of the parts array before executing a command. If the user enters an empty command, we skip it using continue.

Now, our CLI application is more robust and user-friendly.

Conclusion

Congratulations! You have learned how to create a CLI application in Go. You started with a basic structure and gradually added functionality such as command-line flags, user input processing, and command execution. You are now equipped to create your own CLI applications using Go and explore more advanced features and libraries.

In this tutorial, we covered the following categories:

  • Syntax and Basics
  • Functions and Packages

Feel free to experiment with the code and explore the Go documentation to expand your knowledge and create more sophisticated CLI applications.