Run a terminal from inside your terminal.
The purpose of this code is to demonstrate how to have applications running in a PTY (psedoterminal) environment.
Be sure to have Go installed.
Then just:
go run . /bin/bash| module gist.github.com/shovon/8307ba2559f23baa249601cf8af900c7 | |
| go 1.22.4 | |
| require ( | |
| github.com/creack/pty v1.1.21 | |
| golang.org/x/sys v0.22.0 | |
| golang.org/x/term v0.22.0 | |
| ) |
| github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0= | |
| github.com/creack/pty v1.1.21/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= | |
| golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= | |
| golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= | |
| golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk= | |
| golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= |
| package main | |
| import ( | |
| "io" | |
| "log" | |
| "os" | |
| "os/exec" | |
| "os/signal" | |
| "syscall" | |
| "github.com/creack/pty" | |
| "golang.org/x/term" | |
| ) | |
| func runTerminal(c *exec.Cmd) error { | |
| // Start the command with a pty. | |
| ptmx, err := pty.Start(c) | |
| if err != nil { | |
| return err | |
| } | |
| // Make sure to close the pty at the end. | |
| defer func() { _ = ptmx.Close() }() // Best effort. | |
| // Handle pty size. | |
| ch := make(chan os.Signal, 1) | |
| signal.Notify(ch, syscall.SIGWINCH) | |
| go func() { | |
| for range ch { | |
| pty.InheritSize(os.Stdin, ptmx) | |
| } | |
| }() | |
| ch <- syscall.SIGWINCH // Initial resize. | |
| defer func() { signal.Stop(ch); close(ch) }() // Cleanup signals when done. | |
| // Set stdin in raw mode. | |
| oldState, err := term.MakeRaw(int(os.Stdin.Fd())) | |
| if err != nil { | |
| panic(err) | |
| } | |
| defer func() { _ = term.Restore(int(os.Stdin.Fd()), oldState) }() // Best effort. | |
| // Copy stdin to the pty and the pty to stdout. | |
| // NOTE: The goroutine will keep reading until the next keystroke before returning. | |
| go func() { _, _ = io.Copy(ptmx, os.Stdin) }() | |
| _, _ = io.Copy(os.Stdout, ptmx) | |
| return nil | |
| } | |
| func main() { | |
| // Create arbitrary command. | |
| c := exec.Command(os.Args[1], os.Args[2:]...) | |
| if err := runTerminal(c); err != nil { | |
| log.Fatal(err) | |
| } | |
| } |