From 0aaf8b92162623816303bf2110e0b2d86248860f Mon Sep 17 00:00:00 2001 From: shreyaabaranwal Date: Fri, 19 Jun 2026 23:57:08 +0530 Subject: [PATCH 1/3] docs: add example to count ERROR lines in a log file (#236) Signed-off-by: shreyaabaranwal --- examples/app.log | 6 ++++++ examples/count_errors.go | 30 ++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 examples/app.log create mode 100644 examples/count_errors.go diff --git a/examples/app.log b/examples/app.log new file mode 100644 index 0000000..8fcb66f --- /dev/null +++ b/examples/app.log @@ -0,0 +1,6 @@ +2026-06-19 12:00:00 [INFO] Starting application... +2026-06-19 12:01:05 [WARN] Low memory warning +2026-06-19 12:02:10 [ERROR] Database connection failed +2026-06-19 12:03:15 [INFO] Retrying database connection... +2026-06-19 12:04:20 [ERROR] Retries exhausted. Could not connect to database. +2026-06-19 12:05:00 [INFO] Shutting down application. diff --git a/examples/count_errors.go b/examples/count_errors.go new file mode 100644 index 0000000..ecdfdd7 --- /dev/null +++ b/examples/count_errors.go @@ -0,0 +1,30 @@ +// This program reads a log file, filters only the lines containing "ERROR", and prints the count of those lines. +// It uses the github.com/bitfield/script library to handle the file reading, matching, and counting. +// +// Equivalent shell command: +// grep ERROR app.log | wc -l + +package main + +import ( + "fmt" + "os" + + "github.com/bitfield/script" +) + +func main() { + // Check if examples/app.log exists, otherwise fallback to app.log. + logFile := "examples/app.log" + if _, err := os.Stat(logFile); os.IsNotExist(err) { + logFile = "app.log" + } + + count, err := script.File(logFile).Match("ERROR").CountLines() + if err != nil { + fmt.Fprintf(os.Stderr, "Error reading log file: %v\n", err) + os.Exit(1) + } + + fmt.Printf("Number of ERROR lines: %d\n", count) +} From c30c52d253ff4fc3bdd0055087e8496ffb9b3c76 Mon Sep 17 00:00:00 2001 From: shreyaabaranwal Date: Sat, 20 Jun 2026 00:32:21 +0530 Subject: [PATCH 2/3] docs: add example to filter DOWN servers from a CSV (#236) Signed-off-by: shreyaabaranwal --- examples/count_errors.go | 2 ++ examples/filter_csv.go | 31 +++++++++++++++++++++++++++++++ examples/servers.csv | 5 +++++ 3 files changed, 38 insertions(+) create mode 100644 examples/filter_csv.go create mode 100644 examples/servers.csv diff --git a/examples/count_errors.go b/examples/count_errors.go index ecdfdd7..c7272e5 100644 --- a/examples/count_errors.go +++ b/examples/count_errors.go @@ -1,3 +1,5 @@ +//go:build ignore + // This program reads a log file, filters only the lines containing "ERROR", and prints the count of those lines. // It uses the github.com/bitfield/script library to handle the file reading, matching, and counting. // diff --git a/examples/filter_csv.go b/examples/filter_csv.go new file mode 100644 index 0000000..a670e39 --- /dev/null +++ b/examples/filter_csv.go @@ -0,0 +1,31 @@ +//go:build ignore + +// This program reads a CSV file containing server names and their status (comma separated), +// filters only the lines where the status is "DOWN", and prints the name of each such server (first column). +// It uses the github.com/bitfield/script library to handle the file reading, matching, replacing, and filtering. +// +// Equivalent shell command: +// grep DOWN servers.csv | cut -d, -f1 + +package main + +import ( + "fmt" + "os" + + "github.com/bitfield/script" +) + +func main() { + // Check if examples/servers.csv exists, otherwise fallback to servers.csv. + csvFile := "examples/servers.csv" + if _, err := os.Stat(csvFile); os.IsNotExist(err) { + csvFile = "servers.csv" + } + + _, err := script.File(csvFile).Match("DOWN").Replace(",", " ").Column(1).Stdout() + if err != nil { + fmt.Fprintf(os.Stderr, "Error reading CSV file: %v\n", err) + os.Exit(1) + } +} diff --git a/examples/servers.csv b/examples/servers.csv new file mode 100644 index 0000000..e7a29ef --- /dev/null +++ b/examples/servers.csv @@ -0,0 +1,5 @@ +server1,UP +server2,DOWN +server3,DOWN +server4,UP +server5,DOWN From e432526281e5ae2ea69a0cc51edcd5d021fc32f7 Mon Sep 17 00:00:00 2001 From: shreyaabaranwal Date: Fri, 26 Jun 2026 23:44:09 +0530 Subject: [PATCH 3/3] docs: simplify examples to open files directly and link from README (#236) Signed-off-by: shreyaabaranwal --- README.md | 2 ++ examples/count_errors.go | 24 +++++++++--------------- examples/filter_csv.go | 28 +++++++++++----------------- 3 files changed, 22 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 038e31e..9d107c2 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,8 @@ For something a bit more challenging, let's try counting the number of lines in numErrors, err := script.File("test.txt").Match("Error").CountLines() ``` +You can find a complete, runnable version of this in [examples/count_errors.go](examples/count_errors.go), along with other examples in the [`examples/`](examples) directory. + But what if, instead of reading a specific file, we want to simply pipe input into this program, and have it output only matching lines (like `grep`)? ```go diff --git a/examples/count_errors.go b/examples/count_errors.go index c7272e5..91aa34c 100644 --- a/examples/count_errors.go +++ b/examples/count_errors.go @@ -1,32 +1,26 @@ //go:build ignore -// This program reads a log file, filters only the lines containing "ERROR", and prints the count of those lines. -// It uses the github.com/bitfield/script library to handle the file reading, matching, and counting. +// Counts the lines containing "ERROR" in a log file. +// +// Run it from the repository root: +// +// go run examples/count_errors.go // // Equivalent shell command: -// grep ERROR app.log | wc -l - +// +// grep ERROR examples/app.log | wc -l package main import ( "fmt" - "os" "github.com/bitfield/script" ) func main() { - // Check if examples/app.log exists, otherwise fallback to app.log. - logFile := "examples/app.log" - if _, err := os.Stat(logFile); os.IsNotExist(err) { - logFile = "app.log" - } - - count, err := script.File(logFile).Match("ERROR").CountLines() + count, err := script.File("examples/app.log").Match("ERROR").CountLines() if err != nil { - fmt.Fprintf(os.Stderr, "Error reading log file: %v\n", err) - os.Exit(1) + panic(err) } - fmt.Printf("Number of ERROR lines: %d\n", count) } diff --git a/examples/filter_csv.go b/examples/filter_csv.go index a670e39..f8a1ddc 100644 --- a/examples/filter_csv.go +++ b/examples/filter_csv.go @@ -1,31 +1,25 @@ //go:build ignore -// This program reads a CSV file containing server names and their status (comma separated), -// filters only the lines where the status is "DOWN", and prints the name of each such server (first column). -// It uses the github.com/bitfield/script library to handle the file reading, matching, replacing, and filtering. +// Prints the names of servers whose status is "DOWN", read from a CSV file. +// +// Run it from the repository root: +// +// go run examples/filter_csv.go // // Equivalent shell command: -// grep DOWN servers.csv | cut -d, -f1 - +// +// grep DOWN examples/servers.csv | cut -d, -f1 package main import ( - "fmt" - "os" - "github.com/bitfield/script" ) func main() { - // Check if examples/servers.csv exists, otherwise fallback to servers.csv. - csvFile := "examples/servers.csv" - if _, err := os.Stat(csvFile); os.IsNotExist(err) { - csvFile = "servers.csv" - } - - _, err := script.File(csvFile).Match("DOWN").Replace(",", " ").Column(1).Stdout() + // Column splits on whitespace, so turn the comma into a space first, + // then take the first field (the server name). + _, err := script.File("examples/servers.csv").Match("DOWN").Replace(",", " ").Column(1).Stdout() if err != nil { - fmt.Fprintf(os.Stderr, "Error reading CSV file: %v\n", err) - os.Exit(1) + panic(err) } }