bash: permission denied
Why bash refuses to run a script with Permission denied, how a missing execute bit differs from a noexec mount, and the safe ways to fix either.
Last updated
bash: ./script.sh: Permission denied
What it means: The shell found the file and tried to execute it directly, but the filesystem's permission bits don't allow your user to run it.
Likely causes
Most probable first — with how to confirm.
- 1.The file lacks the execute bit — check with `ls -l script.sh`; if the permissions string has no `x` (e.g. `-rw-r--r--`), that's the cause.
- 2.You're running it as `./script.sh` (direct execution, which needs the execute bit) rather than `bash script.sh` (which only needs read access, since bash itself reads and interprets the file).
- 3.The file lives on a filesystem mounted without exec permission — some network shares, or a Windows drive mounted into WSL, can be mounted `noexec` — check with `mount | grep noexec` for the relevant mount point.
- 4.You own the file, but the containing directory restricts traversal for your user, or the file is owned by another user or group without execute rights granted to you — check `ls -ld` on the directory too.
Fixes
Safest first; destructive ones are called out.
- →Add the execute bit: `chmod +x script.sh`, then re-run `./script.sh` — the standard fix, and non-destructive.
- →If you'd rather not change permissions, run it through the interpreter directly: `bash script.sh` or `sh script.sh`, which only needs read access.
- →If the file lives on a `noexec`-mounted filesystem, copy it to a location that allows execution (like your home directory) instead of trying to force exec rights on that mount.
- →Confirm this isn't actually 'command not found' — permission denied means the file was found; a missing file or a path problem produces a different error instead.
Part by part
- bash:
- The shell is reporting, so the failure happened before your script ran a single line. Nothing inside the file is responsible.
- ./script.sh
- The path as you typed it. The leading ./ is required for a file in the current directory, because the shell does not search there by default.
- Permission denied
- The execute bit is missing, or something else prevents execution. The message is the same in both cases, which is why the second is easy to miss.
Common mistakes
chmod 777 script.shFixes it by letting every user on the machine rewrite the script as well as run it. On a shared or server system that is a genuine hole rather than a shortcut.
chmod +x script.shsudo ./script.shElevates without addressing the missing permission, and runs the whole script as root. If it works, you have now run something with far more privilege than it needed.
Assuming the execute bit is always the causeA filesystem mounted noexec produces the identical message however the permissions are set, which is common on /tmp and on some network shares. Check the mount options when chmod appears to have no effect.
Questions
Why do I need the ./ at all?
The shell searches PATH for commands, and the current directory is deliberately not on it — if it were, a file named ls dropped into a directory would run instead of the real one. The ./ says explicitly where to look.
I set +x and it still fails. What now?
Try bash script.sh directly. If that works, the problem is the execute bit's environment — a noexec mount, or a missing or wrong shebang line at the top of the file.
What if the shebang is wrong?
You usually get "bad interpreter" rather than permission denied, and a Windows line ending after the shebang produces exactly that because the carriage return becomes part of the interpreter path.
Why does the bit disappear when others clone the repo?
It should not — git tracks the executable bit. It is usually lost when the file is created on Windows or copied through something that does not preserve permissions, and git update-index --chmod=+x fixes it in the index.