Jenkins sh "Bad substitution" (dash vs bash) in CI
By Kaveh Alemi·Latchkey
The sh step runs the script with /bin/sh, which on Debian/Ubuntu agents is dash, not bash. Bash-only constructs (${var^^}, <<<, arrays, brace ranges) produce Bad substitution or a syntax error under dash.
What this error means
A sh step fails with /bin/sh: 1: Bad substitution or Syntax error: ... unexpected on a script that works in an interactive bash shell.
Jenkins console
+ echo ${VERSION^^}
/home/jenkins/workspace/app@tmp/durable-abc/script.sh: 1: Bad substitution
script returned exit code 2
Diagnose it: agent, workspace, or sandbox?
Jenkinsfile
sh 'hostname && whoami && pwd'
sh 'java -version 2>&1'
sh 'env | sort | head -40'
// workspaces are reused between builds by default
cleanWs()
Common causes
Bash-only syntax under dash
The sh step uses POSIX /bin/sh. Bash-specific features (case modification, here-strings, arrays) are not valid in dash and fail.
Assuming bash is the default shell
Scripts written and tested in bash break when the agent's /bin/sh is dash.
How to fix it
Invoke bash explicitly
Use a bash shebang in a multi-line sh script, or call bash -c.
Or rewrite the script in POSIX-compatible syntax.
Confirm bash is installed on the agent.
Jenkinsfile
sh '''#!/usr/bin/env bash
set -euo pipefail
echo "${VERSION^^}"
'''
How to prevent it
Add a #!/usr/bin/env bash shebang when using bash-only features.
Lint shell with shellcheck against the intended shell.
Prefer POSIX syntax for portability across agents.
Frequently asked questions
What causes Jenkins sh "Bad substitution" (dash vs bash) in CI?
There are 2 common causes: bash-only syntax under dash and assuming bash is the default shell. The sh step uses POSIX /bin/sh.
How do I fix Jenkins sh "Bad substitution" (dash vs bash) in CI?
Invoke bash explicitly. Use a bash shebang in a multi-line sh script, or call bash -c.
What does Jenkins sh "Bad substitution" (dash vs bash) in CI actually mean?
A sh step fails with /bin/sh: 1: Bad substitution or Syntax error: ...
How do I stop Jenkins sh "Bad substitution" (dash vs bash) in CI happening again?
Add a #!/usr/bin/env bash shebang when using bash-only features. The prevention section lists 3 changes that keep it from recurring.