Output Format

In the chapter, Human Readable Output, the topic of formatting is discussed. The following program can be examined, compiled, and run to better understand default formatting and using a flag to specify various formats.

Go
// Place this code in a main.go
package main

import (
	"encoding/csv"
	"encoding/json"
	"fmt"
	"os"
	"text/tabwriter"

	"github.com/olekukonko/tablewriter"
	"github.com/spf13/pflag"
)

type Person struct {
	LastName  string `json:"last_name"`
	FirstName string `json:"first_name"`
	Street    string `json:"street_address"`
	City      string `json:"city"`
	State     string `json:"state"`
}

var people = []Person{
	{"Doe", "John", "123 Main St", "Springfield", "IL"},
	{"Smith", "Jane", "456 Oak Ave", "Lincoln", "NE"},
	{"Brown", "Charlie", "789 Pine Rd", "Salem", "OR"},
	{"Johnson", "Mary", "321 Maple Dr", "Austin", "TX"},
	{"Davis", "Robert", "654 Birch Ln", "Tampa", "FL"},
}

func main() {
	var format string
	pflag.StringVar(&format, "format", "text", "Output format: text, table, csv, json, pretty-json")
	pflag.Parse()

	switch format {
	case "text":
		printText(people)
	case "table":
		printTable(people)
	case "csv":
		printCSV(people)
	case "json":
		printJSON(people, false)
	case "pretty-json":
		printJSON(people, true)
	default:
		fmt.Fprintf(os.Stderr, "Unknown format: %s\n", format)
		os.Exit(1)
	}
}

func printText(data []Person) {
	w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
	fmt.Fprintln(w, "Last Name\tFirst Name\tStreet Address\tCity\tState")
	for _, p := range data {
		fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n", p.LastName, p.FirstName, p.Street, p.City, p.State)
	}
	w.Flush()
}

func printTable(data []Person) {
	table := tablewriter.NewWriter(os.Stdout)
	table.SetHeader([]string{"Last Name", "First Name", "Street Address", "City", "State"})
	for _, p := range data {
		table.Append([]string{p.LastName, p.FirstName, p.Street, p.City, p.State})
	}
	table.Render()
}

func printCSV(data []Person) {
	writer := csv.NewWriter(os.Stdout)
	writer.Write([]string{"Last Name", "First Name", "Street Address", "City", "State"})
	for _, p := range data {
		writer.Write([]string{p.LastName, p.FirstName, p.Street, p.City, p.State})
	}
	writer.Flush()
}

func printJSON(data []Person, pretty bool) {
	var output []byte
	var err error
	if pretty {
		output, err = json.MarshalIndent(data, "", "  ")
	} else {
		output, err = json.Marshal(data)
	}
	if err != nil {
		fmt.Fprintf(os.Stderr, "JSON Error: %v\n", err)
		os.Exit(1)
	}
	fmt.Println(string(output))
}
Expand

This program can be exampled by either compiling it or using “go run” as follows:

Bash
# To run compiled
go mod init hformat
go mod tidy
go build -o hformat main.go
./hformat --format=table
./hformat --format=text
./hformat --format=csv
./hformat --format=json
./hformat --format=pretty-json

# Or optionally run with go run
go run main.go --format=table
go run main.go --format=text
# ...etc

* Note: During the creation of this example code, problems were encountered with Tablewriter v1.0.8 . Opening go.mod and replacing v1.0.8 with v1.0.5 and running ‘go mod tidy’ should resolve any issues.

Bash
./hformat
Last Name  First Name  Street Address  City         State
Doe        John        123 Main St     Springfield  IL
Smith      Jane        456 Oak Ave     Lincoln      NE
Brown      Charlie     789 Pine Rd     Salem        OR
Johnson    Mary        321 Maple Dr    Austin       TX
Davis      Robert      654 Birch Ln    Tampa        FL

./hformat --format=table
+-----------+------------+----------------+-------------+-------+
| LAST NAME | FIRST NAME | STREET ADDRESS |    CITY     | STATE |
+-----------+------------+----------------+-------------+-------+
| Doe       | John       | 123 Main St    | Springfield | IL    |
| Smith     | Jane       | 456 Oak Ave    | Lincoln     | NE    |
| Brown     | Charlie    | 789 Pine Rd    | Salem       | OR    |
| Johnson   | Mary       | 321 Maple Dr   | Austin      | TX    |
| Davis     | Robert     | 654 Birch Ln   | Tampa       | FL    |
+-----------+------------+----------------+-------------+-------+

./hformat --format=csv
Last Name,First Name,Street Address,City,State
Doe,John,123 Main St,Springfield,IL
Smith,Jane,456 Oak Ave,Lincoln,NE
Brown,Charlie,789 Pine Rd,Salem,OR
Johnson,Mary,321 Maple Dr,Austin,TX
Davis,Robert,654 Birch Ln,Tampa,FL

./hformat --format=csv
Last Name,First Name,Street Address,City,State
Doe,John,123 Main St,Springfield,IL
Smith,Jane,456 Oak Ave,Lincoln,NE
Brown,Charlie,789 Pine Rd,Salem,OR
Johnson,Mary,321 Maple Dr,Austin,TX
Davis,Robert,654 Birch Ln,Tampa,FL

./hformat --format=json
[{"last_name":"Doe","first_name":"John","street_address":"123 Main St","city":"Springfield","state":"IL"},{"last_name":"Smith","first_name":"Jane","street_address":"456 Oak Ave","city":"Lincoln","state":"NE"},{"last_name":"Brown","first_name":"Charlie","street_address":"789 Pine Rd","city":"Salem","state":"OR"},{"last_name":"Johnson","first_name":"Mary","street_address":"321 Maple Dr","city":"Austin","state":"TX"},{"last_name":"Davis","first_name":"Robert","street_address":"654 Birch Ln","city":"Tampa","state":"FL"}]

./hformat --format=pretty-json
[
  {
    "last_name": "Doe",
    "first_name": "John",
    "street_address": "123 Main St",
    "city": "Springfield",
    "state": "IL"
  },
  {
    "last_name": "Smith",
    "first_name": "Jane",
    "street_address": "456 Oak Ave",
    "city": "Lincoln",
    "state": "NE"
  },

. . . .