golang shell
我如何在Golang中制作一个简单的交互式外壳
Hannah Joshua在“ Unsplash ”上发表的 “命令计算机键盘键”
所以今天,我在Golang学习了一些新知识和一些基础知识。 它正在制作一个简单的交互式外壳。 这只是一个非常简单的应用程序,但制作起来看起来很酷。
我在Golang工作了1年以上。 人们已经创建了这么多工具,例如: spf13创建的cobra或更多有助于我们制作命令行应用程序的工具。 但是,以某种方式,我很好奇如何在不依赖其他外部库的情况下制作一个简单的库。
因此,出于好奇,我开始搜索如何在Google中进行制作。 但是我发现只有使用其他外部依赖项的教程。 每个人都只是在推广自己的库以简化制作交互式shell的过程。 伙计们? 我只需要使用纯Golang包(没有外部依赖项)来制作一个简单的😌
但是,我发现了一篇有关制作交互式外壳的文章,例如这篇文章: http : //technosophos.com/2014/07/11/start-an-interactive-shell-from-within-go.html ,但是,他确实不像我想要的。 因此,以后只提供了我在Gobyexample.com等网站上发现的许多示例。
我自己编写了一个简单的Shell应用程序。 在这里,我将在下面说明如何做到这一点。
贝壳
因此,在制作简单的Shell应用程序之前,我想确保Shell的含义与您的含义相同。
对我来说,Shell是一个将充当非常基本的用户界面(基于文本的界面)的应用程序。 有人可能会说它是命令行界面(CLI)。
申请
为了制作应用程序,对于最简单的原型,我将像这样制作。
$ls <br> go . mod main. go
从终端读取命令
为此,首先要做的就是读取输入。 我需要从终端读取输入。 为此,我做到了。
reader := bufio.NewReader(os.Stdin)
cmdString,err := reader.ReadString( '\n' )
if err != nil {
fmt.Fprintln(os.Stderr, err)
}
执行命令
然后执行命令。 从终端读取命令字符串后,现在执行命令。
cmdString = strings.TrimSuffix(cmdString,"\n" )
cmd := exec.Command(commandString)
cmd.Stderr = os.Stderr
cmd.Stdout = os.Stdout
cmd.Run()
到这里为止,现在我可以运行我的简单shell应用程序,但是它将仅运行一个命令。 运行命令后,它将停止。
添加无限循环
使它在执行一次后接收所有命令。 我们需要将其添加到无限循环中。
for {
fmt.Print( "$ " )
cmdString, err := reader.ReadString( '\n' )
if err != nil {
fmt.Fprintln(os.Stderr, err)
}
cmdString = strings.TrimSuffix(cmdString, "\n" )
cmd := exec.Command(cmdString)
cmd.Stderr = os.Stderr
cmd.Stdout = os.Stdout
err = cmd.Run()
if err != nil {
fmt.Fprintln(os.Stderr, err)
}
}
如果我们运行该应用程序,它将如下所示
简单的外壳程序
处理论点
在这一行之前,我已经完成了我的第一个CLI应用程序。 但是它仍然不接受参数。 如果我传递参数,那么它将引发错误。
$ls -lah // this command wil throw error
要阅读这些参数,请在下面进行说明。 首先,我将命令拆分为字符串数组。
// ...
cmdString = strings.TrimSuffix(cmdString, "\n" )
arrCommandStr := strings.Fields(cmdString)
cmd := exec.Command(arrCommandStr[ 0 ], arrCommandStr[ 1 :]...)
// ...
为了拆分文本,我使用了包字符串中的Fields函数。 此功能类似于分割字符串功能。 如果是string.Split,则将使用给定的特定分隔符拆分字符串。 但是字符串。字段将用空格分隔单词。
例:
str :="Hello World Beautiful World"
arrString := strings.Fields(str)
fmt.Println(arrString)
// [Hello World Beautiful World]
现在,我的简单外壳程序已经接受并处理给定的参数。 现在,该命令应该起作用了。
$ ls -lah
total4280
drwxr-xr-x 5 iman staff 160 B Nov 6 19 : 48 .
drwxr-xr-x 6 iman staff 192 B Nov 6 11 : 41 ..
-rw-r--r-- 1 iman staff 38 B Nov 6 11 : 43 go.mod
-rw-r--r-- 1 iman staff 606 B Nov 6 20 : 11 main.go
-rwxr-xr-x 1 iman staff 2.1 M Nov 6 19 : 49 simshel
添加退出命令
但是,此应用程序仅适用于在环境中注册的任何内置应用程序。 像退出之类的命令不存在,因为它已在每个CLI应用程序中编程。
然后,我为系统中没有内置应用程序的每个命令(如exit
命令)创建一个切换案例处理程序。
package mainimport (
"bufio"
"fmt"
"os"
"os/exec"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
for {
fmt.Print( "$ " )
cmdString, err := reader.ReadString( '\n' )
if err != nil {
fmt.Fprintln(os.Stderr, err)
}
err = runCommand(cmdString)
if err != nil {
fmt.Fprintln(os.Stderr, err)
}
}
}
func runCommand(commandStr string) error {
commandStr = strings.TrimSuffix(commandStr, "\n" )
arrCommandStr := strings.Fields(commandStr)
switch arrCommandStr[ 0 ] {
case "exit" :
os.Exit( 0 )
// add another case here for custom commands.
}
cmd := exec.Command(arrCommandStr[ 0 ], arrCommandStr[ 1 :]...)
cmd.Stderr = os.Stderr
cmd.Stdout = os.Stdout
return cmd.Run()
}
添加自定义命令
要添加自定义命令,我可以简单地将其添加到切换案例处理程序中。 例如,我想添加类似plus
的命令。 此命令在任何CLI应用程序中都不存在。 我想要这样:
$ plus2 4 5 6 <br> 17
为此,我只需要添加一个sum函数并在switch-case中添加命令case处理程序
结论
最后,它只是一个非常简单的应用程序。 但是可以肯定的是,我在做这个时学到了一些东西。 而且,在撰写本文时,我发现了与此文章类似的文章(这里: https : //sj14.gitlab.io/post/2018-07-01-go-unix-shell/ )。 阅读该文章后,我正在考虑放弃我的草稿。 但是,我在这里写了很多解释和示例,所以无论如何我决定将其发布为XD。
无论如何,我也将源代码也放在了我的Github中: https : //github.com/bxcodec/simpleshell ,如果碰巧的话,我稍后会尝试在其中添加一些功能。
*印尼文版本: https : //medium.com/easyread/today-i-learned-belajar-membuat-aplikasi-interactive-shell-sederhana-di-golang-2ef013003393
*更新:添加了另一个自定义命令示例
golang shell