Fix "bash: ./script.sh: Permission denied"

Quick fix

Give the file the execute permission, then run it again.

chmod +x script.sh
./script.sh

Can't change permissions (USB stick, shared folder)? Run it through the interpreter instead: bash script.sh.

Depending on your shell the message looks like this:

bash: ./script.sh: Permission denied
-bash: ./deploy.sh: Permission denied
zsh: permission denied: ./script.sh

What the error means

When you type ./script.sh, the shell asks the kernel to execute that file. The kernel refuses with EACCES ("Permission denied") when the file has no execute bit for you, when the filesystem is mounted noexec, when you cannot enter one of the directories on its path, or when a security module blocks it. Reading the file and executing it are separate rights: you can open a script in an editor and still not be allowed to run it.

Check the permissions first:

ls -l script.sh

Example output:

-rw-r--r-- 1 alice alice 412 Oct 16 09:12 script.sh

There is no x anywhere in -rw-r--r--, so nobody may execute it.

Cause 1: the file is not executable

New files are created without execute permission, and downloads, git clone from a repository that did not store the bit, or copying through a zip file all lose it.

chmod +x script.sh      # execute for everyone who can read it
chmod u+x script.sh     # execute for the owner only
chmod 755 script.sh     # rwxr-xr-x, typical for shared scripts

Afterwards ls -l shows -rwxr-xr-x. If you are not the owner, chmod fails with "Operation not permitted"; use sudo chmod +x on a file you trust, or copy it to your home directory. Use the chmod calculator to work out octal modes, and see Linux file permissions explained for how the bits work.

For Git repositories, record the bit so others get it too:

git update-index --chmod=+x script.sh
git commit -m "Make script.sh executable"
Never use chmod 777

777 lets every user on the system rewrite your script, which means anyone could insert commands that run the next time you (or root) execute it. Execute permission is all you need.

Cause 2: the filesystem is mounted noexec

If the file is executable but still refused, check the mount options of the filesystem it lives on:

findmnt -T script.sh -o TARGET,FSTYPE,OPTIONS

Example output:

TARGET         FSTYPE OPTIONS
/media/alice/USB vfat  rw,nosuid,nodev,relatime,uid=1000,...,showexec,...

A noexec option, or showexec on FAT (which only marks .exe, .bat and .com files executable), blocks execution. Common places:

  • /tmp or /dev/shm on hardened servers.
  • USB sticks and external disks formatted FAT32, exFAT or NTFS.
  • Network shares (SMB, NFS) mounted with noexec.
  • Windows drives in WSL or dual boot setups.

Workarounds, from simplest to most invasive:

# run through the interpreter: only reading is needed
bash /media/alice/USB/script.sh
# or copy it somewhere executable
cp /media/alice/USB/script.sh ~/bin/ && chmod +x ~/bin/script.sh
# or remount with exec (until next mount)
sudo mount -o remount,exec /media/alice/USB

Only remount /tmp with exec on a hardened server if you understand why it was locked down; installers that fail there usually accept a TMPDIR= pointing elsewhere.

Cause 3: the interpreter in the shebang cannot be executed

The first line of a script (#!/bin/bash) names the program that runs it. If that program is itself not executable or sits on a noexec mount, the error mentions it:

bash: ./script.sh: /opt/tools/bin/python3: bad interpreter: Permission denied

Check the interpreter with ls -l and fix its permissions, or point the shebang to a system interpreter such as #!/usr/bin/env python3. A missing interpreter gives "No such file or directory" instead, and Windows line endings give /bin/bash^M: bad interpreter; fix those with sed -i 's/\r$//' script.sh.

Cause 4: you cannot enter a directory on the path

To run /srv/app/bin/run.sh you need execute (search) permission on /srv, /srv/app and /srv/app/bin. Check every component at once:

namei -l /srv/app/bin/run.sh

Look for a directory without x for your user or group, and fix it with chmod o+x or by adding yourself to the owning group. This also explains cd: Permission denied.

Cause 5: SELinux or AppArmor blocks it

On Fedora and openSUSE Leap 16 (SELinux) or Ubuntu (AppArmor), a confined service may be denied running a script even with correct permissions, typically a web server or cron job executing files from an unusual location. Look for denials:

sudo ausearch -m AVC -ts recent       # SELinux
sudo journalctl -k | grep -i apparmor  # AppArmor

Fix the file label (sudo restorecon -Rv /path) or move the script to a standard location. Do not disable SELinux or AppArmor to work around it.

  • sudo ./script.sh fails the same way: root also needs an execute bit. And sudo script.sh without ./ gives command not found, because the current directory is not in PATH.
  • If you meant to run a command needing root and get a sudoers error, see user is not in the sudoers file.
  • source script.sh or . script.sh runs the file in your current shell and needs only read permission; use it for files that set variables, not for normal scripts.

How to prevent it

  • Make scripts executable as soon as you create them, and commit the bit in Git.
  • Keep personal scripts in ~/.local/bin or ~/bin on a native Linux filesystem.
  • Use a portable shebang (#!/usr/bin/env bash) and Unix line endings.

The bash scripting tutorial covers shebangs, permissions and running scripts from PATH.

Frequently asked questions

How do I make a script executable?

Run chmod +x script.sh (or chmod u+x for only yourself), then start it with ./script.sh.

Why does sudo not fix Permission denied for a script?

Root can read anything, but the kernel still needs at least one execute bit set before it runs a file. Use chmod +x; sudo alone is the wrong fix.

Why can't I run scripts from a USB drive?

FAT32, exFAT and NTFS drives have no Unix permissions, and many are mounted with noexec or a mask that removes execute bits. Run the script with bash script.sh or copy it to your home directory.

Should I use chmod 777 to fix it?

No. 777 makes the file writable by every user, which is a security hole and unnecessary. chmod 755 or chmod u+x is enough.

Spotted a mistake or a command that no longer works? Send a correction — pages are re-checked when reports come in.