Fixing ‘Permission Denied’ for Shell Scripts in WSL2 Ubuntu
Resolve 'Permission Denied' errors when running shell scripts in WSL2 Ubuntu. Learn how file permissions, line endings, and filesystem mounts impact execution.
Resolve 'Permission Denied' errors when running shell scripts in WSL2 Ubuntu. Learn how file permissions, line endings, and filesystem mounts impact execution.
When working with development environments on Windows Subsystem for Linux 2 (WSL2), particularly Ubuntu distributions, encountering a "Permission Denied" error when attempting to execute a shell script is a common hurdle. This issue typically arises when scripts are created, modified, or stored on the Windows host filesystem (e.g., within /mnt/c/Users/YourUser/Scripts/) and then executed from within the WSL2 environment. Understanding the interplay between Linux POSIX permissions, Windows NTFS characteristics, and WSL2's filesystem mounting mechanisms is key to resolving this.
Symptom & Error Signature
Users typically experience this issue directly at the command line when attempting to run a script, often with ./ prefix.
# Attempting to execute a script directly
./my_script.sh
The primary error signature will be:
bash: ./my_script.sh: Permission denied
In some cases, especially if the script was created or heavily edited in a Windows text editor, you might also encounter a "bad interpreter" error, which often indicates an issue with line endings or the shebang:
# Secondary error due to incorrect line endings or shebang
./my_script.sh
bash: ./my_script.sh: /bin/bash^M: bad interpreter: No such file or directory
Root Cause Analysis
The "Permission Denied" error for shell scripts in WSL2 Ubuntu primarily stems from a combination of the following factors:
Missing Execute Permissions: In Linux, a file must have the execute bit (
x) set in its permission mask for the owning user, group, or others to be directly executable. If this bit is absent (e.g.,rw-r--r--), the shell cannot execute the script directly, leading to a permission error.WSL2 Filesystem Mount Options (NTFS Limitations): When files reside on a Windows filesystem mounted into WSL2 (e.g.,
/mnt/c/), the native NTFS filesystem does not inherently support full Linux POSIX permissions (like the execute bit). WSL2 handles this by translating permissions or by requiring specific mount options.- By default, if the
metadataoption is not enabled for automounted drives in/etc/wsl.conf,chmod +xmight not persistently apply the execute bit, or the defaultumaskapplied during mounting might strip it. - The
metadataoption, when enabled, allows WSL2 to store Linux-specific metadata (including permissions, ownership, and timestamps) as hidden NTFS alternate data streams (ADS) or reparse points, makingchmodoperations effective and persistent on Windows files. Without it, the effective permissions are derived from theumask,fmask, anddmaskoptions, which by default often deny execute permissions for files.
- By default, if the
Incorrect Line Endings: Windows uses Carriage Return and Line Feed (
CRLF, orrn) for line endings, while Linux uses only Line Feed (LF, orn). A script created or saved on Windows withCRLFendings, when executed in Linux, can confuse thebashinterpreter, especially on the shebang line (#!). The^Mcharacter (representingr) can be interpreted as part of the interpreter path, leading to "bad interpreter" or "No such file or directory" errors for the shebang.Missing or Incorrect Shebang Line: The shebang (
#!) at the very beginning of a script tells the operating system which interpreter (e.g.,bash,python) should be used to execute the script. If the shebang is missing, malformed, or points to an interpreter not available at that path, the system won't know how to run the script.
Step-by-Step Resolution
Follow these steps to diagnose and resolve the "Permission Denied" error for shell scripts in your WSL2 Ubuntu environment.
1. Verify and Add Execute Permissions
The most common cause is simply the absence of the execute permission bit.
Check current permissions: Use
ls -lto inspect the file's permissions.ls -l my_script.shAn output like
-rw-r--r--indicates that the owner has read/write permissions, but not execute.Add execute permission: Use
chmodto add the execute bit for the owner, or for all users if appropriate.# Add execute permission for the file owner chmod u+x my_script.sh # Or, add execute permission for owner, group, and others (common for scripts) chmod +x my_script.sh # Or, set specific permissions like rwxr-xr-x (owner rwx, group rx, others rx) chmod 755 my_script.shVerify permissions again: Confirm the change with
ls -l. You should now see anxin the permission string (e.g.,-rwxr-xr-x).ls -l my_script.shIf
chmod +xappears to work but the execute bit (x) does not persist after re-checking withls -l(or the script still gives "Permission Denied"), this strongly indicates a deeper issue related to WSL2's handling of permissions on Windows-mounted filesystems. Proceed to Step 4.
2. Check and Correct Shebang Line
Ensure your script has a correct shebang line.
Inspect the shebang: View the first line of your script using
head.head -n 1 my_script.shIt should typically look like
#!/bin/bashor#!/usr/bin/env bash.Correct the shebang (if necessary): If the shebang is missing or incorrect, edit your script to include it.
#!/bin/bash: Direct path to the bash interpreter. This assumesbashis at/bin/bash.#!/usr/bin/env bash: More portable.envfindsbashin the system's PATH.
# Example for nano editor nano my_script.sh # Add or correct the first line: #!/bin/bash
3. Address Line Ending Issues
Scripts created or edited on Windows often have CRLF line endings, which Linux interpreters don't handle well.
Detect CRLF line endings: Use
cat -vEto show control characters.^Mindicates a carriage return.cat -vE my_script.shLook for
^Mcharacters, especially at the end of the shebang line or other lines.Convert to LF line endings: The
dos2unixutility is the simplest and most robust way to convert line endings.# Install dos2unix if you don't have it sudo apt update && sudo apt install -y dos2unix # Convert the script dos2unix my_script.shAlternatively, using
sed:sed -i 's/r$//' my_script.shOr within
vi/vim:vi my_script.sh :set ff=unix :wq
4. Configure WSL2 Mount Options for Windows Drives (Persistent Fix)
If chmod +x doesn't stick for scripts on your Windows drive (e.g., /mnt/c/), you need to enable Linux metadata support for that drive in WSL2.
Edit
wsl.conf: Open thewsl.conffile in your WSL2 distribution usingnanoorvi.sudo nano /etc/wsl.confAdd/Modify
[automount]section: Ensure the[automount]section includesmetadata = true. This tells WSL2 to store Linux file metadata (like permissions, owner, group) directly on the NTFS filesystem.[automount] enabled = true root = /mnt/ options = "metadata"If you have existing
umask,fmask, ordmaskoptions under[automount], themetadataoption typically overrides or takes precedence for permission handling, makingchmodeffective. You generally wantmetadataenabled for consistent permission behavior.Save and Exit: Save the
wsl.conffile.Shut down and restart WSL2: For changes in
wsl.confto take effect, you must completely shut down and restart the WSL2 instance. Open PowerShell (as administrator is not required forwsl --shutdown) on Windows:wsl --shutdownThen, restart your WSL2 distribution by opening a new Ubuntu terminal.
Re-apply execute permissions: Navigate back to your script location in the WSL2 terminal and re-apply the execute permission:
cd /mnt/c/path/to/your/script chmod +x my_script.sh ls -l my_script.sh # VerifyThe execute bit should now persist, and the script should run without "Permission denied."
5. Move Script to WSL2 Filesystem (Workaround/Best Practice)
For scripts that are purely for Linux operations and don't need direct Windows access, storing them within the WSL2 filesystem itself (e.g., in your home directory ~/ or /usr/local/bin/) is often the simplest and most robust solution, as it inherently uses native Linux permissions.
Copy the script: Move the script from your Windows-mounted drive to a location within your WSL2 home directory.
cp /mnt/c/path/to/my_script.sh ~/my_script.shAdd execute permissions (if necessary): Permissions should behave normally here.
chmod +x ~/my_script.shExecute:
~/my_script.shIf you frequently edit scripts using Windows-based IDEs or text editors, ensure they are configured to save files with LF (Unix) line endings to prevent issues, even when working on files within the WSL2 filesystem (accessed via
\wsl$Ubuntu-22.04homeyouruser).
6. Run with an Interpreter Directly (Temporary Bypass)
As a temporary measure or for quick testing, you can explicitly tell bash to interpret the script, bypassing the file's execute permissions. This does not fix the underlying permission issue but can help isolate the problem.
bash my_script.sh
Our Production Verification Guarantee
Encountering a bug not covered here or running a non-standard kernel configuration? Our solutions are continually refined against real production incidents. Submit an environment trace for our editorial team to replicate.