欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

使用Go實現(xiàn)在命令行輸出好看的表格

 更新時間:2024年04月12日 10:08:51   作者:Meepoljd  
這篇文章主要介紹了使用Go實現(xiàn)在命令行輸出好看的表格方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

最近在寫一些運維小工具,比如批量進行ping包的工具,實現(xiàn)不困難,反正就是ping,統(tǒng)計,然后輸出,不過我本著自己既是開發(fā)者又是使用者的理念,還是不喜歡輸出特別難看的工具,就像這樣:

所以就去https://pkg.go.dev/瞄了一眼,看看有沒有啥適合的庫能夠把輸出整的好看點的,于是找到了一個庫github.com/jedib0t/go-pretty/v6/table

這是一個在命令行輸出格式化表格的庫,這里記錄一下使用這個庫進行一些格式化輸出的過程。

其實還有一個比較簡單的庫叫做gotable,也能實現(xiàn)基礎的格式化輸出功能,使用起來也方便些,不過功能相對來說就要單一一些,在表格樣式設置上會差一些,沒那么自由

也可以看下https://pkg.go.dev/github.com/liushuochen/gotable#section-readme

接下來開始正式的去在命令行生成好看的滿足需要的表格。

生成Table

首先我們要生成一個Table結構體的實例,可以直接New一個,也可以自己構造:

t := table.Table{}
// 或者
t := table.NewWriter()

NewWriter會返回一個Writer接口

表頭設置

表格首先要設置表頭,以我的應用為例,表頭設置:

header := table.Row{"ID", "IP", "Num", "PacketsRecv", "PacketLoss", "AvgRtt"}

這樣生成了一個表頭行,然后要通過AppendHeader方法在表格中生效:

t.AppendHeader(header)

看看效果,表頭已經(jīng)打印出來了

+----+----+-----+-------------+------------+--------+
| ID | IP | NUM | PACKETSRECV | PACKETLOSS | AVGRTT |
+----+----+-----+-------------+------------+--------+
+----+----+-----+-------------+------------+--------+

插入行

數(shù)據(jù)的插入和表頭的生成類似,要生成一個table.Row,然后調(diào)用AppendRow方法:

func (d *Demo) AppendRow() {
	for i := 1; i <= 5; i++ {
		row := table.Row{i, fmt.Sprintf("10.0.0.%v", i), i + 4, i, i, "AppendRow"}
		d.T.AppendRow(row)
	}
}

效果如下:

+----+----------+-----+-------------+------------+-----------+
| ID | IP       | NUM | PACKETSRECV | PACKETLOSS | AVGRTT    |
+----+----------+-----+-------------+------------+-----------+
|  1 | 10.0.0.1 |   5 |           1 |          1 | AppendRow |
|  2 | 10.0.0.2 |   6 |           2 |          2 | AppendRow |
|  3 | 10.0.0.3 |   7 |           3 |          3 | AppendRow |
|  4 | 10.0.0.4 |   8 |           4 |          4 | AppendRow |
|  5 | 10.0.0.5 |   9 |           5 |          5 | AppendRow |
+----+----------+-----+-------------+------------+-----------+

當然也可以生成table.Row的切片后調(diào)用一次AppendRows方法,效果和上面是一樣的:

func (d *Demo) AppendRows() {
	var rows []table.Row
	for i := 1; i <= 5; i++ {
		rows = append(rows, table.Row{i, fmt.Sprintf("10.0.0.%v", i), i + 4, i, i, "AppendRows"})
	}
	d.T.AppendRows(rows)
}
+----+----------+-----+-------------+------------+------------+
| ID | IP       | NUM | PACKETSRECV | PACKETLOSS | AVGRTT     |
+----+----------+-----+-------------+------------+------------+
|  1 | 10.0.0.1 |   5 |           1 |          1 | AppendRow  |
|  2 | 10.0.0.2 |   6 |           2 |          2 | AppendRow  |
|  3 | 10.0.0.3 |   7 |           3 |          3 | AppendRow  |
|  4 | 10.0.0.4 |   8 |           4 |          4 | AppendRow  |
|  5 | 10.0.0.5 |   9 |           5 |          5 | AppendRow  |
|  1 | 10.0.0.1 |   5 |           1 |          1 | AppendRows |
|  2 | 10.0.0.2 |   6 |           2 |          2 | AppendRows |
|  3 | 10.0.0.3 |   7 |           3 |          3 | AppendRows |
|  4 | 10.0.0.4 |   8 |           4 |          4 | AppendRows |
|  5 | 10.0.0.5 |   9 |           5 |          5 | AppendRows |
+----+----------+-----+-------------+------------+------------+

