<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
一次偶然的想法,想知道為什麼在終端輸入那些命令列後,就執行了對應的操作,這轉化為程式碼,應該怎麼實現呢?
既然有了問題,那我們就來解決問題吧!
首先我認為想做命令列操作,那就得先”認識“命令列(當然這裡指你的程式碼認識),所以我認位有兩個步驟:
話不多說開幹!
正好在學習 Golang
,那就用它的試試吧!
首先,我們先來學習以下幾個 API
// String defines a string flag with specified name, default value, and usage string. // The return value is the address of an int variable that stores the value of the flag. // String 定義了一個字串標誌,具有指定的名稱、預設值和用法字串。返回值是儲存標誌值的字串變數的地址。 func String(name string, value string, usage string) *string { return CommandLine.String(name, value, usage) }
也就是說,使用-name value
的命令引數,usage
是對這個引數的說明,返回值是這個 value 的指標
,也就是使用者輸入在 -name
後的 value
。
// Int defines an int flag with specified name, default value, and usage string. // The return value is the address of an int variable that stores the value of the flag. // Int 定義了一個具有指定名稱、預設值和用法字串的 int 標誌。返回值是儲存標誌值的 int 變數的地址。 func Int(name string, value int, usage string) *int { return CommandLine.Int(name, value, usage) }
使用方式和 String()
一樣,只是型別的區別。
// StringVar defines a string flag with specified name, default value, and usage string. // The argument p points to a string variable in which to store the value of the flag. // StringVar 定義了一個帶有指定名稱、預設值和用法字串的字串標誌。引數 p 指向一個字串變數,用於儲存標誌的值。 func StringVar(p *string, name string, value string, usage string) { CommandLine.Var(newStringValue(value, p), name, usage) }
這裡可以看到區別就是,將返回值指標,變成了函數的第一個引數。
// IntVar defines an int flag with specified name, default value, and usage string. // The argument p points to an int variable in which to store the value of the flag. // IntVar 定義了一個具有指定名稱、預設值和用法字串的 int 標誌。引數 p 指向一個儲存標誌值的 int 變數。 func IntVar(p *int, name string, value int, usage string) { CommandLine.Var(newIntValue(value, p), name, usage) }
瞭解這些後,我們就開始吧!
package main // ...import func commandStyle() { methodPtr := flag.String("method", "default", "method of sample") valuePtr := flag.Int("value", -1, "value of sample") // 解析 flag.Parse() fmt.Println(*methodPtr, *valuePtr) } func commandStyle2() { var method string var value int flag.StringVar(&method, "method", "default", "method of sample") flag.IntVar(&value, "value", -1, "value of sample") flag.Parse() fmt.Println(method, value) } func main() { commandStyle() }
在終端使用 go run . -method get -value 1
這串命令後,列印出了 get 1
。
Parse 解析來自 os.Args[1:] 的命令列標誌。必須在定義所有標誌之後和程式存取標誌之前呼叫。
這裡的一個重要的點就是要使用 flag.Parse()
,也就是解析go run .` 之後的標誌。使用變數將標誌的值接收,然後列印。
這兩種方式結果都是一樣,只有寫法上的差距,這時候雖然我們體驗了一點簡單的命令列的影子了,但似乎還是感覺好像啥效果也沒有呀。接下來我們就來實現一個 copy 檔案內容的功能
首先我們使用上面說過的類似方式,註冊標誌 f,v
,然後解析標誌
func main() { var showProgress, force bool // -f 當存在時拷貝,是否強制拷貝 flag.BoolVar(&force, "f", false, "force copy when existing") flag.BoolVar(&showProgress, "v", false, "explain what is being done") flag.Parse() // 獲取引數個數,必須要輸入兩個引數,因為copy是從這個檔案到另一個檔案 if flag.NArg() < 2 { flag.Usage() // 列印用途 return } copyFileAction(flag.Arg(0), flag.Arg(1), showProgress, force) }
註冊標誌完成後,我們就可以開始實現我們的 copy
功能了
首先我們必須後面要輸入兩個檔名,讓最後一個檔案copy到前一個檔案(制定規則)
我們模擬命令列輸入:go run . -f -v a.txt b.txt
,這就是我們最後需要實現的東西,f, v
是可以省略的,預設把 a.txt -> b.txt
。
-f
表示當檔案存在時,強制copy覆蓋裡面的內容-v
表示解釋正在做什麼接下來我們需要實現一個 copyFileAction
函數,來實現copy功能,以及命令列引數的效果
func fileExist(fileName string)bool { _, err := os.Stat(fileName) // 返回這個檔案資訊 // IsExist 只是錯誤或報告是否存在 // err == nil,表示有檔案資訊,os.IsExist(err),表示有檔案存在 return err == nil || os.IsExist(err) } // 轉化操作,命令列,與功能實現的邏輯判斷 func copyFileAction(src, dst string, showProgress, force bool) { if !force { // 判斷是否存在檔案,若存在,是否需要覆蓋它 if fileExist(dst) { fmt.Printf("%s exists override? y/n n", dst) reader := bufio.NewReader(os.Stdin) // 讀取輸入內容 data, _, _ := reader.ReadLine() // 取一行的內容 // 判斷輸入的內容 if strings.TrimSpace(string(data)) != "y" { return } } } // copy 檔案 copyFile(src, dst) }
這裡我們可以看到充分利用到了 showProgress 和 force
兩個命令列取的值,當檔案``存在且不強制`時,會有一個詢問,是否覆蓋,同意就實行 copy 操作,不同意不做處理(相當於一次無效命令)。
接下來我們實現功能核心 copyFile
func copyFile(originFile, targetFile string)(written int64, err error){ srcFile, err := os.Open(originFile) // 開啟檔案 if err != nil { // Error() 返回錯誤資訊 log.Fatal(err) return } defer srcFile.Close() dstFile, err := os.Create(targetFile) // 建立檔案 if err != nil { // Error() 返回錯誤資訊 log.Fatal(err) return } defer dstFile.Close() return io.Copy(dstFile, srcFile) // 拷貝檔案 }
這裡我們是採取,將需要被拷貝的檔案開啟,拷貝到的檔名進行建立,然後將內容填充進去,這裡使用了io.Copy()
的內建功能。
package main import ( "bufio" "flag" "fmt" "io" "log" "os" "strings" ) // func commandStyle() { // methodPtr := flag.String("method", "default", "method of sample") // valuePtr := flag.Int("value", -1, "value of sample") // // 解析 // flag.Parse() // fmt.Println(*methodPtr, *valuePtr) // } // func commandStyle2() { // var method string // var value int // flag.StringVar(&method, "method", "default", "method of sample") // flag.IntVar(&value, "value", -1, "value of sample") // flag.Parse() // fmt.Println(method, value) // } func main() { // commandStyle() // commandStyle2() var showProgress, force bool // -f 當存在時拷貝,是否強制拷貝 flag.BoolVar(&force, "f", false, "force copy when existing") flag.BoolVar(&showProgress, "v", false, "explain what is being done") flag.Parse() // 獲取引數個數 if flag.NArg() < 2 { flag.Usage() // 列印用途 return } copyFileAction(flag.Arg(0), flag.Arg(1), showProgress, force) } func fileExist(fileName string)bool { _, err := os.Stat(fileName) // 返回這個檔案資訊 // IsExist 只是錯誤或報告是否存在 // err == nil,表示有檔案資訊,os.IsExist(err),表示有檔案存在 return err == nil || os.IsExist(err) } func copyFile(originFile, targetFile string)(written int64, err error){ srcFile, err := os.Open(originFile) // 開啟檔案 if err != nil { // Error() 返回錯誤資訊 log.Fatal(err) return } defer srcFile.Close() dstFile, err := os.Create(targetFile) // 建立檔案 if err != nil { // Error() 返回錯誤資訊 log.Fatal(err) return } defer dstFile.Close() return io.Copy(dstFile, srcFile) // 拷貝檔案 } // 拷貝檔案 func copyFileAction(src, dst string, showProgress, force bool) { if !force { // 判斷是否存在檔案,若存在,是否需要覆蓋它 if fileExist(dst) { fmt.Printf("%s exists override? y/n n", dst) reader := bufio.NewReader(os.Stdin) // 讀取輸入內容 data, _, _ := reader.ReadLine() // 取一行的內容 // 判斷輸入的內容 if strings.TrimSpace(string(data)) != "y" { return } } } // copy 檔案 copyFile(src, dst) }
以上就是Golang實現簡易的命令列功能的詳細內容,更多關於Golang命令列功能的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45