Fix 'Permission denied' in Linux when running scripts with ./
Getting 'Permission denied' when you try to run a script with ./? The fix is almost always adding execute permission with chmod +x. Let me show you exactly what to do.
I know this error is infuriating. You've written a perfect script, you type ./myscript.sh, and the system just says Permission denied. It's like the computer is mocking you. Don't worry — this is almost always a quick fix.
The Immediate Fix
Run this command in the terminal:
chmod +x myscript.sh
./myscript.sh
That's it. The script should now run. If it doesn't, read on — there are a couple other things that can block you.
Why This Happens
Linux files have three permission sets: owner, group, and others. Each set has read (r), write (w), and execute (x) bits. When you create a new script file, it usually has only read and write permissions — no execute bit. The ./ prefix tells the shell to run the file as a program, but without the execute bit set, the kernel refuses.
Think of it like this: the file exists, you can open it in a text editor and read it, but the system won't let it run as a program because the execute flag isn't flipped on. The chmod +x command flips that switch.
When chmod +x Isn't Enough
Three other things can cause the same error even after you add execute permissions:
1. Wrong Shebang Line
The first line of your script must be a valid shebang. If it's missing or broken, the shell won't know how to interpret the file. For a bash script, the first line should be exactly:
#!/bin/bash
I've seen people type #! /bin/bash (space after the bang) or #!/bin/sh when they need bash features. Get that line right. If you're writing a Python script, use #!/usr/bin/env python3.
2. Filesystem Mounted with noexec
If you're on a shared server or a mounted drive (like /tmp or a USB stick), the filesystem might be mounted with the noexec option. This blocks all execute permissions regardless of file permissions. Check with:
mount | grep $(df . --output=target | tail -1)
If you see noexec in the output, you can't run scripts from that location. Move your script to /home/yourusername/ or another partition without noexec.
3. SELinux or AppArmor Interference
On RHEL, CentOS, or Fedora, SELinux can block script execution even with proper permissions. Check your audit log:
sudo ausearch -m avc -ts recent
If you see denials, you can either temporarily set SELinux to permissive mode (sudo setenforce 0) to test, or properly label your file with restorecon -v myscript.sh. On Ubuntu with AppArmor, check sudo aa-status.
Step-by-Step Troubleshooting Checklist
- Run
ls -l myscript.sh. Do you see-rwxr-xr-x? If not, runchmod +x myscript.sh. - Check the first line of the script with
head -1 myscript.sh. Does it have a valid shebang? For bash, it must be#!/bin/bash. - Check if the filesystem has noexec with
mount | grep $(df . --output=target | tail -1). If it does, move the script. - Check SELinux or AppArmor logs. On RHEL/CentOS,
sudo ausearch -m avc -ts recent. On Ubuntu,sudo journalctl | grep -i apparmor. - Try running the script with an explicit interpreter:
bash myscript.sh. If that works, the file itself is fine — the issue is either permissions or shebang.
Preventing This in the Future
When you create a new script file, set the execute permission immediately. I do this as a habit:
touch myscript.sh
chmod +x myscript.sh
# then edit it
Or use chmod 755 if you want tighter control (owner can write, everyone else can read and execute). Another trick: if you're copying scripts from Windows or email, they often lose execute permissions. After copying, chmod +x * in that directory can fix all of them at once.
For directories where you frequently run scripts, set your umask to include execute bits by default. Add this to your .bashrc:
umask 022
That gives new files 755 permissions (rwxr-xr-x) instead of the default 644. It won't affect existing files.
Why You Shouldn't Use sudo for This
I see people type sudo ./myscript.sh when they get permission denied. That runs the script as root, which bypasses file permissions but also runs the script with full root privileges. If you don't need root for the script, don't use sudo. It's a security risk and it masks the real issue. Fix the permissions instead.
The bottom line: chmod +x is your friend. Use it, move on, and stop banging your head against that wall.
Was this solution helpful?