Paging output from Go

golang pagination
gorm pagination
golang pagination rest api

I'm trying print to stdout from golang using $PAGER or manually invoking more or less to allow the user to easily scroll through a lot of options. How can I achieve this?

You can use the os/exec package to start a process that runs less (or whatever is in $PAGER) and then pipe a string to its standard input. The following worked for me:

func main() {
    // Could read $PAGER rather than hardcoding the path.
    cmd := exec.Command("/usr/bin/less")

    // Feed it with the string you want to display.
    cmd.Stdin = strings.NewReader("The text you want to show.")

    // This is crucial - otherwise it will write to a null device.
    cmd.Stdout = os.Stdout

    // Fork off a process and wait for it to terminate.
    err := cmd.Run()
    if err != nil {
        log.Fatal(err)
    }
}

schwarmco/go-pagination: calculating values needed for , Calculate(1, 3, len(items)) fmt.Println(pager.NumPages) // Output: 2 fmt.Println(​pager.HasNext) // Output: true fmt.Println(pager.HasPrev) // Output: false  You would enter the following command to pause after each page: Directory Listing: ls | more. After one page of output is displayed, the “more” program waits for you to press the spacebar before displaying the next page. If you want to quit out of the paging process, simply press the ‘Q’ key. Quit: Press the 'Q' key

I assume you already have output being printed from your program to stdout that you want to have captured and sent to your pager, you don't want to rewrite the I/O to use another input stream like the other responses require.

You can create an os.Pipe which works the same as running a command with "|less" by attaching one side to your pager and the other side to stdout like this:

// Create a pipe for a pager to use
r, w, err := os.Pipe()
if err != nil {
    panic("You probably want to fail more gracefully than this")
}

// Capture STDOUT for the Pager. Keep the old
// value so we can restore it later.
stdout := os.Stdout
os.Stdout = w

// Create the pager process to execute and attach
// the appropriate I/O streams.
pager := exec.Command("less")
pager.Stdin = r
pager.Stdout = stdout // the pager uses the original stdout, not the pipe
pager.Stderr = os.Stderr

// Defer a function that closes the pipe and invokes
// the pager, then restores os.Stdout after this function
// returns and we've finished capturing output.
//
// Note that it's very important that the pipe is closed,
// so that EOF is sent to the pager, otherwise weird things 
// will happen.
defer func() {
    // Close the pipe
    w.Close()
    // Run the pager
    if err := pager.Run(); err != nil {
        fmt.Fprintln(os.Stderr, err)
    }
    // restore stdout
    os.Stdout = stdout
}()

What is the best way to pipe the output of a command through a , 0 ] then "${PAGER:="less"}" < "$buffer" # The above is equivalent to # cat patch: for one-screen output, the output doesn't go through the less post-processing  By default, paging is enabled on the CLI, this will output 50 lines than you will need to hit the space bar or enter to view the rest of the output. This can cause issues while trying to grab output or viewing certain logs.

Here is a somewhat naive cat example that uses $PAGER when set.

package main

import (
        "io"
        "log"
        "os"
        "os/exec"
)

func main() {
        var out io.WriteCloser
        var cmd *exec.Cmd

        if len(os.Args) != 2 {
                log.Fatal("Wrong number of args: gcat <file>")
        }
        fileName := os.Args[1]
        file, err := os.Open(fileName)
        if err != nil {
                log.Fatal("Error opening file: ", err)
        }

        pager := os.Getenv("PAGER")

        if pager != "" {
                cmd = exec.Command(pager)

                var err error
                out, err = cmd.StdinPipe()
                if err != nil {
                        log.Fatal(err)
                }

                cmd.Stdout = os.Stdout

                if err := cmd.Start(); err != nil {
                        log.Fatal("Unable to start $PAGER: ", err)
                }

        } else {
                out = os.Stdout
        }

        _, err = io.Copy(out, file)
        if err != nil {
                log.Fatal(err)
        }

        file.Close()
        out.Close()

        if cmd != nil {
                if err := cmd.Wait(); err != nil {
                        log.Fatal("Error waiting for cmd: ", err)
                }
        }

}

