最終效果
1. 自定義表格樣式
2. 自定義主題顏色
- 支持三系普通顏色
- 支持16色彩虹色
- 支持單顏色
回顧一下shell語法
1. shell傳遞參數(shù)
我們可以在執(zhí)行shell
腳本時實時傳遞參數(shù)從而指定某些具體的參數(shù)(在本例中包括表格的樣式、顏色等),腳本中獲取參數(shù)的格式為$n
兴泥。其中除n
為0
表示執(zhí)行的文件名外,1
表示第一個參數(shù)榕栏,2
表示第二個參數(shù),以此類推。
- 每一模式必須以右括號結束
- 匹配到取值符合某一模式后,執(zhí)行模式所有命令直到
;;
- 一旦模式匹配則不會執(zhí)行其他模式
- 如果無一模式匹配社裆,可以使用
*
捕獲該值
case 值 in
模式1)
command1
command2
...
commandN
;;
模式2)
command1
command2
...
commandN
;;
esac
在實例中,我們通過第一個參數(shù)指定style
的值來選擇不同的表格形式(具體的表格形式由制表符向量tbs
實現(xiàn))向图。另外當?shù)谝粋€參數(shù)以-h
或者--h
開頭時泳秀,我們可以輸出help
信息:
style="$1"
case $style in
# 根據(jù)第一個參數(shù)為-0或-1或-2來實現(xiàn)不同的表格樣式, 即給tbs賦不同的值
-0) tbs=" ";;
-1) tbs="└┴┘├┼┤┌┬┐ ───│││";;
-2) tbs="└─┘│┼│┌─┐ ───│││";;
# 如果第一個參數(shù)以%開頭, 意味著我們可以外部指定tbs的值
# 把style變量開頭的%去掉賦值給tbs
"%"*) tbs="${style/"%"/}";;
-h*|--h*)
echo '
\t [ --- HELP --- ]
\t command : draw_table.sh [style] [colors] < <file >
\t pipo : echo -e A\\tB\\na\\tb | draw_table.sh [style] [colors]
\t [style] : input 16 characters
\t 1~9 is Num. keypad as table,10 is not used
\t 11~13 are left,middle,right in a row
\t 14~16 are left,middle,right in a column
\t
\t [colors]: input a list,like "-3,-4,-8" sames "-green,-yellow,-white"
\t It set color,table cross ,font ,middle. Or \\033[xxm .
\t And support custom color set every characters of sytle
\t Like "\\033[30m,-red,-yellow,,,,,,,,,,,,," sum 16.
'
exit
;;
esac
# ${var:-DEFAULT}: 如果var沒有被聲明, 或者其值為空, 那么就以$DEFAULT作為其值
tbs="${tbs:-"+++++++++,---|||"}"
2. awk命令
awk
命令:依次對每一行進行處理标沪,但是相比于sed
更擅長取列,個人感覺是類SQL
的文本搜索工具嗜傅。
awk
的基本形式如下:
awk [-F|-f|-v] 'BEGIN{ 命令 } pattern{ 命令 } END{ 命令 }' file
參數(shù):
-F: 指定分隔符
-f: 調用腳本
-v: 使用var=value的格式定義變量
特殊變量:
NF: 字段數(shù)量
NR: 當前處理的行數(shù)
FILENAME: 當前文件名
三個語句塊:
BEGIN{ 命令 }: 執(zhí)行前的命令
pattern{ 命令 }: 處理每一行執(zhí)行的命令
END{ 命令 }: 執(zhí)行完所有行后的命令
3. 自定義輸出顏色
格式如下:
echo -e "\033[字背景顏色;字體顏色m字符串\033[0m"
# 顏色調用始末是固定的:
\033[ ; m …… \033[0m
# 實例:
echo -e "\033[41;36m someword \033[0m"
設計思路
1. 計算和繪制表格相關的全局變量
-
cols_len[NF]
:存儲了每一列的最大長度, 每列最大長度等于該列最長的元素的長度 -
rows[NR][NF]
:將文件的每行每列的數(shù)據(jù)記錄到rows
二維數(shù)組中 -
rows[NR][0]
:rows
第0
列存儲前一行和后一行的列數(shù), 用于確定當行的表格樣式 -
colors[16]
:存儲每個制表符對應的著色方案 -
tbs[16]
:存儲已經著色的制表符金句,其中制表符樣式類似于╚ ╩ ╝ ╠ ╬ ╣ ╔ ╦ ╗ , ═ ═ ═ ║ ║ ║
,前1~9
個為表格骨架的樣式吕嘀,第10
表示著表格元素空格的填充违寞,11~13
分別表示上邊框、中間和下邊框的連接符偶房,第14~16
表示左邊框趁曼、中間和右邊框的連接符
2. 生成表格樣式
由于涉及到單列,因此需要考慮到單列的情況生成如下一些表格樣式變量:
# ------------------------------------------預存所有的表格線, 減少不必要的重復計算------------------------------------------
title_top = line_val("title_top")
title_mid = line_val("title_mid")
title_btm_mid = line_val("title_btm_mid")
title_top_mid = line_val("title_top_mid")
title_btm = line_val("title_btm")
top = line_val("top")
mid = line_val("mid")
btm = line_val("btm")
print "title_top: "title_top"\n"
pring "title_mid: "title_mid"\n"
print "title_btm_mid:"title_btm_mid"\n"
print "title_top_mid:"title_top_mid"\n"
print "title_btm: "title_btm"\n"
print "top: "top"\n"
print "mid: "mid"\n"
print "btm: "btm"\n"
注意事項
Mac
和Linux
很多命令參數(shù)不同是因為Mac
自帶的是BSD
系的命令棕洋,而Linux
用的是GNU
系的命令挡闰。可以在Mac
中使用帶g
前綴的命令解決這一問題掰盘。
在Linux
下直接使用awk
命令即可摄悯,在MAC
下需要下載gawk
命令,否則awk
命令會一直報錯愧捕。
# 安裝GNU工具鏈
brew install coreutils
brew install gawk
運行方法
# 管道方法
$ echo -e "A\tB\na\tb" | sh draw_table.sh
+---+---+
|,A,|,B,|
+---+---+
|,a,|,b,|
+---+---+
# 文件方法
$ echo -e "Your Topic\nA\tB\tC\td\na\tb\th\ts\td\n5\n78\t34" > list.txt
# 第一個參數(shù)控制表格形式
$ sh draw_table.sh < list.txt
+---------------------+
|,,,,,Your Topic,,,, ,|
+----+----+---+---+---+
|,A,,|,B,,|,C,|,d,|,,,|
+----+----+---+---+---+
|,a,,|,b,,|,h,|,s,|,d,|
+----+----+---+---+---+
|,,,,,,,,,,5,,,,,,,,,,|
+----+----+---+---+---+
|,78,|,34,|,,,|,,,|,,,|
+----+----+---+---+---+
# 自定義模式
# 自定義表格邊框:需要用"%"開頭奢驯,前9位表示表格邊框,第10位沒有用處晃财,第11-13 表示行的上叨橱、中、下分隔符断盛,第14-16表示列的左罗洗、中、右分隔符
# 自定義顏色:第一個參數(shù)表示表格框架的顏色钢猛,第二個參數(shù)表示表格內容的顏色伙菜,第三個參數(shù)表示其他顏色
# 最后可以傳入16個顏色參數(shù),表示style中每個字符的顏色
$ sh draw_table.sh '%123456789 abcABC' -red,-blue,-green < list.txt
7aaaaaaaaaaaaaaaaaaaaa9
A Your Topic C
4bbbb8bbbb8bbb8bbb8bbb6
A A B B B C B d B C
4bbbb5bbbb5bbb5bbb5bbb6
A a B b B h B s B d C
4bbbb2bbbb2bbb2bbb2bbb6
A 5 C
4bbbb8bbbb8bbb8bbb8bbb6
A 78 B 34 B B B C
1cccc2cccc2ccc2ccc2ccc3
代碼
#!/bin/bash
#############################################################################
# 作者:banemon
# 郵箱:banemon@
# 修改: tomocat
# Git: https://gitee.com/banemon/linux_sh_script
# 使用說明: https://zhuanlan.zhihu.com/p/144802861
# 命令:sh draw_table.sh < file.txt 或 echo -e "A\tB\na\tb" | sh draw_table.sh
# 幫助:draw_table.sh --help
#############################################################################
# 表格樣式style
style="$1"
case ${style} in
# tbs包含16個符號, 每個符號表示的含義如下:
# 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
# 1 2 3 4 5 6 7 8 9 txt_empt top_row mid_row btm_row left_col mid_col right_col
-0) tbs=" ";;
-1) tbs="└┴┘├┼┤┌┬┐ ───│││";;
-2) tbs="└─┘│┼│┌─┐ ───│││";;
-3) tbs="╚╩╝╠╬╣╔╦╗ ═══║║║";;
-4) tbs="╚═╝║╬║╔═╗ ═══║║║";;
-5) tbs="╙╨╜╟╫╢╓╥╖ ───║║║";;
-6) tbs="╘╧╛╞╪╡╒╤╕ ═══│││";;
-7) tbs="└┴┘├┼┤┌┬┐ ─ ─│ │";;
-8) tbs="└─┘│┼│┌─┐ ─ ─│ │";;
-9) tbs="╚╩╝╠╬╣╔╦╗ ═ ═║ ║";;
-10) tbs="╚═╝║╬║╔═╗ ═ ═║ ║";;
-11) tbs="╙╨╜╟╫╢╓╥╖ ─ ─║ ║";;
-12) tbs="╘╧╛╞╪╡╒╤╕ ═ ═│ │";;
-13) tbs="╘╧╛╞╪╡╒╤╕ ═ ═│ │";;
-14) tbs="╚╩╝╠╬╣╔╦╗ ───│││";;
-15) tbs="+++++++++ ---|||";;
# 自定義表格邊框:需要用"%"開頭命迈,前9位表示表格邊框贩绕,第10位表示填充字符,第11-13 表示行的上壶愤、中淑倾、下分隔符,第14-16表示列的左征椒、中娇哆、右分隔符
# ${string/substring/replacement}: 使用$replacement, 來代替第一個匹配的$substring, 這里是去掉開頭的%, 另外由于%是特殊字符需要加上雙引號(或者反斜杠)
"%"*) tbs="${style/"%"/}";;
# 等價于: \%*) tbs="${style/\%/}";;
-h*|--h*)
# -e 參數(shù)激活轉移字符, 比如\t表示制表符
echo -e '
\t [ --- HELP --- ]
\t command : sh draw_table.sh [style] [colors] < <file>
\t pipo : echo -e A\\tB\\na\\tb | draw_table.sh [style] [colors]
\t [style] : input 16 characters
\t 1~9 is Num. keypad as table,10 is not used
\t 11~13 are up,middle,down in a row
\t 14~16 are left,middle,right in a column
\t
\t -0 :
\t -1 :└┴┘├┼┤┌┬┐ ───│││ -9 :╚╩╝╠╬╣╔╦╗ ═ ═║ ║
\t -2 :└─┘│┼│┌─┐ ───│││ -10 :╚═╝║╬║╔═╗ ═ ═║ ║
\t -3 :╚╩╝╠╬╣╔╦╗ ═══║║║ -11 :╙╨╜╟╫╢╓╥╖ ─ ─║ ║
\t -4 :╚═╝║╬║╔═╗ ═══║║║ -12 :╘╧╛╞╪╡╒╤╕ ═ ═│ │
\t -5 :╙╨╜╟╫╢╓╥╖ ───║║║ -13 :╘╧╛╞╪╡╒╤╕ ═ ═│ │
\t -6 :╘╧╛╞╪╡╒╤╕ ═══│││ -14 :╚╩╝╠╬╣╔╦╗ ───│││
\t -7 :└┴┘├┼┤┌┬┐ ─ ─│ │ -15 :+++++++++ ---|||
\t -8 :└─┘│┼│┌─┐ ─ ─│ │
\t
\t [colors]: input a list,like "-3,-4,-8" sames "-green,-yellow,-white"
\t It set color,table cross ,font ,middle. Or \\033[xxm .
\t And support custom color set every characters of sytle
\t Like "\\033[30m,-red,-yellow,,,,,,,,,,,,," sum 16.
\t
\t -1|-black -5|-blue
\t -2|-red -6|-purple
\t -3|-green -7|-cyan
\t -4|-yellow -8|-white
'
exit
;;
esac
# 當沒有參數(shù)時, 設定tbs的默認值
tbs="${tbs:-"+++++++++,---|||"}"
# 顏色
color="$2"
case $color in
# 1~3可用于設置自己喜歡的自定義樣式, 設置${color}的值即可
1) ;;
2) ;;
3) ;;
"-"*|"\033"*)
# 3位數(shù)標,詞
colors="$color"
;;
"%"*) :
# %號開頭的全自定義
colors="${color/"%"/}"
;;
esac
colors="${colors:-"-4,-8,-4"}"
# 主體函數(shù)
gawk -F '\t' \
-v table_s="${tbs}" \
-v color_s="${colors}" \
'BEGIN{
}{
# ------------------------------------------遍歷每行記錄全局變量------------------------------------------
# cols_len[NF]: 存儲了每一列的最大長度, 每列最大長度等于該列最長的元素的長度
# rows[NR][NF]: 將文件的每行每列的數(shù)據(jù)記錄到rows二維數(shù)組中
# rows[NR][0]: 第0列存儲前一行和后一行的列數(shù), 用于確定當行的表格樣式
# max_single_col_length: 單列行的最大長度
# ps: 由于單列是直接合并整行的單元格, 為圖表美觀(防止cols_len[1]因為某些特長的單列而增長), 單獨記錄單列的最大長度
# 計算單列行的最大長度
if (NF == 1) {
max_single_col_length = max_single_col_length < super_length($1) ? super_length($1) : max_single_col_length
rows[NR][1] = $1
} else { # 非單列行更新每一列的最大長度
for(i=1; i<=NF; i++){
cols_len[i]=cols_len[i] < super_length($i) ? super_length($i) : cols_len[i]
rows[NR][i]=$i
}
}
# 前后行狀態(tài)
if (NR == 1) {PrevNF=0}
# 每行第0列存儲前一行和當前行的列數(shù), 用于確定當行的表格樣式
rows[NR][0] = PrevNF "," NF
PrevNF=NF
}END{
# ------------------------------------------colors變量著色, 生成colors和tbs變量------------------------------------------
# 構建顏色向量: colors, 長度為16
color_sum = split(color_s,clr_id,",")
if (color_sum == 3){ # 簡易自定義模式: 傳入三種顏色
for (i=1; i<=3; i++) {
if (color_s ~ "-") {
clr_id[i] = color_var(clr_id[i])
}
}
# 組建色表: 三種顏色構造colors向量
for (i=1; i<=16; i++) {
if (i < 10) {
colors[i] = clr_id[1]
} else if (i == 10){
colors[i] = clr_id[2]
} else if (i > 10){
colors[i] = clr_id[3]
}
}
} else if (color_sum == 16){ # 全自定義模式: 傳入16種顏色
for (i=1; i<=16; i++){
if(color_s ~ "-"){
clr_id[i] = color_var(clr_id[i])
}
colors[i] = clr_id[i]
}
}
# 設置顏色變量
clr_end = "\033[0m" # shell著色的尾部標識
clr_font = colors[10] # 第10位制表符的顏色, 也就是單元格內填充字符的顏色
# 構建已著色的制表符向量: tbs, 長度16
for (i=1; i<=length(table_s); i++){
if(colors[i]=="")
tbs[i] = substr(table_s, i, 1) # 獲取第i個制表符
else
tbs[i] = colors[i] substr(table_s,i,1) clr_end # 給制表符著色, 例如紅色 `\033[31m制表符\033[0m`
fi
}
# ------------------------------------------如果單列長度大于非單列最大行長度則調整各列長度------------------------------------------
max_line_len = 0 # 統(tǒng)計非單列的最大行長度
for (i=1; i<=length(cols_len); i++) {
max_line_len = max_line_len + cols_len[i] + 2 # 每列需要包含2個空格, 防止內容和制表符緊挨著
}
max_line_len = max_line_len + length(cols_len) - 1 # 多列的行最大總長度需要包含每列之間的制表符個數(shù)(列數(shù) -1)
# 如果單列最大總長度大于多列的行最大總長度時, 需要把超出的部分平均分給每列, 保證圖表美觀
diff_length = max_single_col_length + 2 - max_line_len
if (diff_length > 0) {
for(j=1; j<=diff_length; j++){
i = (j - 1) % length(cols_len) + 1
cols_len[i] = cols_len[i] + 1
}
# 由于增加了每列長度, 故需要調整單列最大行長度
# max_line_len = max_single_col_length + 2
} else { # 如果單列最大總長度小于行的最大總長度, 那么單列長度要和最大行總長度保持一致
max_single_col_length = max_line_len - 2
}
# ------------------------------------------預存所有的表格線, 減少不必要的重復計算------------------------------------------
title_top = line_val("title_top")
title_mid = line_val("title_mid")
title_btm_mid = line_val("title_btm_mid")
title_top_mid = line_val("title_top_mid")
title_btm = line_val("title_btm")
top = line_val("top")
mid = line_val("mid")
btm = line_val("btm")
# debug
# print "title_top: " title_top "\n"
# pring "title_mid: " title_mid "\n"
# print "title_btm_mid:" title_btm_mid "\n"
# print "title_top_mid:" title_top_mid" \n"
# print "title_btm: " title_btm" \n"
# print "top: " top" \n"
# print "mid: " mid" \n"
# print "btm: " btm" \n"
# ------------------------------------------繪制表格------------------------------------------
row_num = length(rows)
for(i=1; i<=row_num; i++){
# 解析出前一行和當前行的列數(shù)
split(rows[i][0], col_num_list, ",")
prev_col_num = int(col_num_list[1])
curr_col_num = int(col_num_list[2])
# 繪制首行
if (i==1 && prev_col_num == 0) {
if (curr_col_num <= 1) {
# 單列
print title_top
print line_val("title_txt", rows[i][1], max_single_col_length)
} else if (curr_col_num >= 2) {
# 多列
print top
print line_val("txt", rows[i])
}
} else if (prev_col_num <=1 ) {
# 前一行為單列時
if (curr_col_num <=1 ) {
# 單列
print title_mid
print line_val("title_txt", rows[i][1], max_single_col_length)
} else if (curr_col_num >= 2) {
# 多列
print title_btm_mid
print line_val("txt", rows[i])
}
}else if (prev_col_num >= 2) {
# 前一行為多列時
if (curr_col_num <= 1) {
# 單列
print title_top_mid
print line_val("title_txt", rows[i][1], max_single_col_length)
} else if (curr_col_num >= 2) {
# 多列
print mid
print line_val("txt", rows[i])
}
}
# 表格底邊
if (i == row_num && curr_col_num <= 1) {
# 尾行單列時
print title_btm
} else if (i == row_num && curr_col_num >= 2){
# 尾行多列時
print btm
}
}
}
# 返回字符串的長度, 支持中文等雙字節(jié)字符
# eg: 內置函數(shù)length("中文")返回2, super_length("中文")返回4
function super_length(txt){
leng_base = length(txt);
leng_plus = gsub(/[^\x00-\xff]/, "x", txt) # 返回Ascii碼大于255的字符匹配個數(shù)
return leng_base + leng_plus
}
# color_var函數(shù): 解析形如"-n"開頭的顏色配置
function color_var(color){
if(color=="-1" ||color=="-black"){
n=30
}else if(color=="-2" || color=="-red"){
n=31
}else if(color=="-3" || color=="-green"){
n=32
}else if(color=="-4" || color=="-yellow"){
n=33
}else if(color=="-5" || color=="-blue"){
n=34
}else if(color=="-6" || color=="-purple"){
n=35
}else if(color=="-7" || color=="-cyan"){
n=36
}else if(color=="-8" || color=="-white"){
n=37
}else if(color=="-0" || color=="-reset"){
n=0
}else{
n=0
}
return "\033[" n "m"
}
# ------------------------------------------生成繪制內容的函數(shù)------------------------------------------
# 參數(shù): part繪制的位置; txt繪制的文本內容; cell_lens繪制的單元格長度
# eg: tbs為已著色的制表符 ╚ ╩ ╝ ╠ ╬ ╣ ╔ ╦ ╗ , ═ ═ ═ ║ ║ ║
# TODO: cell_len, line, i這三個參數(shù)的意義何在, awk的特殊用法?
function line_val(part, txt, cell_lens, cell_len, line, i) {
# 更新本次行標
if (part=="top") {
tbs_l=tbs[7]
tbs_m=tbs[8]
tbs_r=tbs[9]
tbs_b=tbs[11]
} else if (part=="mid") {
tbs_l=tbs[4]
tbs_m=tbs[5]
tbs_r=tbs[6]
tbs_b=tbs[12]
} else if (part=="txt") { # tbs[10]為填充字符, 用于填充單元格內的空格
tbs_l=tbs[14] tbs[10]
tbs_m=tbs[10] tbs[15] tbs[10]
tbs_r=tbs[10] tbs[16]
tbs_b=tbs[10]
} else if (part=="btm"){
tbs_l=tbs[1]
tbs_m=tbs[2]
tbs_r=tbs[3]
tbs_b=tbs[13]
} else if (part=="title_top"){
tbs_l=tbs[7]
tbs_m=tbs[11]
tbs_r=tbs[9]
tbs_b=tbs[11]
} else if (part=="title_top_mid"){
tbs_l=tbs[4]
tbs_m=tbs[2]
tbs_r=tbs[6]
tbs_b=tbs[12]
} else if (part=="title_mid"){
tbs_l=tbs[4]
tbs_m=tbs[12]
tbs_r=tbs[6]
tbs_b=tbs[12]
} else if (part=="title_txt"){
tbs_l=tbs[14] tbs[10]
tbs_m=tbs[10] tbs[15] tbs[10]
tbs_r=tbs[10] tbs[16]
tbs_b=tbs[10]
} else if (part=="title_btm"){
tbs_l=tbs[1]
tbs_m=tbs[13]
tbs_r=tbs[3]
tbs_b=tbs[13]
} else if (part=="title_btm_mid"){
tbs_l=tbs[4]
tbs_m=tbs[8]
tbs_r=tbs[6]
tbs_b=tbs[12]
}
# title行只有一列文本
if (part == "title_txt") {
cols_count=1
} else {
cols_count = length(cols_len)
}
# 遍歷該行所有列, 構造改行的內容
line_content = ""
# 對于一行內的每一個單元格, 計算單元格文本cell_txt 和 對應的空白字符填充數(shù)fill_len
for (i=1; i<=cols_count; i++) {
if (part == "txt") {
# 多列左對齊
cell_txt = txt[i]
fill_len = cols_len[i] - super_length(cell_txt)
}else if(part=="title_txt"){
# 單列居中
cell_txt = txt
fill_len = (cell_lens - super_length(cell_txt)) / 2
is_need_fix = (cell_lens - super_length(cell_txt)) % 2 # 如果填充字符長度非偶數(shù)則需要fix
} else {
cell_txt = ""
fill_len = cols_len[i] + 2
}
# 單元格文本著色
cell_txt = clr_font cell_txt clr_end
# 單元格內空白補全
if (part == "title_txt") {
# 單列居中, 在單元格文本兩側補全空格字符
for (cell_len=1; cell_len <= fill_len; cell_len++) {
cell_txt = tbs_b cell_txt tbs_b
}
# 單列非偶長度補全
if (is_need_fix == 1) {
cell_txt = cell_txt " "
}
}else{
# 多列左對齊
for (cell_len=1; cell_len<=fill_len; cell_len++) {
cell_txt = cell_txt tbs_b
}
}
# 首格
if (i == 1) {
line_content = line_content cell_txt
} else {
# 中格
line_content = line_content tbs_m cell_txt
}
# 尾格
if ( i == cols_count ) {
line_content = line_content tbs_r
}
}
# 返回行: tbs_l表示最左側的表格樣式, line_content表示該行的內容
return tbs_l line_content
}
'
使用實例
實際中經常碰到日志采集分析的問題,可以在shell
腳本加入如下的語句用于可視化輸出表格數(shù)據(jù):
echo -e "Module Log Analyse
Function Name\tCount
Function1\t20
Function2\t1113
Function3\t257
Function4\t113" | sh draw_table.sh -4 -red,-white,-blue
Reference
[1] https://www.runoob.com/linux/linux-shell-process-control.html
[2] https://www.cnblogs.com/gaochsh/p/6901809.html
[3] https://www.cnblogs.com/nb-blog/p/5780424.html
[4] https://www.cnblogs.com/knowlegefield/p/7774693.html
AD
我的博客即將同步至騰訊云+社區(qū),邀請大家一同入駐:https://cloud.tencent.com/developer/support-plan?invite_code=wcmvy196t4o