Skip to content

shell

Execute shell commands with streaming output, exit code capture, and output extraction.

ParameterTypeRequiredDescription
funcstringyesMust be shell
dostringyesShell command(s) to execute. Supports multi-line with |.
shellstringnoShell type: shell (default, POSIX sh), gosh, bash, zsh, pwsh
envmapnoAdditional environment variables for this step
output_formatstringnoOutput parsing: auto (default), json, yaml, text
outputsmapnoNamed output extraction using Go templates on result
timeoutstringnoPer-execution timeout (e.g., 30s, 5m)
FieldTypeDescription
result.outputstringCombined stdout and stderr text
result.exit_codeintProcess exit code (0 = success)
result.dataobjectParsed structured data when output is JSON/YAML (requires output_format: auto or explicit format)
steps:
- name: greet
func: shell
do: echo "Hello, world!"
steps:
- name: build
func: shell
do: |
echo "Building version {{ vars.version }}"
npm install
npm run build
echo "BUILD_ID=build-$(date +%s)"

Extract structured data from command output using outputs and Go template expressions:

steps:
- name: build
func: shell
do: |
echo "Building application..."
echo "IMAGE_TAG=myapp:v1.2.3"
echo "BUILD_STATUS=success"
outputs:
image_tag: '{{ result.output | regexFind "IMAGE_TAG=(.+)" }}'
status: '{{ result.output | regexFind "BUILD_STATUS=(.+)" }}'
- name: verify
func: assert
args:
condition: '{{ eq steps.build.status "success" }}'
desc: "Build must succeed"
steps:
- name: deploy
func: shell
env:
AWS_REGION: us-east-1
DEPLOY_ENV: "{{ vars.environment }}"
do: |
echo "Deploying to $AWS_REGION ($DEPLOY_ENV)"

When commands emit JSON, OrchStep auto-parses the output for direct field access:

steps:
- name: get_instances
func: shell
do: aws ec2 describe-instances --output json
outputs:
instance_id: "{{ result.data.Reservations.0.Instances.0.InstanceId }}"
state: "{{ result.data.Reservations.0.Instances.0.State.Name }}"
steps:
- name: build
func: shell
do: |
docker build -t app:{{ vars.version }} .
echo "DIGEST=$(docker inspect --format='{{.Id}}' app:{{ vars.version }})"
outputs:
digest: '{{ result.output | regexFind "DIGEST=(.+)" }}'
- name: push
func: shell
do: |
docker push app:{{ vars.version }}
echo "Pushed image with digest {{ steps.build.digest }}"

The default shell is POSIX sh (/bin/sh), which works on Alpine, distroless containers, and all Linux/macOS systems. Override at the step level using args.type:

TypeEngineBest For
shell (default)/bin/shMaximum portability
goshGo-native (mvdan/sh)Windows, single-binary deployments
bash/bin/bashBash-specific features (arrays, [[ ]])
zsh/bin/zshmacOS default shell features
pwshPowerShellPowerShell scripting
steps:
- name: posix-portable
func: shell
do: echo "Runs in /bin/sh (default)"
- name: go-native
func: shell
args:
type: "gosh"
cmd: echo "Runs in Go-native shell — works on Windows"
- name: needs-bash
func: shell
args:
type: "bash"
cmd: |
declare -A map
map[key]="value"
echo "${map[key]}"

Shell type can also be configured globally or at workflow level. See Shell Execution for full configuration details.

gosh is OrchStep’s built-in Go shell interpreter. It requires no external shell binary, making it ideal for Windows and minimal containers:

name: cross-platform
config:
func:
shell:
type: "gosh"
tasks:
build:
steps:
- name: compile
func: shell
do: |
echo "Works on Windows, Linux, and macOS"
echo "No bash required"
steps:
- name: long_task
func: shell
do: ./long-running-script.sh
timeout: 60s
retry:
max_attempts: 3
interval: 5s
on_error: warn