表格標題

在設置表格實際內(nèi)容時,還可以設置一個表格標題,如下:

func (d *Demo) AddTitle() {
	d.T.SetTitle("This is Easy Table")
}
+-------------------------------------------------------------+
| This is Easy Table                                          |
+----+----------+-----+-------------+------------+------------+
| ID | IP       | NUM | PACKETSRECV | PACKETLOSS | AVGRTT     |
+----+----------+-----+-------------+------------+------------+
|  1 | 10.0.0.1 |   5 |           1 |          1 | AppendRow  |
|  2 | 10.0.0.2 |   6 |           2 |          2 | AppendRow  |
|  1 | 10.0.0.1 |   5 |           1 |          1 | AppendRows |
|  2 | 10.0.0.2 |   6 |           2 |          2 | AppendRows |
+----+----------+-----+-------------+------------+------------+

自動標號

在插入行的時候,我額外輸入了一個ID列,作為標號,其實table提供了相關的方法和接口,只需要調(diào)用SetAutoIndex方法,增加自動的索引列即可:

func (d *Demo) MakeHeader() {
	header := table.Row{"IP", "Num", "PacketsRecv", "PacketLoss", "AvgRtt"}
	d.T.AppendHeader(header)
	d.T.SetAutoIndex(true)
}
+------------------------------------------------------------+
| This is Easy Table                                         |
+---+----------+-----+-------------+------------+------------+
|   | IP       | NUM | PACKETSRECV | PACKETLOSS | AVGRTT     |
+---+----------+-----+-------------+------------+------------+
| 1 | 10.0.0.1 |   5 |           1 |          1 | AppendRow  |
| 2 | 10.0.0.2 |   6 |           2 |          2 | AppendRow  |
| 3 | 10.0.0.1 |   5 |           1 |          1 | AppendRows |
| 4 | 10.0.0.2 |   6 |           2 |          2 | AppendRows |
+---+----------+-----+-------------+------------+------------+

單元格合并

有的時候,相鄰單元格的值一樣我們可能會想要進行合并,這樣更美觀,單元格合并分為列合并和行合并;先定義一下這里的列合并和行合并:

  • 列合并:針對單列,如果單列中的多個相鄰行數(shù)據(jù)一樣,那么就合并為一個大行;
  • 行合并:針對單行,如果單行中的多個相鄰列數(shù)據(jù)一樣,那么久合并為一個大列;

這里我們用到的原始表格如下:

+--------------------------------------------------------------+
| This is Easy Table                                           |
+---+----------+-------+-------------+------------+------------+
|   | IP       |   NUM | PACKETSRECV | PACKETLOSS | AVGRTT     |
+---+----------+-------+-------------+------------+------------+
| 1 | 10.0.0.1 |     5 |           1 |          1 | AppendRow  |
| 2 | 10.0.0.2 |     6 |           2 |          2 | AppendRow  |
| 3 | 10.0.0.1 |     5 |           1 |          1 | AppendRows |
| 4 | 10.0.0.2 |     6 |           2 |          2 | AppendRows |
+---+----------+-------+-------------+------------+------------+
|   | TOTAL    | TOTAL |       TOTAL |      TOTAL | 4          |
+---+----------+-------+-------------+------------+------------+

列合并

我們先進行最后一列AvgRtt的列合并:

func (d *Demo) ColumnMerge() {
	d.T.SetColumnConfigs([]table.ColumnConfig{
		{
			Name: "AvgRtt",
			// Number是指定列的序號
			// Number: 5,
			AutoMerge: true,
			Align:     text.AlignCenter,
		},
	})
}

可以選擇通過列的表頭或者列的序號來選擇具體進行合并的列:

+---+----------+-------+-------------+------------+------------+
|   | IP       |   NUM | PACKETSRECV | PACKETLOSS | AVGRTT     |
+---+----------+-------+-------------+------------+------------+
| 1 | 10.0.0.1 |     5 |           1 |          1 |  AppendRow |
| 2 | 10.0.0.2 |     6 |           2 |          2 |            |
| 3 | 10.0.0.1 |     5 |           1 |          1 | AppendRows |
| 4 | 10.0.0.2 |     6 |           2 |          2 |            |
+---+----------+-------+-------------+------------+------------+
|   | TOTAL    | TOTAL |       TOTAL |      TOTAL | 4          |
+---+----------+-------+-------------+------------+------------+

