简体   繁体   中英

Golang template to format docker ps output as JSON

I am wondering if it is possible to add the additional formating required to make this output a valid JSON string. To do so I need one character at the start, one on every line except the last, and then one final character.

I currently have this;

$ sudo docker ps --format "{ \"{{.ID}}\" : \"{{.Names}}\"}"
{ "85c4c597bef9" : "addon_a0d7b954_nodered"}
{ "ec3c55af0497" : "addon_a0d7b954_appdaemon"}
{ "63e3081fbe42" : "addon_a0d7b954_logviewer"}

I cannot work out how to use Go to just put out a single character at the start (or even if it is possible).

The problem is that you specify a template, but that template is applied individually on each of your containers, and each template result is rendered in a new line. Your template does not apply to a list of items, but to individual items, and how the result is outputted (how the lines are joined) is not in your control.

But you may achieve what you want with linux commands.

This code demonstrates how your template is executed:

src := "{ \"{{.ID}}\" : \"{{.Names}}\"}"
t := template.Must(template.New("").Parse(src))

ps := []map[string]string{
    {"ID": "85c4c597bef9", "Names": "addon_a0d7b954_nodered"},
    {"ID": "ec3c55af0497", "Names": "addon_a0d7b954_appdaemon"},
    {"ID": "63e3081fbe42", "Names": "addon_a0d7b954_logviewer"},
}

for _, p := range ps {
    if err := t.Execute(os.Stdout, p); err != nil {
        panic(err)
    }
    fmt.Println()
}

This outputs what you have currently (try it on the Go Playground ):

{ "85c4c597bef9" : "addon_a0d7b954_nodered"}
{ "ec3c55af0497" : "addon_a0d7b954_appdaemon"}
{ "63e3081fbe42" : "addon_a0d7b954_logviewer"}

You may use paste to join the lines with a comma like this:

docker ps --format "{ \"{{.ID}}\" : \"{{.Names}}\"}" |paste -sd','

One last thing: prepend a [ and append a ] so it becomes a valid JSON array.

To append something to a command's output, you may use

echo something | (command && cat)

To omit the newline caused by echo , you may use echo -n .

So your "wished" output is a series of appends: ] to the output of docker , and that to the output of the single [ .

So the solution in your case:

echo ] | (docker ps --format "{ \"{{.ID}}\" : \"{{.Names}}\"}" | paste -sd',' && cat) | (echo [ && cat)

This will output:

[
{ "85c4c597bef9" : "addon_a0d7b954_nodered"},{ "ec3c55af0497" : "addon_a0d7b954_appdaemon"},{ "63e3081fbe42" : "addon_a0d7b954_logviewer"}
]

a go-ish solution might look like this, although i am not sure how it will behave with nested objects.

package main

import (
    "encoding/json"
    "fmt"
    "io"
    "log"
    "os"
)

func main() {
    dec := json.NewDecoder(os.Stdin)
    enc := json.NewEncoder(os.Stdout)
    fmt.Println("[")
    d := map[string]interface{}{}
    var i int
    for {
        err := dec.Decode(&d)
        if err != nil {
            if err == io.EOF {
                break
            }
            log.Println(err)
            continue
        }
        if i > 0 {
            fmt.Println(",")
        }
        enc.Encode(d)
        i++
    }
    fmt.Println("]")
}

then, docker ps -a --format "{{json.}}" | jq "{ID, Names}" | go run gow/src/test/jsonl/main.go docker ps -a --format "{{json.}}" | jq "{ID, Names}" | go run gow/src/test/jsonl/main.go

jq helps.

To get the complete json for reference.

docker ps -a --format "{{json .}}" | jq -s

To get only the required columns in the output with tab separated version

docker ps -a --format "{{json .}}" | jq -r -c '[.ID, .State, .Names, .Image] | @tsv'

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM