README.md
1# script
2
3[![codecov](https://codecov.io/gh/posener/script/branch/master/graph/badge.svg)](https://codecov.io/gh/posener/script)
4[![GoDoc](https://img.shields.io/badge/pkg.go.dev-doc-blue)](http://pkg.go.dev/github.com/posener/script)
5
6Package script provides helper functions to write scripts.
7
8Inspired by [https://github.com/bitfield/script](https://github.com/bitfield/script), with some improvements:
9
10* Output between streamed commands is a stream and not loaded to memory.
11
12* Better representation and handling of errors.
13
14* Proper incocation, usage and handling of stderr of custom commands.
15
16The script chain is represented by a
17[`Stream`](https://godoc.org/github.com/posener/script#Stream) object. While each command in the
18stream is abstracted by the [`Command`](https://godoc.org/github.com/posener/script#Command)
19struct. This library provides basic functionality, but can be extended freely.
20
21## Examples
22
23### HelloWorld
24
25A simple "hello world" example that creats a stream and pipe it to the stdout.
26
27```golang
28// Create an "hello world" stream and use the ToStdout method to write it to stdout.
29Echo("hello world").ToStdout()
30```
31
32 Output:
33
34```
35hello world
36```
37
38### Iterate
39
40An example that shows how to iterate scanned lines.
41
42```golang
43// Stream can be any stream, in this case we have echoed 3 lines.
44stream := Echo("first\nsecond\nthird")
45
46// To iterate over the stream lines, it is better not to read it into memory and split over the
47// lines, but use the `bufio.Scanner`:
48defer stream.Close()
49scanner := bufio.NewScanner(stream)
50for scanner.Scan() {
51 fmt.Println(scanner.Text())
52}
53```
54
55 Output:
56
57```
58first
59second
60third
61```
62
63### Through
64
65An example that shows how to create custom commands using the `Through` method with a `PipeFn`
66function.
67
68```golang
69Echo("1\n2\n3").Through(PipeFn(func(r io.Reader) (io.Reader, error) {
70 // Create a command that sums up all numbers in input.
71 //
72 // In this example we create a reader function such that the whole code will fit into the
73 // example function body. A more proper and readable way to do it was to create a new
74 // type with a state that implements the `io.Reader` interface.
75
76 // Use buffered reader to read lines from input.
77 buf := bufio.NewReader(r)
78
79 // Store the sum of all numbers.
80 sum := 0
81
82 // Read function reads the next line and adds it to the sum. If it gets and EOF error, it
83 // writes the sum to the output and returns an EOF.
84 read := func(b []byte) (int, error) {
85 // Read next line from input.
86 line, _, err := buf.ReadLine()
87
88 // if EOF write sum to output.
89 if err == io.EOF {
90 return copy(b, append([]byte(strconv.Itoa(sum)), '\n')), io.EOF
91 }
92 if err != nil {
93 return 0, err
94 }
95
96 // Convert the line to a number and add it to the sum.
97 if i, err := strconv.Atoi(string(line)); err == nil {
98 sum += i
99 }
100
101 // We don't write anything to output, so we return 0 bytes with no error.
102 return 0, nil
103 }
104
105 return readerFn(read), nil
106})).ToStdout()
107```
108
109 Output:
110
111```
1126
113```
114
115---
116Readme created from Go doc with [goreadme](https://github.com/posener/goreadme)
117