這樣看表格線條不明顯,感覺不到區(qū)分,那么可以加上一些設置d.T.Style().Options.SeparateRows = true

+---+----------+-------+-------------+------------+------------+
|   | IP       |   NUM | PACKETSRECV | PACKETLOSS | AVGRTT     |
+---+----------+-------+-------------+------------+------------+
| 1 | 10.0.0.1 |     5 |           1 |          1 |  AppendRow |
+---+----------+-------+-------------+------------+            |
| 2 | 10.0.0.2 |     6 |           2 |          2 |            |
+---+----------+-------+-------------+------------+------------+
| 3 | 10.0.0.1 |     5 |           1 |          1 | AppendRows |
+---+----------+-------+-------------+------------+            |
| 4 | 10.0.0.2 |     6 |           2 |          2 |            |
+---+----------+-------+-------------+------------+------------+
|   | TOTAL    | TOTAL |       TOTAL |      TOTAL | 4          |
+---+----------+-------+-------------+------------+------------+

行合并

行合并我們對最后一行的匯總行進行合并,具體做法是在添加匯總行時增加RowConfig參數(shù):

func (d *Demo) AppendFooter() {
	d.T.AppendFooter(table.Row{"Total", "Total", "Total", "Total", count}, table.RowConfig{AutoMerge: true})
}
+---+----------+-------+-------------+------------+------------+
|   | IP       |   NUM | PACKETSRECV | PACKETLOSS | AVGRTT     |
+---+----------+-------+-------------+------------+------------+
| 1 | 10.0.0.1 |     5 |           1 |          1 |  AppendRow |
+---+----------+-------+-------------+------------+            |
| 2 | 10.0.0.2 |     6 |           2 |          2 |            |
+---+----------+-------+-------------+------------+------------+
| 3 | 10.0.0.1 |     5 |           1 |          1 | AppendRows |
+---+----------+-------+-------------+------------+            |
| 4 | 10.0.0.2 |     6 |           2 |          2 |            |
+---+----------+-------+-------------+------------+------------+
|   |                    TOTAL                    | 4          |
+---+---------------------------------------------+------------+

樣式設置

現(xiàn)在整個表格已經(jīng)生成,但我們還需要進行一些美化,這就要對表格的樣式進行設置了;

居中設置

對于居中,無法直接進行全局的設置,必須根據(jù)列進行,如下:

func (d *Demo) SetAlignCenter() {
	column := []string{"IP", "Num", "PacketsRecv", "PacketLoss", "AvgRtt"}
	c := []table.ColumnConfig{}
	// 根據(jù)表格的列數(shù)循環(huán)進行設置,統(tǒng)一居中
	for i := 1; i <= len(column); i++ {
		name := column[i-1]
		if name == "AvgRtt" {
			c = append(c, table.ColumnConfig{
				Name:        "AvgRtt",
				AutoMerge:   true,
				Align:       text.AlignCenter,
				AlignHeader: text.AlignCenter,
				AlignFooter: text.AlignCenter,
			})
			continue
		}
		c = append(c, table.ColumnConfig{
			Name:        column[i],
			Align:       text.AlignCenter,
			AlignHeader: text.AlignCenter,
			AlignFooter: text.AlignCenter,
		})
	}
	d.T.SetColumnConfigs(c)
}

居中效果如下,這樣既能保留列合并又完成了劇中設置:

+---+----------+-------+-------------+------------+------------+
|   | IP       |  NUM  | PACKETSRECV | PACKETLOSS |   AVGRTT   |
+---+----------+-------+-------------+------------+------------+
| 1 | 10.0.0.1 |   5   |      1      |      1     |  AppendRow |
+---+----------+-------+-------------+------------+            |
| 2 | 10.0.0.2 |   6   |      2      |      2     |            |
+---+----------+-------+-------------+------------+------------+
| 3 | 10.0.0.1 |   5   |      1      |      1     | AppendRows |
+---+----------+-------+-------------+------------+            |
| 4 | 10.0.0.2 |   6   |      2      |      2     |            |
+---+----------+-------+-------------+------------+------------+
|   |                    TOTAL                    |      4     |
+---+---------------------------------------------+------------+

