[shell腳本]在終端可視化輸出表格數據

v2-de1338b4785a9c68ff2d132dfe46ac03_1440w.jpeg

最終效果

1. 自定義表格樣式

2. 自定義主題顏色

  • 支持三系普通顏色
  • 支持16色彩虹色
  • 支持單顏色

回顧一下shell語法

1. shell傳遞參數

咱們能夠在執行shell腳本時實時傳遞參數從而指定某些具體的參數(在本例中包括表格的樣式、顏色等),腳本中獲取參數的格式爲$n。其中除n0表示執行的文件名外,1表示第一個參數,2表示第二個參數,以此類推。html

  • 每一模式必須以右括號結束
  • 匹配到取值符合某一模式後,執行模式全部命令直到;;
  • 一旦模式匹配則不會執行其餘模式
  • 若是無一模式匹配,可使用*捕獲該值
case 值 in
模式1)
    command1
    command2
    ...
    commandN
    ;;
模式2)
    command1
    command2
    ...
    commandN
    ;;
esac

在實例中,咱們經過第一個參數指定style的值來選擇不一樣的表格形式(具體的表格形式由製表符向量tbs實現)。另外當第一個參數以-h或者--h開頭時,咱們能夠輸出help信息:linux

style="$1"
case $style in
    # 根據第一個參數爲-0或-1或-2來實現不一樣的表格樣式, 即給tbs賦不一樣的值
    -0)  tbs="                ";;
    -1)  tbs="└┴┘├┼┤┌┬┐ ───│││";;
    -2)  tbs="└─┘│┼│┌─┐ ───│││";;
    # 若是第一個參數以%開頭, 意味着咱們能夠外部指定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的基本形式以下:git

awk [-F|-f|-v] 'BEGIN{ 命令 } pattern{ 命令 } END{ 命令 }' file

參數:shell

-F: 指定分隔符
-f: 調用腳本
-v: 使用var=value的格式定義變量

特殊變量:數組

NF: 字段數量
NR: 當前處理的行數
FILENAME: 當前文件名

三個語句塊:bash

BEGIN{ 命令 }:    執行前的命令
pattern{ 命令 }:  處理每一行執行的命令
END{ 命令 }:      執行完全部行後的命令

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]:將文件的每行每列的數據記錄到rows二維數組中
  • rows[NR][0]rows0列存儲前一行和後一行的列數, 用於肯定當行的表格樣式
  • 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"

注意事項

MacLinux不少命令參數不一樣是由於 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 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表示列的左、中、右分隔符
# 自定義顏色:第一個參數表示表格框架的顏色,第二個參數表示表格內容的顏色,第三個參數表示其餘顏色
# 最後能夠傳入16個顏色參數,表示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 參數激活轉移字符, 好比\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
# 當沒有參數時, 設定tbs的默認值
tbs="${tbs:-"+++++++++,---|||"}"

# 顏色
color="$2"
case $color in
    # 1~3可用於設置本身喜歡的自定義樣式, 設置${color}的值便可
    1) ;;
    2) ;;
    3) ;;
    "-"*|"\033"*)
        # 3位數標,詞
        colors="$color"
        ;;
    "%"*) :
        # %號開頭的全自定義
        colors="${color/"%"/}"
        ;;
esac
colors="${colors:-"-4,-8,-4"}"
 
# 主體函數
gawk -F '\t' \
    -v table_s="${tbs}" \
    -v color_s="${colors}" \
    'BEGIN{
    }{
        # ------------------------------------------遍歷每行記錄全局變量------------------------------------------
        # cols_len[NF]: 存儲了每一列的最大長度, 每列最大長度等於該列最長的元素的長度
        # rows[NR][NF]: 將文件的每行每列的數據記錄到rows二維數組中
        # rows[NR][0]: 第0列存儲前一行和後一行的列數, 用於肯定當行的表格樣式
        # 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
            }
        }

        # 先後行狀態
        if (NR == 1) {PrevNF=0}
        # 每行第0列存儲前一行和當前行的列數, 用於肯定當行的表格樣式
        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 # 統計非單列的最大行長度
        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 # 多列的行最大總長度須要包含每列之間的製表符個數(列數 -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++){
            # 解析出前一行和當前行的列數
            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
            }
        }
    }

    # 返回字符串的長度, 支持中文等雙字節字符
    # eg: 內置函數length("中文")返回2, super_length("中文")返回4
    function super_length(txt){
        leng_base = length(txt);
        leng_plus = gsub(/[^\x00-\xff]/, "x", txt) # 返回Ascii碼大於255的字符匹配個數
        return leng_base + leng_plus
    }

    # color_var函數: 解析形如"-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"
    }

    # ------------------------------------------生成繪製內容的函數------------------------------------------
    # 參數: part繪製的位置; txt繪製的文本內容; cell_lens繪製的單元格長度
    # eg: tbs爲已着色的製表符 ╚ ╩ ╝ ╠ ╬ ╣ ╔ ╦ ╗ , ═ ═ ═ ║ ║ ║
    # TODO: cell_len, line, i這三個參數的意義何在, 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 和 對應的空白字符填充數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 # 若是填充字符長度非偶數則須要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腳本加入以下的語句用於可視化輸出表格數據:字體

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/...
[2] https://www.cnblogs.com/gaoch...
[3] https://www.cnblogs.com/nb-bl...
[4] https://www.cnblogs.com/knowl...

相關文章
相關標籤/搜索