0
0

Shell作ってみる:Goバージョン

Posted at

内容

  • この記事を参考に実施した
  • Cの記事もあるので、今後そちらでも作成したいと思う

記事のコード(一部改変)

動かしたところ、EOFが無限に表示されてしまったため、一部変更した
また独自のコマンドhelloを追加した

main.go
package main

import (
	"bufio"
	"errors"
	"fmt"
	"os"
	"os/exec"
	"strings"
)

// learn-memo: メイン関数。プログラムのエントリーポイントとなり、ユーザーの入力を無限ループで処理する
func main() {
	fmt.Print("Golang Shell\n")
	reader := bufio.NewReader(os.Stdin)
	for {
		fmt.Print("> ")
		// learn-memo: キーボードからの入力を読み取る
		input, err := reader.ReadString('\n')
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
		}

		// learn-memo: 入力から改行文字を削除
		input = strings.TrimSuffix(input, "\n")

		// learn-memo: 空の入力をスキップ
		if input == "" {
			continue
		}

		// learn-memo: 入力されたコマンドを実行
		if err = execInput(input); err != nil {
			fmt.Fprintln(os.Stderr, err)
		}
	}
}

// learn-memo: cdコマンドが引数なしで呼ばれた場合のエラー
var ErrNoPath = errors.New("path required")

// learn-memo: 入力されたコマンドを実行する関数
func execInput(input string) error {
	// learn-memo: 入力をコマンドと引数に分割
	args := strings.Split(input, " ")

	// learn-memo: ビルトインコマンドのチェック
	switch args[0] {
	case "cd":
		// learn-memo: cdコマンドの処理。引数が不足している場合はエラーを返す
		if len(args) < 2 {
			return ErrNoPath
		}
		// learn-memo: ディレクトリを変更
		return os.Chdir(args[1])
	case "exit":
		// learn-memo: プログラムを終了
		os.Exit(0)
	case "hello":
		fmt.Println("world")
		return nil
	}

	// learn-memo: 外部コマンドの実行準備
	cmd := exec.Command(args[0], args[1:]...)

	// learn-memo: 標準エラー出力と標準出力を設定
	cmd.Stderr = os.Stderr
	cmd.Stdout = os.Stdout

	// learn-memo: コマンドを実行し、エラーがあれば返す
	return cmd.Run()
}

感想

正直入力を無限ループで待機して、知っている引数であれば処理を行い、知らない引数は外部のコマンドを叩こうという形であるため、あまりshellを自作した実感はない

shellをゼロから構築するイメージだったため少し物足りないが、shellをラップしてbashなどができているので独自にカスタムしたshellを手軽に使いたいのであれば選択肢としてはありかなと思う。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0