數(shù)字自動高亮標紅

在我的應用場景中,ping的ip如果出現(xiàn)了丟包情況,那就要紅色高亮,方便使用者馬上關注到,這種情況下,可以通過Transformer來設置:

func (d *Demo) SetWarnColor() {
	// 字體顏色
	WarnColor := text.Colors{text.BgRed}
	warnTransformer := text.Transformer(func(val interface{}) string {
		if val.(float64) > 0 {
			// 統(tǒng)計丟包服務器總數(shù)
			return WarnColor.Sprintf("%.2f%%", val)
		}
		return fmt.Sprintf("%v%%", val)
	})

	d.T.SetColumnConfigs([]table.ColumnConfig{
		{
			Name:        "PacketLoss",
			AutoMerge:   true,
			Align:       text.AlignCenter,
			AlignHeader: text.AlignCenter,
			AlignFooter: text.AlignCenter,
			Transformer: warnTransformer,
		},
	})
}

實際效果如下:

完整Demo代碼

package main

import (
	"fmt"
	"math/rand"

	"github.com/jedib0t/go-pretty/v6/table"
	"github.com/jedib0t/go-pretty/v6/text"
)

var count = 0

type Demo struct {
	T table.Writer
}

func NewDemo() *Demo {
	return &Demo{
		T: table.NewWriter(),
	}
}

func (d *Demo) MakeHeader() {
	header := table.Row{"IP", "Num", "PacketsRecv", "PacketLoss", "AvgRtt"}
	d.T.AppendHeader(header)
	d.T.SetAutoIndex(true)
	// d.T.SetStyle(table.StyleLight)
	d.T.Style().Options.SeparateRows = true
}

func (d *Demo) AddTitle() {
	d.T.SetTitle("This is Easy Table")
}

func (d *Demo) AppendRow() {
	// rowConfig := table.RowConfig{AutoMerge: true}
	for i := 1; i <= 2; i++ {
		row := table.Row{fmt.Sprintf("10.0.0.%v", i), i + 4, i, rand.Float64() * 100, "AppendRow"}
		count += 1
		d.T.AppendRow(row)
	}
	d.T.AppendRow(table.Row{fmt.Sprintf("10.0.0.%v", 4), 1 + 4, 1, 0.0, "AppendRow"})
}

func (d *Demo) AppendRows() {
	var rows []table.Row
	for i := 1; i <= 2; i++ {
		rows = append(rows, table.Row{fmt.Sprintf("10.0.0.%v", i), i + 4, i, rand.Float64() * 100, "AppendRows"})
		count += 1
	}
	d.T.AppendRows(rows)
}

func (d *Demo) AppendFooter() {
	d.T.AppendFooter(table.Row{"Total", "Total", "Total", "Total", count}, table.RowConfig{AutoMerge: true, AutoMergeAlign: text.AlignCenter})
}

func (d *Demo) ColumnMerge() {
	d.T.SetColumnConfigs([]table.ColumnConfig{
		{
			Name: "AvgRtt",
			// Number是指定列的序號
			// Number: 5,
			AutoMerge: true,
			Align:     text.AlignCenter,
		},
	})
}

func (d *Demo) SetAlignCenter() {
	column := []string{"IP", "Num", "PacketsRecv", "PacketLoss", "AvgRtt"}
	c := []table.ColumnConfig{}

	// 根據(jù)表格的列數(shù)循環(huán)進行設置,統(tǒng)一居中
	for i := 1; i <= len(column); i++ {
		name := column[i-1]
		if name == "AvgRtt" {
			c = append(c, table.ColumnConfig{
				Name:        "AvgRtt",
				AutoMerge:   true,
				Align:       text.AlignCenter,
				AlignHeader: text.AlignCenter,
				AlignFooter: text.AlignCenter,
			})
			continue
		}
		c = append(c, table.ColumnConfig{
			Name:        column[i],
			Align:       text.AlignCenter,
			AlignHeader: text.AlignCenter,
			AlignFooter: text.AlignCenter,
		})
	}
	d.T.SetColumnConfigs(c)
}

