bash: ./script.sh: Permission denied almost never means you lack rights to the file’s contents — it means the file is not marked executable, or it lives on a filesystem mounted so that nothing on it can execute. Two very different fixes, so identify which one you have.
The usual cause: no execute bit
A freshly downloaded or newly written script has no x permission. Add it:
chmod +x script.sh
./script.shCheck what you have with ls -l. You want to see an x in the owner column:
ls -l script.sh
# -rw-r--r-- → not executable
# -rwxr-xr-x → executableThe workaround that always tells the truth
Call the interpreter directly. If this works but ./script.sh does not, the problem was definitely the execute bit, not the code:
bash script.sh
sh script.sh
python3 script.pyWhen chmod does not help: noexec mounts
/tmp, /dev/shm and some home partitions are frequently mounted noexec for security — nothing on them may run regardless of permissions. Check with:
mount | grep -E '/tmp|/home'
# look for the word "noexec" in the options- Move the script to a normal path such as your home directory and run it there.
- Or invoke the interpreter explicitly (
bash /tmp/script.sh), which sidesteps the exec check.
A related trap: the shebang
If the script is executable but you get bad interpreter or a cryptic error, the first line may point at a missing interpreter or carry Windows line endings. Check and strip carriage returns:
head -1 script.sh # should be e.g. #!/usr/bin/env bash
sed -i 's/\r$//' script.sh # remove trailing \r from Windows editors“Permission denied” on cd or a file you own
Entering a directory needs its execute bit; reading a file needs read on the file and execute on every directory above it. If cd is refused:
chmod +x /path/to/dir # execute = "may traverse"
ls -ld /path /path/to /path/to/dirNeed a clean box to test permission-sensitive deploys without touching production? A throwaway KVM VPS spins up in about a minute and bills by the month.
Frequently asked
Why does 'bash script.sh' work but './script.sh' does not?
Calling the interpreter directly does not need the file's execute bit; running it as a program does. If the interpreter form works, add the execute bit with chmod +x.
chmod +x did not help — why?
The file is probably on a filesystem mounted noexec, such as /tmp or /dev/shm. Move it to your home directory, or invoke the interpreter directly.
Is it safe to remount /tmp without noexec?
Avoid it. noexec on /tmp is a deliberate defence against dropped payloads. Run the script from a normal path instead of weakening the mount.