基于Go語(yǔ)言實(shí)現(xiàn)類似tree命令的小程序
需求
寫一個(gè)簡(jiǎn)版類似于unix tree命令的go語(yǔ)言小程序,如下參數(shù)仿照于tree命令的文檔
該小程序支持的功能如下:
mtree命令默認(rèn)打印以層級(jí)結(jié)構(gòu)打印所有目錄和文件,默認(rèn)以字母排序,支持以下參數(shù)
mtree [-adfLopugshDtr]
列出相關(guān)參數(shù)
-d 僅列出目錄
-L 指定需要打印目錄結(jié)構(gòu)的層數(shù)
-o filename 將結(jié)果輸出到指定文件
文件相關(guān)參數(shù)
-f 打印每個(gè)文件基于當(dāng)前位置的全路徑
-p 打印每個(gè)文件的權(quán)限
-u 打印屬主名稱
-g 打印屬組名稱
-s 打印文件大小
-h 打印文件大小,以更加人性化的方式,會(huì)帶上單位,比如 K、M、G、T
-D 打印文件最后的修改時(shí)間
排序相關(guān)參數(shù)
-t 以最后修改時(shí)間排序輸出
eg:
命令: ./main -u -g -p -D -s -o tmp.txt
tmp.txt文件內(nèi)容如下
. ├── [-rwxr-xr-x root root 2138809 Oct 26 2022] main ├── [-rw-r--r-- root root 2009 Oct 25 2022] tmp.txt └── [drwxr-xr-x root root 4096 Mar 14 2022] workspace ├── [drwxr-xr-x root root 4096 Mar 14 2022] cppProj │ ├── [drwxr-xr-x root root 4096 Mar 14 2022] dockerExecDemo │ ├── [-rw-r--r-- root root 398 Mar 14 2022] exec.cpp │ └── [-rwxr-xr-x root root 16872 Mar 14 2022] set_ns ├── [drwxr-xr-x root root 4096 Mar 16 2022] k8s │ ├── [drwxr-xr-x root root 4096 Mar 17 2022] _05 │ │ ├── [drwxr-xr-x root root 4096 Mar 16 2022] _15 │ │ │ ├── [-rw-r--r-- root root 10 Mar 16 2022] password.txt │ │ │ ├── [-rw-r--r-- root root 405 Mar 16 2022] test_projected_volumn.yml │ │ │ └── [-rw-r--r-- root root 7 Mar 16 2022] username.txt │ │ ├── [drwxr-xr-x root root 4096 Mar 17 2022] _17 │ │ │ └── [-rw-r--r-- root root 340 Mar 16 2022] nginx-deployment.yaml │ │ └── [drwxr-xr-x root root 4096 Mar 17 2022] _18 │ │ ├── [-rw-r--r-- root root 165 Mar 17 2022] srv.yml │ │ └── [-rw-r--r-- root root 346 Mar 17 2022] statefulset.yaml │ ├── [-rwxrwxrwx root root 313 Jan 26 2022] nginx.yaml │ ├── [-rw-r--r-- root root 197 Mar 16 2022] nginx2.yml │ └── [-rw-r--r-- root root 188 Jan 26 2022] nginx_service.yaml └── [drwxr-xr-x root root 4096 Jan 28 2022] podDemo └── [-rw-r--r-- root root 201 Jan 28 2022] nginx.yaml
目的
在個(gè)人mac電腦上,想在終端里面看看目錄結(jié)構(gòu),奈何網(wǎng)絡(luò)條件不好,tree命令沒(méi)有安裝成功,于是動(dòng)手自己寫一個(gè)tree命令的想法油然而生; 同時(shí)又可以熟悉go語(yǔ)言標(biāo)準(zhǔn)庫(kù),提高編碼能力,本程序主要涉及go pkg有:flag、os、fs、path、filepath等
需求分析
針對(duì)上面的輸出顯示,可以把每一行的信息分為
- 文件路徑,文件名稱,文件的相對(duì)路徑, eg:
./workspace/k8s/_05/_15/password.txt
- 文件屬性,權(quán)限,屬主,屬組,大小,時(shí)間 eg:
[root root 10]
- 前綴 eg:
│ │ │ └──
代碼思路:針對(duì)程序當(dāng)前執(zhí)行路徑,遍歷子目錄節(jié)點(diǎn),如果子節(jié)點(diǎn)同樣是目錄的話,則遞歸遍歷;在遞歸遍歷的過(guò)程中,獲取每一個(gè)文件的相關(guān)屬性信息; 同時(shí),對(duì)于程序指定的參數(shù),可以分為屬性類參數(shù)和控制類參數(shù)
- 屬性類參數(shù)有: -u -g -f -p -s -h
- 控制類參數(shù)有: -L -o -d -D -t
對(duì)于屬性類的參數(shù),定義不同的filter,在遍歷的過(guò)程中,每一個(gè)文件節(jié)點(diǎn),都經(jīng)過(guò)過(guò)濾器過(guò)濾,用于填充對(duì)應(yīng)的屬性信息; 對(duì)于控制類的參數(shù),則貫穿于程序過(guò)程中,用于控制不同的行為
這里重點(diǎn)分析下如何輸出前綴的這種層級(jí)關(guān)系的前綴,以下述目錄結(jié)構(gòu)進(jìn)行舉例說(shuō)明:
目錄結(jié)構(gòu)
. └── workspace ├── cppProj │ └── dockerExecDemo ├── k8s │ └── _05 │ ├── _15 │ ├── _17 │ └── _18 └── podDemo
眾所周知,unix文件系統(tǒng)是樹狀結(jié)構(gòu);因此,這里首先就目錄結(jié)構(gòu)抽象成樹結(jié)構(gòu),如下圖,左上角是對(duì)應(yīng)的目錄結(jié)構(gòu),右邊是抽象的樹狀結(jié)構(gòu):
圖豎著看可能還不夠清晰,把該樹結(jié)構(gòu)橫過(guò)來(lái),這樣就可以很好的用該樹結(jié)構(gòu)和目錄的層級(jí)關(guān)系進(jìn)行一一類比了
下面重點(diǎn)分析下如何輸出每一層目錄的前綴,先看└──
和├──
是如何確定的,如上目錄結(jié)構(gòu)所示, _18
節(jié)點(diǎn)屬于目錄_05
的最后一個(gè)節(jié)點(diǎn),因此_18
節(jié)點(diǎn)前面為字符串└──
; 一個(gè)目錄中,除了最后一個(gè)節(jié)點(diǎn)前面的字符串為└──
,其他節(jié)點(diǎn)前面的字符串都是├──
,這里的前綴字符串很容易就可以總結(jié)得出; 但是對(duì)于節(jié)點(diǎn)dockerExecDemo
前面的字符串 │
, 和_18
節(jié)點(diǎn)前面的字符串 │
,該如何打印呢? 通過(guò)分析我們的樹狀結(jié)構(gòu)可以總結(jié)得出,如果一個(gè)節(jié)點(diǎn)的父親沒(méi)有右兄弟,則添加前綴
, 否則添加前綴│
, 每一個(gè)節(jié)點(diǎn)都以這樣的方式追隨到根結(jié)點(diǎn),就可以得出該節(jié)點(diǎn)的前綴關(guān)系;這里已_15
節(jié)點(diǎn)來(lái)完整的舉例說(shuō)明:
_15
節(jié)點(diǎn)屬于第一個(gè)節(jié)點(diǎn),因此首先添加前綴 "├──"; 前綴結(jié)果為: "├──"_15
節(jié)點(diǎn)的父親_05
沒(méi)有右兄弟,因此繼續(xù)添加前綴 " "; 前綴結(jié)果為:" ├──"_05
節(jié)點(diǎn)的父親k8s
有右兄弟,因此繼續(xù)添加前綴 "│ "; 前綴結(jié)果為:"│ ├──"k8s
節(jié)點(diǎn)的父親workspace
沒(méi)有右兄弟,因此繼續(xù)添加前綴 " "; 前綴結(jié)果為:" │ ├──"- 最終
_15
節(jié)點(diǎn)的整體前綴為 " │ ├── "
上面所述的樹結(jié)構(gòu),go語(yǔ)言的定義如下:
type MFileNode struct { Level int ModTime time.Time UserName string Size int64 GroupName string FileName string IsDir bool Children []*MFileNode Parent *MFileNode Left *MFileNode Right *MFileNode Prefix strings.Builder Attr strings.Builder Path strings.Builder }
核心遍歷目錄樹的代碼如下,
// Walk 文件結(jié)構(gòu)遍歷目錄樹,構(gòu)造MTree,同時(shí)每一文件節(jié)點(diǎn),都經(jīng)過(guò)參數(shù)過(guò)濾器進(jìn)行格式化輸出 func Walk(parentMFile *MFileNode, parent, base string, filters *MFilter) error { if parentMFile.Level >= level { return nil } dirEntries, err := os.ReadDir(filepath.Join(parent, base)) if err != nil { return err } if len(dirEntries) == 0 { return nil } parentMFile.Children = make([]*MFileNode, 0, len(dirEntries)) var pre *MFileNode = nil for _, dir := range dirEntries { if onlyDir && !dir.IsDir() { continue } childMFile := &MFileNode{ Level: parentMFile.Level + 1, Children: nil, FileName: dir.Name(), Parent: parentMFile, Left: pre, IsDir: dir.IsDir(), } // 維護(hù)左右兄弟節(jié)點(diǎn)關(guān)系 if pre != nil { pre.Right = childMFile } pre = childMFile info, err := dir.Info() if err != nil { return err } // 參數(shù)過(guò)濾器 filters.Exec(childMFile, info) parentMFile.Children = append(parentMFile.Children, childMFile) if dir.IsDir() { err1 := Walk(childMFile, filepath.Join(parent, base), dir.Name(), filters) if err1 != nil { return err1 } } } return nil }
最終程序?qū)崿F(xiàn)的輸出和 unix tree命令輸出對(duì)比如下圖所示,幾乎完整的實(shí)現(xiàn)了自己的目的:
到此這篇關(guān)于基于Go語(yǔ)言實(shí)現(xiàn)類似tree命令的小程序的文章就介紹到這了,更多相關(guān)Go語(yǔ)言 tree命令內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Golang Http 驗(yàn)證碼示例實(shí)現(xiàn)
這篇文章主要介紹了Golang Http 驗(yàn)證碼示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08GO語(yǔ)言中創(chuàng)建切片的三種實(shí)現(xiàn)方式
這篇文章主要介紹了GO語(yǔ)言中創(chuàng)建切片的三種實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-09-09一文詳解Golang協(xié)程調(diào)度器scheduler
這篇文章主要介紹了一文詳解Golang協(xié)程調(diào)度器scheduler,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的朋友可以參考一下2022-07-07Go 協(xié)程超時(shí)控制的實(shí)現(xiàn)
本文主要介紹了Go 協(xié)程超時(shí)控制的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-08-08