func (d *Demo) SetWarnColor() {
	// 字體顏色
	WarnColor := text.Colors{text.BgRed}
	warnTransformer := text.Transformer(func(val interface{}) string {
		if val.(float64) > 0 {
			// 統(tǒng)計丟包服務器總數(shù)
			return WarnColor.Sprintf("%.2f%%", val)
		}
		return fmt.Sprintf("%v%%", val)
	})

	d.T.SetColumnConfigs([]table.ColumnConfig{
		{
			Name:        "PacketLoss",
			AutoMerge:   true,
			Align:       text.AlignCenter,
			AlignHeader: text.AlignCenter,
			AlignFooter: text.AlignCenter,
			Transformer: warnTransformer,
		},
	})
}

func (d *Demo) Print() {
	fmt.Println(d.T.Render())
}

func main() {
	demo := NewDemo()
	demo.MakeHeader()

	// demo.AddTitle()
	demo.AppendRow()
	demo.AppendRows()
	// demo.ColumnMerge()
	demo.AppendFooter()
	// demo.SetAlignCenter()
	demo.SetWarnColor()
	demo.Print()
}

結語

本文介紹了使用第三方庫美化Golang的命令行表格格式化輸出,除了table以外,go-pretty庫中還包含了進度條、列表等美化方法,感興趣可以自己看看官方文檔。

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關文章

  • Systemd集成Golang二進制程序的方法

    Systemd集成Golang二進制程序的方法

    這篇文章主要介紹了Systemd集成Golang二進制程序的方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-10-10
  • golang Iris運行多個應用的實現(xiàn)

    golang Iris運行多個應用的實現(xiàn)

    本文主要介紹了golang Iris運行多個應用的實現(xiàn),在Iris里面,提供了一種方式可以讓我們同時運行多個應用,具有一定的參考價值,感興趣的可以了解一下
    2024-01-01
  • go使用Viper管理配置文件的方法步驟

    go使用Viper管理配置文件的方法步驟

    在項目開發(fā)中,需要把一些配置配置提取出來,方便配置和管理,可以使用Viper工具,Viper 是 Go 應用程序的完整配置解決方案,也支持從環(huán)境變量中讀取,本文給大家介紹了go使用Viper管理配置文件的方法步驟,需要的朋友可以參考下
    2024-07-07
  • golang基礎之Gocurrency并發(fā)

    golang基礎之Gocurrency并發(fā)

    這篇文章主要介紹了golang基礎之Gocurrency并發(fā),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-07-07
  • 一文帶你熟悉Go語言中的分支結構

    一文帶你熟悉Go語言中的分支結構

    這篇文章主要和大家分享一下Go語言中的分支結構(if?-?else-if?-?else、switch),文中的示例代碼講解詳細,對我們學習Go語言有一定的幫助,需要的可以參考一下
    2022-11-11
  • 詳解Golang中strconv庫的用法

    詳解Golang中strconv庫的用法

    strconv包提供了字符串和基本數(shù)據(jù)類型之間的相互轉(zhuǎn)換功能,本文將帶大家深入了解Go語言標準庫中的strconv包,掌握其常用的函數(shù)和用法,希望對大家有所幫助
    2023-06-06
  • Go單體服務開發(fā)最佳實踐總結

    Go單體服務開發(fā)最佳實踐總結

    這篇文章主要介紹了Go單體服務開發(fā)最佳實踐,通過本文詳細跟大家分享一下如何使用?go-zero?快速開發(fā)一個有多個模塊的單體服務,需要的朋友可以參考下
    2022-04-04
  • 深入理解go unsafe用法及注意事項

    深入理解go unsafe用法及注意事項

    go雖然是一種高級語言,但是也還是給開發(fā)者提供了指針的類型unsafe.Pointer,我們可以通過它來直接讀寫變量的內(nèi)存,本文來了解一下?unsafe?里所能提供的關于指針的一些功能,以及使用unsafe.Pointer的一些注意事項
    2024-01-01
  • 一文帶你了解Go語言中方法的調(diào)用

    一文帶你了解Go語言中方法的調(diào)用

    這篇文章主要和大家分享一下Go語言中的方法的調(diào)用,文中的示例代碼講解詳細,對我們學習Go語言有一定的幫助,需要的小伙伴可以參考一下
    2022-12-12
  • GO語言并發(fā)之好用的sync包詳解

    GO語言并發(fā)之好用的sync包詳解

    標準庫中的sync包在我們的日常開發(fā)中用的頗為廣泛,那么大家對sync包的用法知道多少呢,這篇文章就大致講一下sync包和它的使用,感興趣的可以學習一下
    2022-12-12

最新評論