DOC_INDEX
THEME
DOCS/Migrating to OrchStep/From Shell Scripts

From Shell Scripts

Turn a scripts/ folder of .sh files into OrchStep tasks - positional args become named variables, and shared libraries become modules.

The most common starting point of all: a scripts/ folder. deploy.sh, release.sh, seed-db.sh - each a chunk of Bash you run by hand. OrchStep gives that folder structure, discoverability, and portability without making you rewrite the shell you already trust.

The 30-second version

./scripts/deploy.sh prod 2.1    ->   orchstep run deploy --var environment=prod --var version=2.1
./scripts/test.sh               ->   orchstep run test
ls scripts/                     ->   orchstep list-tasks

How the concepts map

scripts/ folderOrchStep
scripts/deploy.shA deploy task (or tasks/deploy.yml)
./scripts/deploy.sh prodorchstep run deploy --var environment=prod
Positional args $1, $2Named --var + defaults:
set -euo pipefailThe default - a failed step stops the run
source scripts/lib.shA reusable module
A run-all.sh wrapperA ci task that calls each task:

Side by side

You don't rewrite the logic - you wrap it. A multi-line script becomes a do: | block; positional args become readable named variables.

SCRIPTS/DEPLOY.SH
#!/usr/bin/env bash
set -euo pipefail

ENV="${1:-staging}"
VERSION="${2:-1.0.0}"

echo "deploying v$VERSION to $ENV"
# ... more steps ...
TASKS/DEPLOY.YML
desc: Deploy to an environment
steps:
  - name: ship
    func: shell
    do: |
      echo "deploying v{{ vars.version }} to {{ vars.environment }}"
      # ... paste the rest of the script here ...

With the defaults declared once at the workflow root:

defaults:
  version: "1.0.0"
  environment: "staging"
orchstep run deploy --var environment=production --var version=2.1.0
  $ echo "deploying v2.1.0 to production"
deploying v2.1.0 to production
Result: success

The win is at the call site: ./scripts/deploy.sh prod 2.1 true (what was the third argument again?) becomes self-documenting named variables.

A scripts/ folder is a tasks/ directory

This migration lines up almost one-to-one with OrchStep's task file discovery: drop one file per command under tasks/ and each becomes callable automatically.

scripts/                 tasks/
  build.sh        ->       build.yml      (orchstep run build)
  test.sh         ->       test.yml       (orchstep run test)
  deploy.sh       ->       deploy.yml     (orchstep run deploy)

orchstep list-tasks then replaces ls scripts/, and orchstep menu gives you a keyboard picker over them.

Gotchas worth knowing

  • set -e is the default. OrchStep stops on the first failed step, so you rarely need it. For "keep going" or cleanup, use error handling (on_error, catch, finally).
  • Positional to named. $1/$2 become --var name=value. Declare sensible defaults: so the bare orchstep run deploy still works.
  • Shared Bash libraries become modules. If several scripts source lib.sh, promote that shared logic into a module instead of copy-paste.
  • env is reserved. Don't use env as a variable name - it is the environment-variable namespace. Use environment.

Migrate one script at a time

A task can call the old script verbatim while you convert it:

tasks:
  deploy:
    steps:
      - name: legacy
        func: shell
        do: ./scripts/deploy.sh "{{ vars.environment }}" "{{ vars.version }}"

Swap the body for native steps when you're ready, and delete the .sh file.

What you gain

  • orchstep run --dry-run shows what every script would do before it runs.
  • Cross-platform: no bash assumptions, runs the same in CI and on Windows.
  • Typed outputs between steps instead of export and re-parsing.

Where to go next