Shell Executor (macOS / Linux)
Run commands and scripts on Unix-like systems (macOS, Linux, BSD).
Configure the Shell
- DAG defaults (literal values):yaml
shell: ["/bin/bash", "-e", "-u"] steps: - command: echo "Runs with bash -e -u" - Step override (evaluated at runtime so params/secrets/outputs are allowed):yaml
steps: - shell: ${CUSTOM_SHELL:-/bin/zsh} command: echo "Runs in the step shell" - Fallback: If no shell is set, Dagu uses
DAGU_DEFAULT_SHELL, then$SHELL, thensh. - String or array:
shellaccepts either"bash -e"or["bash", "-e"]; arrays avoid quoting issues.
Running Commands
- Inline command string:yaml
steps: - echo "Hello" - command: echo "Hello with key" - | echo "Multi-line command block" echo "Runs as a script (not split into args)" - Command + args array:yaml
steps: - command: [python3, -u, app.py, --limit, "10"] - Script block:yamlIf you omit a step-level
steps: - script: | #!/usr/bin/env bash set -e echo "Multi-line script"shelland the script has a shebang, that interpreter is used. Otherwise the resolved shell runs the script file. - Interpreter + inline script:yaml
steps: - command: python3 script: | import sys print("Args:", sys.argv) - Working directory and env: Use
workingDir/dirandenvon the step (or DAG defaults) to control context.
Script Behavior (Unix)
- A
script:block is saved to a temp file in the working directory when possible and removed after the step finishes. - If there is no step-level
shelland the script has a shebang, that interpreter runs the script. Without a shebang, the resolved shell runs it (Dagu appends-efor sh/bash/zsh/ksh/ash/dash when using the default/DAG-level shell; step-level shells are left unchanged). - When both
commandandscriptare set,commandis treated as the interpreter and receives the script path directly (no shell wrapper) — useful forcommand: python3with inline code.
Shell Options
POSIX shells (sh/bash/zsh/ksh/ash/dash)
With the default or DAG-level shell, Dagu appends-eso the shell stops on the first failing command. If you set a step-level shell, add-eyourself when you want errexit.nix-shell
Pin tools per step withshell: nix-shellandshellPackages:yamlsteps: - shell: nix-shell shellPackages: [python3, jq] command: | python3 --version jq --versionnix-shell must be installed separately. Dagu runs inside
nix-shell --run ...; it defaults to--pureif you do not supply purity flags. Include any flags you need (such as--impure) in theshellarray. When Dagu supplies the shell, it prependsset -e;to the command string unless you already provided it.Direct execution (no shell parsing)
shell: directruns binaries without shell features; use array form:yamlsteps: - shell: direct command: [/usr/bin/python3, -u, script.py]
Tips
- Prefer array syntax for commands with flags to avoid quoting surprises.
- Keep DAG-level shells stable; override per-step only when you need a different interpreter.
- Use shebangs in multi-line scripts when you want a specific interpreter without repeating
shell. - When using nix-shell, list every tool your step needs in
shellPackagesfor reproducibility.
