Go紅隊開發—CLI框架(一)

CLI開發框架

命令行工具開發,主要是介紹開發用到的包,集成了一個框架,只要學會了基本每個人都能開發安全工具了。

該文章先學flags包,是比較經典的一個包,相比后面要學習的集成框架這個比較自由比較細化點,自定義可能高一些,后續會學到一個Cobra框架,這個很多安全工具都在使用,先學會flags包入門再去理解Cobra框架就比較好學。

flags包

  • 支持段選項長選項
    意思是使用的時候可以用簡寫也可以用完整的參數寫,比如一個工具叫a.exe,用的時候可以a.exe -h 也可以 a.exe -help
  • 支持短選項組合寫,比如:a.exe -p a.exe -s 兩種可以寫在一起:a.exe -ps
  • 一個參數選項可以給多個值(代碼中很容易了解到這一點)
  • flags包默認有-h選項,解析完后–help和-h會返回你的所有參數解釋,不用自己寫help

安裝

go get github.com/jessevdk/go-flags

個人感覺學習這個框架只需要理解兩步:

  • 指定結構體選項
  • 解析結構體

基礎的選項:隨便寫幾個展示即可

  • short:短選項名字
  • long:長選項名字
  • description:顯示你當前選項的一個解釋,-help或者-h的時候顯示
  • tips:
// 參數選項type Option struct {//所有結構體首字母一定要大寫,否則解析不了,但是short或者long的名字就隨便你起V     string   `short:"v" long:"verbose" description:"顯示詳細信息"`Vlist []string `short:"V" long:"verbose-list" description:"顯示詳細信息列表"`I     int      `short:"i" long:"input" description:"int類型測試"`//這里可以給了一個默認值default:"xxx",不給的話在不使用該參數的時候就不用調用那個函數P      func(string)   `short:"p" long:"print" description:"打印"` // default:"myPrint"IntMap map[string]int `short:"m" long:"intmap" description:"intmap"`}

函數這里是要給一個函數傳遞進去使用,具體如下:
是在你實例化你的選項結構體后,將你寫好的函數傳遞進去,或者你寫一個匿名函數也行。

// 打印功能func myPrint(str string) {fmt.Println("打印-p參數值:", str)}
func main() {var opt Option  //定義一個選項opt.P = myPrint //把打印函數賦值給P
}

使用的時候就可以用該參數了,傳遞的參數值就是給到函數變量使用的:

參數傳遞格式

  • -V傳遞:-V 123 -V 456 -V 789
    這樣才能傳遞進map里面,不可以使用逗號或者空格隔開-V 123 456 / -V 123,456都是不行的
  • map的傳遞:-m key1:123 -m key2:456,不建議使用等號=,至少我在windows測試的時候等號不能作為鍵值對分割,只能使用:分割,同時多個map鍵值對也是多個-m才能傳遞添加進去。

剩下幾個類型自己實踐即可,這里就夠用了。


選項設置

選項設置都是直接在結構體選項反引號中直接添加即可,他會解析的。

  • required:在結構體選項中可設置,true的時候,該選項必選,否則報錯,一定要給這個選項一個值
    比如:
    V ?string ? short:"v" long:"verbose" description:"顯示詳細信息" required:true

  • default:表示你這個選項參數有一個默認值,就算你不加他也會以默認值形式作用本次運行
    比如:上面結構體代碼注釋其實有提到
    P ?func(string) ? short:"p" long:"print" description:"打印" default:"myPrint"
    這里就是可以給一個default,表示這個選項的默認值是多少,可以看到我這里給的是一個函數名,這個函數名我也在代碼這種實現了嗎,所以運行的時候肯定是可以找到我這個函數然后執行

分組

這個功能比較好用,至少對我來說以后開發構思中肯定需要用到這個,以及后面講的子命令都是在一些比較完整的工具開發中用的比較多。

先看運行的效果圖

這里和之前的不一樣了,之前的沒有分組的時候就是直接把一些參數打印出來,這里會有參數分組,對比之下會更加直觀一點。