Pagers: more, less, and most, more(1) is what we call a pager utility. Oftentimes the output of a particular command is too big to fit on one screen. They leave this job to the pager utility. advanced past the screen you wanted. more does not provide a way to go back​. A 70V output is available on Bogen amplifiers and is the primary type of output for paging systems. A step-up output transformer in the amplifier provides the high 70V output signal. All speakers with step-down transform-ers(rated for 70V systems) are connected to this output. Other Output Types (25V, 16- and 8-ohm)

This version creates an io.Writer called pager for all the output that you want paged (you can assign it to os.Stdout if you like) and correctly closes that and waits for the $PAGER when main() returns.

import (
    "fmt"
    "io"
    "log"
    "os"
    "os/exec"
)

var pager io.WriteCloser

func main() {
    var cmd *exec.Cmd
    cmd, pager = runPager()
    defer func() {
        pager.Close()
        cmd.Wait()
    }()
    fmt.Fprintln(pager, "Hello, 世界")
}

func runPager() (*exec.Cmd, io.WriteCloser) {
    pager := os.Getenv("PAGER")
    if pager == "" {
        pager = "more"
    }
    cmd := exec.Command(pager)
    out, err := cmd.StdinPipe()
    if err != nil {
        log.Fatal(err)
    }
    cmd.Stdout = os.Stdout
    cmd.Stderr = os.Stderr
    if err := cmd.Start(); err != nil {
        log.Fatal(err)
    }
    return cmd, out
}

Paging Screen Output, When running interactively, Octave normally sends any output intended for your terminal that is more than one screen long to a paging program, such as less or  To return to the beginning of the output, press lowercase g and to go to the end press uppercase G. To go to a specific line, enter a number before pressing the g or G keys. Searching for a Pattern Locate text within the output using the forward-slash key followed by the text you wish to search or a regular expression.

Is there a paging version of `watch`?, to watch the output of qstat, but this can only shows the first screenful. With a paging version of watch , I would be able to move around in the output as it is still​  To display the Output window whenever you build a project, in the Options dialog box, on the Projects and Solutions > General page, select Show Output window when build starts. Then, with a code file open for editing, choose Go to Next Message and Go To Previous Message on the Output window toolbar to select entries in the Output pane.

Octave, Go to the first, previous, next, last section, table of contents. No output is displayed by the pager until just before Octave is ready to print the top level prompt,  A Simple Approach to Generate Page Numbers in X of Y Format in ODS RTF Output Amos Shu, Endo Pharmaceuticals., Chadds Ford, PA ABSTRACT Page numbers in X of Y format, such as “Page 18 of 280”, “Page 2 of 30”, are a common feature of ODS RTF outputs. The “X” indicates the current page number, and the “Y” is the total number of pages.

less Man Page - Linux, Page through text one screenful at a time, Search through output, Edit the extensive enhancements such as allowing backward paging through a file as well as G > ESC-> * Go to last line in file (or line N). p % * Go to beginning of file (or N  In the same dialog increase the height of the page to a value that makes the output fit nicely to a single PDF sheet. For now keep the width the same as the original PDF output. In our example we will increase the height of the page to 14 inches so we run the report now the PDF output looks as follow.

Comments
  • The question is very unclear. If you print to stdout and the user manually invokes a pager, then ... you've achieved what you want.
  • I think the question explains perfectly what I want. What I'm trying to achieve is to pipe the stdout of my go program to the call to $PAGER
  • Years ago (Oct 2012 according to ls) I made a package to do something like this. I vaguely recall there was some problem/issue with actually using it however (e.g. I tried adding it to godoc to make it like hg man with the pager extension enabled, but I ended up back with just piping through a pager on the command line instead).
  • You can do w, err := cmd.StdinPipe() to let arbitrary code write to the process through w.
  • You're right you could: pager := os.ExpandEnv("$PAGER")