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) | |
} | |
} |