bash: ./script.sh: Permission denied means the file has no execute bit, so the shell refuses to run it as a program. Run chmod +x script.sh once and ./script.sh works.

If you only want to run it this once, bash script.sh ran the same file without the bit in the test below, with exit code 0.

The error

ls -l script.sh
-rw-r--r-- 1 root root 41 Nov  6 07:54 script.sh
bash -i -c './script.sh'
...
bash: ./script.sh: Permission denied
exit code: 126

Why it happens

The permissions column of ls -l reads -rw-r--r--: read and write for the owner, read for everyone else, and no x anywhere. The file was created with printf ... > script.sh, and a newly created file had no execute bit in this test. Running it as ./script.sh asks the system to execute the file, which it refused; bash reported Permission denied and exit code 126. The message looks like a user problem, but the file belonged to the user running it (root, here). What was missing was the execute permission on the file itself.

The text before the colon names who reported it. Typed at a prompt it starts with bash:; when the same line runs inside another script it starts with that script's name and line number, as in /tmp/rest.sh: line 22: ./script.sh: Permission denied.

The fix

chmod +x script.sh
ls -l script.sh
-rwxr-xr-x 1 root root 41 Nov  6 07:50 script.sh
./script.sh
Hello from the script
exit code: 0

chmod +x added the x for owner, group and others, and the same command printed the script's output with exit code 0. Without changing the file, bash script.sh also worked:

bash script.sh
Hello from the script
exit code: 0

The chmod route is the one to keep for a script you run often or call from other scripts. The bash script.sh route is handy for a one-off run.

How it was reproduced

The capture was made in an ubuntu:24.04 container (Ubuntu 24.04.5 LTS, GNU bash 5.2.21, Docker Engine 29.9.2) standing in for Ubuntu in WSL. A two-line script (#!/bin/bash and an echo) was written with printf, then run with bash -i -c './script.sh' to get the message as an interactive shell prints it, and again from inside another script. Both gave exit code 126; after chmod +x script.sh both printed Hello from the script with exit code 0.

Frequently asked

How do I fix bash ./script.sh Permission denied in Ubuntu WSL?
Give the file the execute bit with chmod +x script.sh and run ./script.sh again. In the test the permissions changed from -rw-r--r-- to -rwxr-xr-x and the script ran with exit code 0.
Can I run a shell script without chmod +x?
Yes. bash script.sh ran the same file without the execute bit and printed its output with exit code 0.
What does exit code 126 mean in bash?
In this test bash returned 126 when ./script.sh was refused with Permission denied because the file had no execute bit.

More decoded errors in the Fixes category. If the execute bit is set and the script still fails with "cannot execute: required file not found", see the CRLF line endings post.