This error occurs when Docker's shell cannot locate a command you're trying to run inside a container. Common causes include missing binaries, incorrect shebangs, Windows line endings, or using minimal base images without a shell.
The "/bin/sh: command not found" error indicates that the shell inside your Docker container cannot find the executable you're trying to run. This error originates from the container's shell interpreter (/bin/sh), not from Docker itself. When you run a command in Docker (via RUN, CMD, ENTRYPOINT, or docker exec), the shell attempts to locate the binary either in the system PATH or at the specified location. If the binary doesn't exist, isn't executable, or can't be found in PATH, you'll see this error. This is particularly common with minimal base images like Alpine (which uses busybox/ash instead of bash) or scratch images (which have no shell at all). It can also occur when scripts have Windows line endings (CRLF) that corrupt the shebang line.
Check your Docker build output or container logs to identify the exact command that's failing:
# For build failures, check the output carefully
docker build -t myimage .
# For runtime failures, check container logs
docker logs <container_name_or_id>Look for the exact error message format: /bin/sh: <command>: not found - the <command> tells you what's missing.
Start an interactive shell in your container or base image to check if the command exists:
# For images with a shell
docker run -it --rm <image_name> /bin/sh
# Check if command exists
which <command>
type <command>
# List what's in PATH
echo $PATHIf the command doesn't exist, you need to install it in your Dockerfile.
Add the package containing your command. Use the correct package manager for your base image:
# Alpine Linux (uses apk)
RUN apk add --no-cache bash curl wget
# Debian/Ubuntu (uses apt-get)
RUN apt-get update && apt-get install -y bash curl wget
# RHEL/CentOS (uses yum or dnf)
RUN yum install -y bash curl wgetTip: Use apk search <name> or apt-cache search <name> to find package names.
If your script uses #!/bin/bash but your image doesn't have bash, update the shebang:
# For Alpine or minimal images, use sh (more portable)
#!/bin/sh
# Or install bash in your Dockerfile first
RUN apk add --no-cache bashMake sure your script is also executable:
COPY script.sh /app/
RUN chmod +x /app/script.shIf you developed on Windows, your scripts might have CRLF line endings that break the shebang:
# Convert locally before building
dos2unix script.sh
# Or convert in Dockerfile
RUN sed -i 's/\r$//' /app/script.sh
# Or use tr
RUN tr -d '\r' < /app/script.sh > /app/script_fixed.sh && mv /app/script_fixed.sh /app/script.shConfigure Git to preserve line endings:
git config --global core.autocrlf inputOr add a .gitattributes file:
*.sh text eol=lfThe exec form (JSON array) doesn't use a shell, so the command must be a direct binary path:
# Exec form - runs binary directly (no shell expansion)
CMD ["/app/myprogram"]
ENTRYPOINT ["/app/entrypoint.sh"]
# Shell form - runs through /bin/sh -c (shell expansion works)
CMD /app/myprogram
# IMPORTANT: Use double quotes in JSON, not single quotes
# Correct:
CMD ["./script.sh"]
# Wrong:
CMD ['./script.sh']If you need shell features (pipes, variables), use shell form or explicitly invoke the shell:
CMD ["/bin/sh", "-c", "echo $HOME && ./script.sh"]Scratch and distroless images have no shell. You must use exec form with statically compiled binaries:
FROM scratch
# Copy your statically compiled binary
COPY --from=builder /app/myprogram /myprogram
# Must use exec form since there's no shell
ENTRYPOINT ["/myprogram"]For Go programs, compile statically:
FROM golang:1.21-alpine AS builder
RUN CGO_ENABLED=0 go build -o /app/myprogram .
FROM scratch
COPY --from=builder /app/myprogram /myprogram
ENTRYPOINT ["/myprogram"]If the container fails too quickly to inspect, override the entrypoint:
# Start container with shell instead of failing command
docker run -it --entrypoint /bin/sh <image_name>
# For images without sh, try ash (Alpine) or bash
docker run -it --entrypoint /bin/ash <image_name>
# Once inside, manually run your command to see the full error
/app/entrypoint.shFor Kubernetes pods:
command: ["sleep", "infinity"]Alpine Linux specifics: Alpine uses busybox ash shell, not bash. Many bash-specific features won't work:
- source command - use . instead
- [[ conditionals - use [ instead
- Arrays and associative arrays are limited
- echo -e for escape sequences - use printf instead
Dynamic linking issues: Binaries compiled on glibc systems (Ubuntu, Debian) may fail on Alpine (musl libc) with "not found" even though the file exists. This happens because the dynamic linker (/lib/ld-linux) doesn't exist. Solutions:
- Compile with CGO_ENABLED=0 for Go
- Use -static flag for C/C++
- Use a glibc-based image instead of Alpine
Multi-architecture builds: If you're building for multiple architectures, ensure your base image and any binaries match the target platform:
docker buildx build --platform linux/amd64,linux/arm64 -t myimage .Debugging "file exists but not found": This paradox usually means:
1. Wrong shebang interpreter (#!/bin/bash but no bash)
2. CRLF line endings corrupting the shebang
3. Missing dynamic libraries (ldd <binary> to check)
4. Wrong architecture binary
image operating system "linux" cannot be used on this platform
How to fix 'image operating system linux cannot be used on this platform' in Docker
manifest unknown: manifest unknown
How to fix 'manifest unknown' in Docker
cannot open '/etc/passwd': Permission denied
How to fix 'cannot open: Permission denied' in Docker
Error response from daemon: failed to create the ipvlan port
How to fix 'failed to create the ipvlan port' in Docker
toomanyrequests: Rate exceeded for anonymous users
How to fix 'Rate exceeded for anonymous users' in Docker Hub