分組的結構體之間的聯系是比較緊密的

  • 先創建好組名(組名也要用結構體)
    結構體內的字段都是你接下來要創建的結構體選項,所以在這里可以先提前想好選項的結構體名字
    比如下面的就是HostScan就是我們接下來要創建的分組的選項參數結構體
    group就是組名,到時候你在help中就能看到分組的組名
    namespace是空間名,在help中顯示為Host.xxx選項,就是類似這樣,主要是告訴你哪個組下的選項,重要是group是組名即可,顯示的時候比較明顯。
// basic 分組type Basic struct {HostOption Host `group:"host" namespace:"Host"`ScanOption Scan `group:"scan" namespace:"Scan"`}
  • 正常創建你在分組的時候想好的那幾個結構體字段,我們給的名字是:HostScanOption,那么接下來就是寫這兩個結構體了
    注意:我在Scan中又開了一個組ScanType,所以還要寫一個ScanType的結構體
    這是help效果圖,應該很容易理解是怎么分組的了,也知道那個namespace是什么了,注意區分Hosthost,host是分組的組名,Host才是那個namespace。
type Host struct {HostName string `short:"N" long:"hostname" description:"主機名"`HostMac  string `short:"M" long:"hostmac" description:"主機mac"`}// 在掃描類型中繼續分組type ScanType struct {HttpType string `short:"T" long:"http" description:"http掃描"`DataBase string `short:"D" long:"database" description:"數據庫掃描"`Other    string `short:"O" long:"other" description:"其他掃描"`}type Scan struct {BasicScan ScanType `group:"scantype" namespace:"scantype"`ScanPort  int      `short:"P" long:"scanport" description:"掃描端口"`ScanIP    string   `short:"I" long:"scanip" description:"掃描ip"`}

子命令

簡單的來說:go version 這個 version就是子命令,不用帶-,直接用的就是子命令,-version 這種帶-的就是選項而不是子命令哈,注意一個符號的區別。


同時記住一點:子命令在flags包中也自動實現了-h /h命令,所以不用編寫幫助信息。
(但是你想要實現不添加-h /h 就實現比如 xx.exe finger 也能給出幫助信息的話就要在接口中實現了,后續會在finger中講明白)

version
  • 先實現version子命令
    繼承了flags.Command的Execute接口就成功實現了子命令了,只剩下注冊到主要的結構體中,也就是之前學到的需要一個結構體注冊選項
    (tips:version的結構體為空,不是拿來切割或者分組,只是一個顯示版本號,后面講finger的時候他才是作為這個分組命令來弄)
//給一個空的,因為version一般都不需要什么其他參數來輔助就可以看到版本了
type ChildCommand struct {}// 繼承了flags.Command即可自動調用func (c *ChildCommand) Execute(args []string) error {fmt.Println("version: 1.0.0")return nil}
  • 注冊子命令到主選項結構體中,這里才是給到flags解析的結構體,注意這里給的鍵不再是short/long,而是command
type VOption struct {Version ChildCommand `command:"version" description:"Version顯示版本信息"`}

運行效果沒問題(源碼稍后放)

finger(測試)

finger來加深理解
一般指紋識別的都是xx.exe finger -u xxx -p xxx
所以我認為用這個例子非常好

  • 依舊是先做好一個子命令,但是這里要給子命令上兩個選項,用來指紋識別的ip和端口
    同時要記得實現接口Execute
// 模擬一下指紋掃描中常見的一個子命令type Finger struct {U string `short:"u" long:"url" description:"url"`P string `short:"p" long:"port" description:"port"`}func (c *Finger) Execute(args []string) error {if c.U == "" || c.P == "" {// 如果沒有提供參數,顯示幫助信息,盡量做的完美一點parser := flags.NewParser(c, flags.Default)parser.WriteHelp(os.Stdout)return nil}return nil}
  • 在主結構體中注冊這個子命令
    我就直接在之前的VOption結構體注冊了
