Linux Shell Script: 'Permission Denied' Execution Error Troubleshooting Guide
Fix 'Permission Denied' errors when running Linux shell scripts. Debug execute permissions, file ownership, and common bash script issues.
When attempting to execute a shell script on a Linux system, encountering a “Permission denied” error can be a frustrating roadblock. This issue prevents your script from running, regardless of its content or syntax. As an experienced Systems Administrator, understanding the various facets of Linux permissions, file ownership, and filesystem attributes is crucial for swiftly diagnosing and resolving this common problem. This guide will walk you through a highly technical, step-by-step process to troubleshoot and fix “Permission denied” errors for shell scripts.
Symptom & Error Signature
The primary symptom is the script failing to execute, presenting a clear error message in your terminal. You will typically see output similar to one of these variations:
$ ./my_script.sh
bash: ./my_script.sh: Permission denied
Or, if the script is invoked directly without bash explicitly:
$ /path/to/my_script.sh
/path/to/my_script.sh: Permission denied
In some cases, especially if attempting to execute a file that is not a script or has corrupted permissions, you might also see:
$ some_executable
-bash: some_executable: Permission denied
This error specifically indicates that the operating system has denied the current user the right to execute the specified file.
Root Cause Analysis
The “Permission denied” error for shell script execution stems from the kernel’s security mechanisms. Here are the primary underlying reasons:
-
Missing Execute Permission (Most Common):
- Every file on a Linux filesystem has read (
r), write (w), and execute (x) permissions for three categories: the file’s owner, the file’s group, and others (everyone else). - For a script to be executable by a user, that user must have the ‘execute’ bit set for their respective category (owner, group, or other). If the ‘x’ bit is not set, the system will deny execution.
- Every file on a Linux filesystem has read (
-
Incorrect File Ownership or Group:
- If the script’s owner is
userAanduserAhas execute permissions, butuserB(who is trying to run it) does not belong to the file’s group (or the group lacks execute permission),userBwill be denied. Similarly, if ‘others’ lack execute permission,userBwill be denied if they’re neither the owner nor in the group.
- If the script’s owner is
-
Filesystem Mount Options (
noexec):- Some filesystems, or specific partitions/mount points, are mounted with the
noexecoption. This is a security measure that prevents any file from being executed from that particular mount point, regardless of its individual file permissions. Common examples include/tmp,/var/tmp, or user-controlled storage mounts.
- Some filesystems, or specific partitions/mount points, are mounted with the
-
Incorrect Shebang (Interpreter Path) or Missing Interpreter:
- A shell script typically begins with a “shebang” line (e.g.,
#!/bin/bash). This line specifies the interpreter used to execute the script. - While usually resulting in a “command not found” error for the interpreter itself, if the interpreter specified in the shebang does not exist, is not executable, or has incorrect permissions for the user, it can indirectly lead to execution failure. However, a direct “Permission denied” on the script itself usually points to the script’s permissions rather than the interpreter’s.
- A shell script typically begins with a “shebang” line (e.g.,
-
SELinux or AppArmor Security Policies (Advanced):
- Security-Enhanced Linux (SELinux) and AppArmor are mandatory access control (MAC) systems that enforce security policies beyond standard discretionary access control (DAC - traditional
rwxpermissions). - Even if file permissions seem correct, SELinux or AppArmor might restrict a process or user from executing a script based on predefined security contexts or profiles. This is more common in hardened enterprise environments.
- Security-Enhanced Linux (SELinux) and AppArmor are mandatory access control (MAC) systems that enforce security policies beyond standard discretionary access control (DAC - traditional
Step-by-Step Resolution
Follow these steps to diagnose and resolve the “Permission denied” error for your shell script.
1. Verify and Set Execute Permissions
This is the most common fix. Use the ls -l command to inspect the script’s permissions.
-
Inspect Permissions:
ls -l /path/to/my_script.shExample Output:
-rw-r--r-- 1 user group 1234 Jun 27 10:00 my_script.shIn this example,
rw-r--r--indicates:- Owner (
user): Read (r), Write (w), No execute (-) - Group (
group): Read (r), No write (-), No execute (-) - Others: Read (
r), No write (-), No execute (-)
The absence of the
x(execute) bit for the relevant user category is the problem. - Owner (
-
Add Execute Permissions: Use
chmodto add the execute bit.# Add execute permission for the owner chmod u+x /path/to/my_script.sh # Add execute permission for owner and group chmod ug+x /path/to/my_script.sh # Add execute permission for owner, group, and others (most common for scripts) chmod +x /path/to/my_script.shThe
chmod +xcommand is equivalent tochmod a+x(all users). A common and secure permission set for an executable script is755: owner has read, write, execute; group and others have read and execute.chmod 755 /path/to/my_script.shVerify the change:
ls -l /path/to/my_script.sh # Expected output: -rwxr-xr-x 1 user group 1234 Jun 27 10:00 my_script.sh[!IMPORTANT] While
chmod 777grants full permissions to everyone, it is generally a security risk and should be avoided in production environments unless absolutely necessary for a very specific, isolated use case. Always grant the minimum necessary permissions. -
Retry Execution:
./path/to/my_script.sh
2. Check File Ownership and Group
If adding execute permissions doesn’t resolve the issue, verify that the current user has the appropriate ownership or group membership to execute the script.
-
Inspect Ownership and Group:
ls -l /path/to/my_script.shExample Output:
-rwxr-xr-x 1 root root 1234 Jun 27 10:00 my_script.shHere, the script is owned by
root:root. If you are running asuserA, andothersdo not have execute permission, you’ll be denied. -
Identify Current User/Group:
id -un # Current username id -gn # Current primary group id # All groups current user belongs to -
Change Ownership (if necessary): If the script is owned by a different user and you need the current user to own it, use
chown. You generally needsudoprivileges for this.sudo chown your_user:your_group /path/to/my_script.shReplace
your_userandyour_groupwith the desired username and group.[!WARNING] Changing file ownership, especially system files, can have significant security and operational impacts. Only change ownership if you are certain it’s required and understand the implications.
-
Retry Execution.
3. Inspect Shebang Line and Interpreter
While less likely to directly cause “Permission denied” on the script itself (more often “command not found”), an issue with the shebang or interpreter can prevent execution.
-
Check Shebang Line: The first line of your script should specify the interpreter.
head -1 /path/to/my_script.shExample Output:
#!/bin/bashEnsure this path is correct for your system. Common alternatives include
#!/usr/bin/env bashfor better portability, or#!/bin/shfor POSIX compliance. -
Verify Interpreter Existence and Permissions: Check if the specified interpreter exists and is executable.
which bash # Or `which python`, `which node`, etc. ls -l /bin/bash # Check permissions of the interpreter itselfThe interpreter itself (
/bin/bashin this example) must have execute permissions for all users (-rwxr-xr-xis typical). If it doesn’t, that’s a much larger system issue requiring root intervention. -
Alternative Execution Method: If the shebang or permissions are problematic, you can often explicitly tell Bash to interpret the script. This bypasses the shebang and the script’s execute permission, relying only on Bash having read access to the script.
bash /path/to/my_script.shIf this works, but
./my_script.shdoesn’t, the issue is definitely related to the script’s execute bit or its shebang.
4. Examine Filesystem Mount Options
If permissions are correct, the filesystem itself might be preventing execution.
-
Identify Mount Point: First, determine which filesystem the script resides on.
df -h /path/to/my_script.shThis will show the mount point (e.g.,
/home,/var/www,/tmp). -
Check Mount Options: Now, check the mount options for that specific mount point.
mount | grep /path/to/mount_pointExample Output indicating an issue:
/dev/sda2 on /tmp type ext4 (rw,nosuid,nodev,noexec,relatime)The presence of
noexecis the culprit here. -
Resolution:
- Move the script: The simplest solution is to move the script to a filesystem that does not have the
noexecoption (e.g.,/opt,/usr/local/bin, or your home directory if it’s notnoexec). - Remount (Temporary): You can remount the filesystem without
noexec(requiressudo):
This change is temporary and will revert after a reboot.sudo mount -o remount,exec /path/to/mount_point - Modify
/etc/fstab(Permanent): For a permanent change, edit/etc/fstabto removenoexecfrom the mount options for that partition.
Find the line corresponding to your mount point and changesudo nano /etc/fstabnoexectoexec. Example: From:
To:UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx /tmp ext4 defaults,noexec 0 2
After saving, apply changes with:UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx /tmp ext4 defaults,exec 0 2
Or reboot the system.sudo mount -a
[!WARNING] Modifying
/etc/fstabincorrectly can prevent your system from booting. Always back up/etc/fstabbefore making changes (sudo cp /etc/fstab /etc/fstab.bak). Removingnoexecfrom security-sensitive partitions like/tmpcan introduce vulnerabilities. Only do so if you fully understand the security implications. - Move the script: The simplest solution is to move the script to a filesystem that does not have the
5. SELinux or AppArmor Diagnostics (Advanced)
If all conventional permissions and mount options are correct, a Mandatory Access Control (MAC) system might be interfering.
-
Check SELinux Status:
sestatusIf SELinux is
enforcing, it might be the cause. -
Check for SELinux Denials in Audit Log:
sudo grep 'AVC' /var/log/audit/audit.log # Or, if auditd isn't running/configured, check dmesg: dmesg | grep 'SELINUX_AVC'Look for
deniedentries related to your script or the execution attempt. -
Restore SELinux Context: Sometimes, files get incorrect SELinux contexts, especially if moved or copied from different locations.
sudo restorecon -v /path/to/my_script.shThis command applies the default SELinux context to the file.
-
Check AppArmor Status:
sudo aa-statusIf AppArmor is enabled and profiles are loaded, it might be restricting execution.
-
AppArmor Logs: AppArmor denials are typically logged in
syslogordmesg.sudo grep 'apparmor="DENIED"' /var/log/syslog # Or: sudo dmesg | grep 'apparmor="DENIED"' -
Temporary SELinux/AppArmor Disablement (for testing):
[!WARNING] Temporarily disabling SELinux or AppArmor should only be done in a controlled testing environment and never on a production server without explicit understanding of the security risks. Re-enable them immediately after testing.
- SELinux Permissive Mode:
This switches SELinux tosudo setenforce 0permissivemode, where it logs denials but doesn’t block actions. If your script runs now, SELinux was the issue. Re-enable withsudo setenforce 1. - AppArmor (Disabling Profiles):
This is more complex and involves unloading or putting specific profiles into
complainmode. Refer to AppArmor documentation for details.
- SELinux Permissive Mode:
By methodically following these steps, you should be able to identify and rectify the root cause of the “Permission denied” error when executing your Linux shell scripts. Always prioritize understanding the underlying permissions model to ensure both functionality and security.
