Loading repository data…
Loading repository data…
eduardoagarcia / repository
Shef is a powerful CLI framework for cooking up dynamic shell recipes.
A transparent discovery signal based on current public GitHub metadata.
This score does not audit code, security, maintainers, documentation quality, or suitability. Verify the repository and its current documentation before adoption.
Shef, a wordplay on "shell" and "chef", is a powerful CLI framework for cooking up dynamic shell recipes.
At its core, imagine that Make, GitHub Actions,
and CyberChef had a weird little <moira-rose>bea-by</>.
Shef allows you to chain multiple commands together, add interactive user prompts, loop using complex control structures, easily run and manage background tasks, and build reusable workflows with advanced logic and conditionals.
This first example demonstrates a simple recipe that echos "Hello World!" to the terminal.
recipes:
- name: "hello-world"
description: "A simple hello world recipe"
operations:
- name: "Run echo command"
command: echo "Hello, World!"
This next example demonstrates progress bars and loops, where a recipe creates a number of temporary files, and then loops through the directory to clean up each file it just created.
This example demonstrates a more advanced recipe where a user selects which background tasks to run and then monitors each task's progress in real-time.
[!TIP] Want to see more before diving deeper? Check out the demo recipes.
Bash scripting is a powerful and valid approach for shell automation. Shef isn't designed to replace bash scripts, but rather provides a toolkit that compliments bash when you need specific features.
Shef implements some common tooling like built-in support for interactive prompts, background task management, and CLI process standardization. This structured approach can simplify certain tasks that might require more verbose code in bash.
Consider Shef as another tool in your automation toolkit. Absolutely use bash scripts when they're the right fit, and reach for Shef when its features align with your specific needs.
I considered several options, and YAML emerged as the most practical choice for this particular use case. JSON lacks comments and multiline string support, which are essential when defining shell commands and documenting workflows. XML would have been unnecessarily verbose. TOML, while nice, doesn't handle nested structures as elegantly for complex workflows.
brew tap eduardoagarcia/tap
brew install shef
shef -v
For detailed installation instructions on Linux and Windows platforms, please refer to the comprehensive installation guide.
Once Shef is installed, you are ready to begin using it.
# Sync all public recipes locally
shef sync
# Run the Hello World recipe
shef demo hello-world
# List available recipes (demo recipes are excluded by default)
shef ls
# List all recipes within a category
shef ls demo
# View help information about a recipe
shef demo arguments -h
shef [recipe-name]
shef [global-flags] [category] [recipe-name] [input-text] [recipe-flags...]
| Flag | Description |
|---|---|
-h, --help | Show help information |
-v, --version | Show version information |
-d, --debug | Enable debug output |
--debug-file | Save debug logs to specified file path |
-c, --category | Specify a category |
-L, --local | Force local recipes first |
-U, --user | Force user recipes first |
-P, --public | Force public recipes first |
-r, --recipe-file | Path to the recipe file |
| Command | Description |
|---|---|
sync s | Sync public recipes locally |
list ls l | List available recipes (note: demo recipes are excluded by default) |
which w [category] [recipe-name] | Show the location of a recipe file |
Shef looks for recipes in multiple locations and contexts within your system:
./.shef/*.yaml in the current directory (only shown when you're in the directory, like Make)~/.shef/user/*.yaml in your home directory (always shown)~/.shef/public/*.yaml in your home directory (always shown)On Linux systems, Shef also supports the XDG Base Directory Specification:
$XDG_CONFIG_HOME/shef/user/*.yaml (defaults to ~/.config/shef/user/*.yaml)$XDG_DATA_HOME/shef/public/*.yaml (defaults to ~/.local/share/shef/public/*.yaml)Shef includes both standard and XDG paths on Linux systems.
If you have recipes with the same name and category in different locations, you can prioritize a specific source:
shef -L git version # Prioritize local recipes
shef -U git version # Prioritize user recipes
shef -P git version # Prioritize public recipes
Recipes are defined in YAML files:
recipes:
- name: "example"
description: "An example recipe"
category: "demo"
vars:
name: "World"
workdir: "./my-project" # optional
help: |
This is detailed help text for the example recipe.
It can include multiple paragraphs and shows when users run:
shef demo example -h
operations:
- name: "First Operation"
id: "first_op"
command: echo "Hello, {{ .name }}!"
- name: "Second Operation"
id: "second_op"
command: ls -la
-h or --help flagsOperations are the building blocks of recipes:
- name: "Operation Name" # Operation name
id: "var_id" # [Optional] Identifier for referencing the variable for the operation
command: echo "Hello" # [Optional] Shell command to execute
execution_mode: "standard" # [Optional] How the command runs (standard, interactive, stream, or background)
output_format: "raw" # [Optional] How to format command output (raw [default], trim, or lines)
silent: false # [Optional] Flag whether to suppress output to stdout. Default is false.
exit: false # [Optional] When set to true, the recipe will exit after the operation completes. Default is false.
condition: .var == "true" # [Optional] Condition for execution
on_success: "success_op" # [Optional] Operation to run on success (if not defined, Shef continues to next operation)
on_failure: "failure_op" # [Optional] Operation to run on failure
transform: "{{ trim .output }}" # [Optional] Transform output
raw_command: false # [Optional] When true, bypasses template rendering for the command. Default is false.
user_shell: false # [Optional] When true, runs command in user's interactive shell. Default is false.
prompts: # [Optional] Interactive prompts (can include one or more prompts)
- name: "Prompt Name"
id: "var_id"
type: "input"
message: "Enter value:"
control_flow: # [Optional] Control flow structure
type: "foreach" # Type of control flow (foreach, for, while)
operations: # [Optional] Sub-operations for control flows
- name: "Sub Operation"
command: echo "Processing " {{ .item }}
break: false # [Optional] When true, break out of a control flow and resume recipe
execution_mode is specified). Output is captured and can be used by
subsequent operations.