type VOption struct {Version ChildCommand `command:"version" description:"Version顯示版本信息"`// 指紋掃描Finger Finger `command:"finger" description:"Finger指紋掃描"`}

注冊完成就可以用了

  • 加幫助參數
  • 這個沒有加參數 -h 或者 /h等等

以上就是flags包的一些基礎常用的內容了,拿到參數之后就是往后丟給你自己寫的功能函數即可。

所有測試源碼

test1 基礎使用測試、test2分組測試 和 test3子命令 自己看著用就行。

package mainimport ("fmt""log""os""github.com/jessevdk/go-flags")// 參數選項type Option struct {//所有結構體首字母一定要大寫,否則解析不了,但是short或者long的名字就隨便你起V     string   `short:"v" long:"verbose" description:"顯示詳細信息"`Vlist []string `short:"V" long:"verbose-list" description:"顯示詳細信息列表"`I     int      `short:"i" long:"input" description:"int類型測試"`//這里可以給了一個默認值default:"xxx",不給的話在不使用該參數的時候就不用調用那個函數P      func(string)   `short:"p" long:"print" description:"打印"` // default:"myPrint"IntMap map[string]int `short:"m" long:"intmap" description:"intmap"`}// 打印功能func myPrint(str string) {fmt.Println("打印-p參數值:", str)}// basic 分組type Basic struct {HostOption Host `group:"host" namespace:"Host"`ScanOption Scan `group:"scan" namespace:"Scan"`}type Host struct {HostName string `short:"N" long:"hostname" description:"主機名"`HostMac  string `short:"M" long:"hostmac" description:"主機mac"`}// 在掃描類型中繼續分組type ScanType struct {HttpType string `short:"T" long:"http" description:"http掃描"`DataBase string `short:"D" long:"database" description:"數據庫掃描"`Other    string `short:"O" long:"other" description:"其他掃描"`}type Scan struct {BasicScan ScanType `group:"scantype" namespace:"scantype"`ScanPort  int      `short:"P" long:"scanport" description:"掃描端口"`ScanIP    string   `short:"I" long:"scanip" description:"掃描ip"`}type ChildCommand struct {}// 繼承了flags.Command即可自動調用func (c *ChildCommand) Execute(args []string) error {fmt.Println("version: 1.0.0")return nil}// 模擬一下指紋掃描中常見的一個子命令type Finger struct {U string `short:"u" long:"url" description:"url"`P string `short:"p" long:"port" description:"port"`}func (c *Finger) Execute(args []string) error {if c.U == "" || c.P == "" {// 如果沒有提供參數,顯示幫助信息parser := flags.NewParser(c, flags.Default)parser.WriteHelp(os.Stdout)return nil}return nil}type VOption struct {Version ChildCommand `command:"version" description:"Version顯示版本信息"`// 指紋掃描Finger Finger `command:"finger" description:"Finger指紋掃描"`}func test3() {parser := flags.NewParser(&VOption{}, flags.Default)_, err := parser.Parse()if err != nil {if flagsErr, ok := err.(*flags.Error); ok && flagsErr.Type == flags.ErrHelp {return // 幫助信息已打印,直接退出}//如果不是打印的幫助信息報錯的話就直接log就行log.Println("parses failed: ", err)return}}func test1() {var opt Option  //定義一個選項opt.P = myPrint //把打印函數賦值給Pparser := flags.NewParser(&opt, flags.Default)_, err := parser.Parse()if err != nil {if flagsErr, ok := err.(*flags.Error); ok && flagsErr.Type == flags.ErrHelp {return // 幫助信息已打印,直接退出}//如果不是打印的幫助信息報錯的話就直接log就行log.Println("parses failed: ", err)return}fmt.Println("--------------------------")fmt.Println("打印-v參數值:", opt.V)fmt.Println("打印-V 列表所有的參數值:", opt.Vlist)fmt.Println("打印-i參數值:", opt.I)fmt.Println("打印--intmap參數值:", opt.IntMap)}func test2() {var BasicOption Basicparser := flags.NewParser(&BasicOption, flags.Default)_, err := parser.Parse()if err != nil {if flagsErr, ok := err.(*flags.Error); ok && flagsErr.Type == flags.ErrHelp {return // 幫助信息已打印,直接退出}//如果不是打印的幫助信息報錯的話就直接log就行log.Println("parses failed: ", err)return}fmt.Println("--------------------------")}func main() {// test1()// test2()test3()}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/74483.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/74483.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/74483.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

eclipse [jvm memory monitor] SHOW_MEMORY_MONITOR=true

eclipse虛擬機內存監控設置SHOW_MEMORY_MONITORtrue D:\eclipse-jee-oxygen-2-win32-x86_64\workspace\.metadata\.plugins\org.eclipse.core.runtime\.settings org.eclipse.ui.prefs (文件比較多,別找錯了) SHOW_MEMORY_MONITORtrue 重啟 -xms 1024…

量子計算與人工智能的融合:下一代算力革命

1. 引言:算力需求的飛速增長與量子計算的潛力 在信息技術飛速發展的今天,人工智能(AI)已經滲透到我們生活的方方面面,從智能助手到自動駕駛,再到醫療診斷,AI 的應用場景日益廣泛。然而&#xf…

Linux paste命令

目錄 一. 簡介二. 基本語法三. 小案例 一. 簡介 paste 命令用于合并多個文件的行&#xff0c;按列方式輸出&#xff0c;默認以制表符&#xff08;Tab&#xff09;分隔。 ?基本語法 paste [選項] 文件1 文件2 ...二. 基本語法 <()的方式模擬文件流paste命令將2個文件流粘…

uniapp處理流式請求

在uniapp里面處理流式請求相對于web端來說有點麻煩&#xff0c;下面我將講述幾種處理流式請求的方式。 1.websocket WebSocket 是處理實時數據流的最佳選擇之一&#xff0c;UniApp 提供了原生的 WebSocket 支持&#xff1a; <template><view class"container&…

低代碼理解

一、低代碼開發的核心定義 低代碼開發是通過可視化界面和聲明式編程替代傳統手工編碼的軟件開發范式&#xff0c;其核心目標是&#xff1a; 降低技術門檻&#xff1a;允許非專業開發者&#xff08;公民開發者&#xff09;參與應用構建提升開發效率&#xff1a;通過復用預制組…

WHAM 人體3d重建部署筆記 vitpose

目錄 視頻結果: docker安裝說明: conda環境安裝說明: 依賴項: 依賴庫: 安裝 mmpose,mmcv 下載模型權重: 算法原理, demo腳本 報錯inference_top_down_pose_model: 測試命令: 視頻結果: wham_smpl預測結果 git地址: GitHub - yohanshin/WHAM WHAM: Recons…

react 大屏根據屏幕分辨率縮放

記錄&#xff0c;以防忘記 const DataLargeScreen () > {const layoutRef useRef<any>();// ui稿寬度const width useRef(1920).current;// ui稿高度const height useRef(1080).current;const [scaleValue, setScaleValue] useState(1);const useWhichScaleValu…

【網絡】網關

【網絡】網關 網關 是計算機網絡中用于連接兩個不同網絡的設備或服務器&#xff0c;它充當著“翻譯器”和“轉發器”的角色&#xff0c;將數據包從一個網絡傳遞到另一個網絡&#xff0c;并在必要時進行協議轉換和數據重包裝。 主要功能 數據轉發&#xff1a;當本地網絡設備發…

Axure大屏可視化模板:賦能多領域,開啟數據展示新篇章

在當今這個數據爆炸的時代&#xff0c;數據已經成為各行各業的核心資產。然而&#xff0c;如何高效、直觀地展示數據&#xff0c;并將其轉化為有價值的決策依據&#xff0c;成為了許多企業和組織面臨的共同挑戰。Axure大屏可視化模板&#xff0c;作為一款強大的數據展示工具&am…

數據不外傳!通過內網穿透實現綠聯NAS遠程訪問的安全配置方案

文章目錄 前言1. 開啟ssh服務2. ssh連接3. 安裝cpolar內網穿透4. 配置綠聯NAS公網地址 前言 大家好&#xff0c;今天要帶給大家一個超級酷炫的技能——如何讓綠聯NAS秒變‘千里眼’&#xff0c;通過簡單的幾步操作就能輕松實現內網穿透。想象一下&#xff0c;無論你身處何地&a…

面試題精選《劍指Offer》:JVM類加載機制與Spring設計哲學深度剖析-大廠必考

一、JVM類加載核心機制 &#x1f525; 問題5&#xff1a;類從編譯到執行的全鏈路過程 完整生命周期流程圖 關鍵技術拆解 編譯階段 查看字節碼指令&#xff1a;javap -v Robot.class 常量池結構解析&#xff08;CONSTANT_Class_info等&#xff09; 類加載階段 // 手動加載…

WordPress分類目錄綁定二級域名插件

一.子域名訪問形式 1.wordpress 分類目錄 轉換為 子域名 &#xff08;綁定二級域名&#xff09;形式 2.wordpress 頁面轉換為 子域名 &#xff08;綁定二級域名&#xff09; 形式 3.wordpress 作者頁轉換為 子域名 &#xff08;綁定二級域名&#xff09;形式 4.為不同子域名…

Shopify Checkout UI Extensions

結賬界面的UI擴展允許應用開發者構建自定義功能&#xff0c;商家可以在結賬流程的定義點安裝&#xff0c;包括產品信息、運輸、支付、訂單摘要和Shop Pay。 Shopify官方在去年2024年使用結賬擴展取代了checkout.liquid&#xff0c;并將于2025年8月28日徹底停用checkout.liquid…

華為HCIE方向那么多應該如何選擇?

在華為認證體系里&#xff0c;HCIE作為最高等級的認證&#xff0c;是ICT領域專業實力的有力象征。HCIE設置了多個細分方向&#xff0c;這些方向宛如不同的專業賽道&#xff0c;為期望在ICT行業深入發展的人提供了豐富的選擇。今天&#xff0c;咱們就來好好聊聊華為HCIE方向的相…

bootstrap介紹(前端框架)(提供超過40種可復用組件,從導航欄到輪播圖,從卡片到彈窗)bootstrap框架

文章目錄 Bootstrap框架全解析起源與發展核心特性與優勢響應式設計組件豐富度一致性與兼容性 柵格系統深度解析柵格系統工作原理斷點設置與響應式策略 組件系統導航組件表單系統 自定義與擴展SASS變量系統構建系統優化 性能優化策略按需加載減少嵌套層級 實踐案例&#xff1a;電…

FastGPT原理分析-數據集創建第二步:處理任務的執行

概述 文章《FastGPT原理分析-數據集創建第一步》已經分析了數據集創建的第一步&#xff1a;文件上傳和預處理的實現邏輯。本文介紹文件上傳后&#xff0c;數據處理任務的具體實現邏輯。 數據集創建總體實現步驟 從上文可知數據集創建總體上來說分為兩大步驟&#xff1a; &a…

el-select下拉框,搜索時,若是匹配后的數據有且只有一條,則當失去焦點時,默認選中該條數據

1、使用指令 當所需功能只能通過直接的 DOM 操作來實現時&#xff0c;才應該使用自定義指令。可使用方法2封裝成共用函數&#xff0c;但用指令他人復用時比較便捷。 <el-tablev-loading"tableLoading"border:data"tableList"default-expand-allrow-key…

vue中keep-alive組件的使用

keep-alive是vue的內置組件&#xff0c;它的主要作用是對組件進行緩存&#xff0c;避免組件在切換時被重復創建和銷毀&#xff0c;從而提高應用的性能和用戶體驗。它自身不會渲染一個 DOM 元素&#xff0c;也不會出現在父組件鏈中。使用時&#xff0c;只需要將需要緩存的組件包…

Kafka攔截器

文章目錄 1.定義2.生產者攔截器2.1 示例 3.消費者攔截器3.1 示例 1.定義 攔截器主要用于實現clients端的定制化需求&#xff0c;包括消息在生產者發送到 Kafka 或者在消費者接收消息之前進行一些定制化的操作。用于在消息發送和接收的關鍵步驟中進行攔截和處理。可以修改消息&…

進程間通信(匿名管道) ─── linux第22課

目錄 進程間通信 進程間通信目的 進程間通信的發展 進程間通信分類 1. 管道 2. System V IPC 3. POSIX IPC 管道 什么是管道 站在文件描述符角度-深度理解管道 站在內核角度-管道本質 ?編輯 匿名管道 測試匿名管道的讀寫 匿名管道的四大現象&#xff1a; 匿…