Skip to content

Instantly share code, notes, and snippets.

@nthery
Created February 14, 2021 08:07
Show Gist options
  • Save nthery/9ba28821e8a4c54c16bda90396644568 to your computer and use it in GitHub Desktop.
Save nthery/9ba28821e8a4c54c16bda90396644568 to your computer and use it in GitHub Desktop.
Gotac prints lines from standard input or files in command-line in reverse order
// Gotac prints lines from standard input or files in command-line in reverse order.
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
args := os.Args[1:]
if len(args) == 0 {
tac(os.Stdin, "stdin")
} else {
for _, path := range args {
var f *os.File
if path == "-" {
f = os.Stdin
path = "stdin"
} else {
var err error
f, err = os.OpenFile(path, os.O_RDONLY, 0)
if err != nil {
fmt.Fprintf(os.Stderr, "cannot open %v: %v\n", path, err)
continue
}
defer f.Close()
}
tac(f, path)
}
}
}
// tac reads f line by line and prints lines in reverse order.
// path is used for error handling.
func tac(f *os.File, path string) {
lines, err := readLines(f)
printReverse(lines)
if err != nil {
fmt.Fprintf(os.Stderr, "error while reading %v: %v\n", path, err)
}
}
// readLines returns a slice containing all lines in f without end-of-line.
// If an error occurs, lines contains all lines accumulated before the error.
func readLines(f *os.File) ([]string, error) {
lines := make([]string, 0, 16)
scanner := bufio.NewScanner(f)
for scanner.Scan() {
lines = append(lines, scanner.Text())
}
return lines, scanner.Err()
}
// printReverse prints lines from end to beginning.
func printReverse(lines []string) {
for i := len(lines) - 1; i >= 0; i-- {
fmt.Println(lines[i])
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment