Fix 'Permission Denied' on Shell Scripts Fast
You tried running a script and got 'Permission denied'. It's almost always a missing execute bit. Here's the fix and why.
Yeah, that 'Permission denied' message when you try to run your script is annoying. It's almost always the same root cause — the file doesn't have the execute bit set. Let's fix it right now.
The Quick Fix
Run this command on your script:
chmod +x yourscript.sh
Then run it again:
./yourscript.sh
That's it 90% of the time. No, you don't need sudo chmod unless the script is owned by root. Don't overcomplicate it.
If you're still stuck, try:
bash yourscript.sh
That bypasses the execute permission issue entirely — you're telling bash to read the file directly. Not a permanent fix, but it proves the script itself works.
Why This Happens
Linux file permissions are split into three groups: owner, group, and others. Each has read (4), write (2), and execute (1) bits. When you create a new script with touch or redirect output, the default permissions are typically 644 (read/write for owner, read-only for everyone else). No execute bit means the kernel won't run it.
The chmod +x command adds the execute bit to all three groups. Your shell then sees the file as executable and runs it. Under the hood, the kernel checks the st_mode field in the inode — if the execute bit isn't set, you get the EACCES error, which surfaces as 'Permission denied'. Simple.
There's also the shebang line at the top of the script — #!/bin/bash or #!/bin/sh. If that's missing or points to a wrong path, you'll get a different error usually, but sometimes it can combine with permission issues. Always check the first line of your script.
Less Common Variations
1. The Filesystem is Mounted with 'noexec'
This one's sneaky. The file has execute permission, but the partition where it lives won't allow execution. Common on /tmp, /home on shared servers, or external drives. Check with:
mount | grep $(df . --output=target | tail -1)
If you see noexec in the options, move your script to /usr/local/bin or $HOME and try again. You can also run bash yourscript.sh as a workaround — that reads the file as a script, not an executable binary.
2. Wrong Ownership or Group
If the script is owned by root and you're running it as a regular user, even chmod +x won't help if the 'others' permissions don't include execute. Fix with:
chmod o+x yourscript.sh
Or change the owner:
sudo chown $USER:$USER yourscript.sh
3. SELinux or AppArmor Blocking Execution
You'll see this more on CentOS/RHEL or Fedora, but it can happen on Ubuntu if you've tightened security. Check ls -Z on the script — if the SELinux context looks wrong, run:
restorecon -v yourscript.sh
Or temporarily set enforcing to permissive to test:
sudo setenforce 0
But don't leave it that way. Fix the context properly if that's the root cause.
4. Windows Line Endings (CRLF)
If you edited your script on Windows and copied it to Linux, the line endings might be \r\n instead of \n. The shebang line won't be recognized properly. Symptoms include weird 'Permission denied' or 'No such file' errors. Fix with:
dos2unix yourscript.sh
Or:
sed -i 's/\r$//' yourscript.sh
Prevention for Next Time
Stop creating scripts with touch. Instead, do this when you start a new script:
cat > script.sh << 'EOF'
#!/bin/bash
echo "Hello"
EOF
chmod +x script.sh
Or use your editor and set the execute bit immediately after saving. I use a one-liner in my .bashrc:
alias newsh='touch $1 && chmod +x $1 && vim $1'
You can also set your umask to something like 0022 for new files, but that won't help with execute bits — umask only affects read/write. For execute bits, you need a habit. Every time you write a script, run chmod +x before you test. Saves you the frustration.
One more thing: if you're writing scripts in a shared directory (like /opt/scripts), make sure the group permissions include execute. Use chmod g+rx so others in the same group can run them. Don't use 777 — that's lazy and dangerous.
That's it. Fix the bit, move on. You won't see this error again once you make chmod +x your first reflex after writing a script.
Was this solution helpful?