Featured image of post Go Shell

Go Shell

Go Shell

I have recently made a shell in go, link to its source code.

Basic code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
package main

import (
	"bufio"
	"fmt"
	"os"
	"os/exec"
	"os/signal"
	"runtime"
	"strings"
)

func main() {
	if runtime.GOOS == "windows" {
		fmt.Println("Shell is not made for windows. Sorry")
		os.Exit(1)
	}

	reader := bufio.NewReader(os.Stdin)
	for {
		wd, err := os.Getwd()
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
		}
		fmt.Print(wd)
		fmt.Print(" $ ")
		input, err := reader.ReadString('\n')
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
		}
		if err = execInput(input); err != nil {
			fmt.Fprintln(os.Stderr, err)
		}
	}
}
func execInput(input string) error {
	home := os.Getenv("HOME")
	input = strings.TrimSuffix(input, "\n")

	args := strings.Split(input, " ")

	switch args[0] {
	case "exit":
		os.Exit(0)
	case "cd":
		if len(args) < 2 {
			return os.Chdir(home)
		}
		return os.Chdir(args[1])
	}

	cmd := exec.Command(args[0], args[1:]...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	return cmd.Run()
}

Don’t worry, we’ll go over the code

Code explanation

Check if running on windows

1
2
3
4
if runtime.GOOS == "windows" {
  fmt.Println("Shell is not made for windows. Sorry")
  os.Exit(1)
}

This checks if it is running on windows. If it is, it exits with error.

Create reader

1
reader := bufio.NewReader(os.Stdin)

This allows us to read from the standard input.

Read loop

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
for {
  wd, err := os.Getwd()
  if err != nil {
    fmt.Fprintln(os.Stderr, err)
  }
  fmt.Print(wd)
  fmt.Print(" $ ")
  input, err := reader.ReadString('\n')
  if err != nil {
    fmt.Fprintln(os.Stderr, err)
  }
  if err = execInput(input); err != nil {
    fmt.Fprintln(os.Stderr, err)
  }
}

This reads from the standard input and executes the input.

Execute input

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
func execInput(input string) error {
  home := os.Getenv("HOME")
  input = strings.TrimSuffix(input, "\n")

  args := strings.Split(input, " ")

  switch args[0] {
  case "exit":
    os.Exit(0)
  case "cd":
    if len(args) < 2 {
      return os.Chdir(home)
    }
    return os.Chdir(args[1])
  }

  cmd := exec.Command(args[0], args[1:]...)
  cmd.Stdin = os.Stdin
  cmd.Stdout = os.Stdout
  cmd.Stderr = os.Stderr

  return cmd.Run()
}

This executes the input.

1
2
3
4
5
6
7
8
9
switch args[0] {
case "exit":
  os.Exit(0)
case "cd":
  if len(args) < 2 {
    return os.Chdir(home)
  }
  return os.Chdir(args[1])
}

This switch statement adds commands that don’t have a binary.

Conclusion

This is a shell in go.
Obviously it can be modified to add commands and customize it.

Licensed under CC BY-NC-SA 4.0