Shell-style programming in Go: Write powerful "shell scripts" as Go programs
yupsh lets you write Go programs that work like shell scripts, combining the best of both worlds:
- Shell's Power: Composable commands, pipelines, and text processing glue
- Go's Strengths: Type safety, performance, robust error handling, and rich data structures
Instead of writing bash scripts, write Go programs with shell-like operations!
- Glue Code: Connecting different tools and processing data flows
- Text Processing: Powerful pipelines for filtering, transforming, and analyzing
- Automation: Quick scripts to automate repetitive tasks
- Type Safety: Catch errors at compile time instead of runtime
- Performance: Compiled binaries run faster and use less memory
- Data Handling: Rich standard library and powerful data structures
- Error Handling: Explicit error handling prevents silent failures
- Testing: Built-in testing framework with excellent tooling
- Distribution: Single binary deployment, no dependency issues
// Instead of this bash script:
// #!/bin/bash
// cat logs/*.log \
// | grep ERROR \
// | cut -d' ' -f1,3 \
// | sort \
// | uniq -c \
// | head -10
// Write this Go program:
func main() {
ctx := context.Background()
pipeline := yup.Pipe(
cat.Cat("logs/*.log"),
grep.Grep("ERROR", grep.IgnoreCase),
cut.Cut(cut.Fields(1, 3), cut.Delimiter(" ")),
sort.Sort(),
uniq.Uniq(uniq.Count),
head.Head(head.Lines(10)),
)
pipeline.Execute(ctx, nil, os.Stdout, os.Stderr)
}yupsh provides pure Go implementations of common Unix commands. Each command is independently maintained with comprehensive examples.
| Command | Shell Example | yupsh Equivalent | Examples |
|---|---|---|---|
| awk | awk '{print $2}' |
awk.Awk(customProgram, input) |
📚 awk-examples |
| cat | cat file.txt |
cat.Cat("file.txt") |
📚 cat-examples |
| cut | cut -d',' -f1,3 |
cut.Cut(cut.Fields(1, 3), cut.Delimiter(",")) |
📚 cut-examples |
| grep | grep "pattern" |
grep.Grep("pattern") |
📚 grep-examples |
| head | head -n 10 |
head.Head(head.Lines(10)) |
📚 head-examples |
| nl | nl file.txt |
nl.Nl("file.txt") |
📚 nl-examples |
| paste | paste file1 file2 |
paste.Paste("file1", "file2") |
📚 paste-examples |
| rev | rev |
rev.Rev() |
📚 rev-examples |
| sed | sed 's/old/new/' |
sed.Sed("s/old/new/") |
📚 sed-examples |
| sort | sort -n |
sort.Sort(sort.Numeric) |
📚 sort-examples |
| tac | tac file.txt |
tac.Tac("file.txt") |
📚 tac-examples |
| tail | tail -n 20 |
tail.Tail(tail.Lines(20)) |
📚 tail-examples |
| tr | tr 'a-z' 'A-Z' |
tr.Tr("a-z", "A-Z") |
📚 tr-examples |
| uniq | uniq -c |
uniq.Uniq(uniq.Count) |
📚 uniq-examples |
| wc | wc -l |
wc.Wc(wc.Lines) |
📚 wc-examples |
| Command | Shell Example | yupsh Equivalent | Examples |
|---|---|---|---|
| basename | basename /path/file.txt |
basename.Basename("/path/file.txt") |
📚 basename-examples |
| comm | comm file1 file2 |
comm.Comm("file1", "file2") |
📚 comm-examples |
| diff | diff file1 file2 |
diff.Diff("file1", "file2") |
📚 diff-examples |
| dirname | dirname /path/file.txt |
dirname.Dirname("/path/file.txt") |
📚 dirname-examples |
| find | find . -name "*.go" |
find.Find(".", find.Name("*.go")) |
📚 find-examples |
| join | join file1 file2 |
join.Join("file1", "file2") |
📚 join-examples |
| ls | ls -la |
ls.Ls(ls.Long, ls.All) |
📚 ls-examples |
| split | split -l 100 file |
split.Split("file", split.Lines(100)) |
📚 split-examples |
| Command | Shell Example | yupsh Equivalent | Examples |
|---|---|---|---|
| base64 | base64 file.txt |
base64.Base64("file.txt") |
📚 base64-examples |
| echo | echo "hello" |
echo.Echo("hello") |
📚 echo-examples |
| hexdump | hexdump -C file |
hexdump.Hexdump("file", hexdump.Canonical) |
📚 hexdump-examples |
| seq | seq 1 10 |
seq.Seq(1, 10) |
📚 seq-examples |
| shuf | shuf file.txt |
shuf.Shuf("file.txt") |
📚 shuf-examples |
| tee | tee output.txt |
tee.Tee("output.txt") |
📚 tee-examples |
| xargs | xargs -n 1 echo |
xargs.Xargs(xargs.MaxArgs(1)) |
📚 xargs-examples |
| yes | yes "string" |
yes.Yes("string") |
📚 yes-examples |
| Command | Description | yupsh Equivalent | Examples |
|---|---|---|---|
| capture | Capture command output to buffers | capture.Capture(cmd, capture.Stdout, capture.Stderr) |
📚 capture-examples |
| emit | Emit strings as command output | emit.Emit("line1", "line2") |
📚 emit-examples |
| exec | Execute external commands | exec.Exec("command", args...) |
📚 exec-examples |
| pipe | Compose commands in pipelines | pipe.Pipe(cmd1, cmd2, cmd3) |
Built into framework |
| while | Loop through input lines | while.While(func(line string) {...}) |
📚 while-examples |
| Command | Description | yupsh Equivalent | Examples |
|---|---|---|---|
| git | Git version control operations | git.Git("status") |
📚 git-examples |
| perl | Execute Perl scripts | perl.Perl(script) |
📚 perl-examples |
| json | JSON processing utilities | json.Parse(input) |
Command available |
Pure Go implementations - No subprocess spawning for core commands. Zero external dependencies.
- ✅ Shell's composability with Go's type safety
- ✅ Pure Go implementations - no subprocess overhead
- ✅ Single binary - works anywhere Go runs
- ✅ Testable & maintainable - full IDE support
- ✅ Extensible - each command is independent
# Install the framework and commands
go get github.com/gloo-foo/framework
go get github.com/yupsh/grep
go get github.com/yupsh/sort// Write shell-like Go code
pipeline := yup.Pipe(
grep.Grep("ERROR"),
sort.Sort(),
head.Head(head.Lines(10)),
)
pipeline.Execute(ctx, input, os.Stdout, os.Stderr)- 📘 Documentation: Core concepts, philosophy, and detailed guides
- 🚀 Examples: Real shell scripts vs yupsh Go programs
- 🔧 Framework: Build your own commands
- 💬 Discussions: Ask questions and share ideas
yupsh - Shell-style programming in Go
GitHub •
Documentation •
Examples