Skip to content

creack/pty

Folders and files

NameName
Last commit message
Last commit date

Latest commit

edfbf75 · Oct 31, 2024
Dec 9, 2023
Oct 31, 2023
May 3, 2011
Oct 31, 2023
Jul 1, 2022
Jun 29, 2019
Dec 9, 2023
May 29, 2021
Apr 5, 2021
Oct 31, 2023
Oct 31, 2024
Oct 31, 2024
Aug 13, 2024
Oct 31, 2023
Oct 31, 2024
Nov 9, 2023
Mar 27, 2022
Oct 31, 2023
Oct 31, 2023
Oct 31, 2023
Oct 31, 2023
May 16, 2021
Apr 28, 2023
Apr 28, 2023
Apr 28, 2023
Oct 31, 2023
Apr 28, 2023
Apr 28, 2023
Apr 28, 2023
Oct 28, 2024
Oct 31, 2024
Mar 27, 2022
Mar 27, 2022
Mar 27, 2022
Oct 28, 2023
Mar 27, 2022
Mar 27, 2022
Mar 27, 2022
Mar 27, 2022
Mar 27, 2022
Oct 31, 2023
Oct 31, 2023
Mar 27, 2022
Mar 27, 2022
Mar 27, 2022
Mar 27, 2022
Mar 27, 2022
Mar 27, 2022
Mar 27, 2022
Mar 27, 2022
Mar 27, 2022
Mar 27, 2022
Sep 27, 2021
Apr 28, 2023
Oct 16, 2021
Mar 27, 2022
Mar 27, 2022
Feb 28, 2024
May 1, 2015
Mar 27, 2022
Mar 27, 2022
Mar 27, 2022
Mar 27, 2022
Sep 1, 2022

Repository files navigation

pty

Pty is a Go package for using unix pseudo-terminals.

Install

go get github.com/creack/pty

Examples

Note that those examples are for demonstration purpose only, to showcase how to use the library. They are not meant to be used in any kind of production environment. If you want to set deadlines to work and Close() interrupting Read() on the returned *os.File, you will need to call syscall.SetNonblock manually.

Command

package main

import (
	"io"
	"os"
	"os/exec"

	"github.com/creack/pty"
)

func main() {
	c := exec.Command("grep", "--color=auto", "bar")
	f, err := pty.Start(c)
	if err != nil {
		panic(err)
	}

	go func() {
		f.Write([]byte("foo\n"))
		f.Write([]byte("bar\n"))
		f.Write([]byte("baz\n"))
		f.Write([]byte{4}) // EOT
	}()
	io.Copy(os.Stdout, f)
}

Shell

package main

import (
        "io"
        "log"
        "os"
        "os/exec"
        "os/signal"
        "syscall"

        "github.com/creack/pty"
        "golang.org/x/term"
)

func test() error {
        // Create arbitrary command.
        c := exec.Command("bash")

        // 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 {
                        if err := pty.InheritSize(os.Stdin, ptmx); err != nil {
                                log.Printf("error resizing pty: %s", err)
                        }
                }
        }()
        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() {
        if err := test(); err != nil {
                log.Fatal(err)
        }
}