The file is right there. It's not corrupted, and you're not missing a typo. Linux just hasn't been told this file is allowed to run — here's the one-line fix, and why sudo isn't it.
Adapted from the Command Line Essentials Companion Guide.
You write a script, save it, and try to run it:
$ ./deploy.sh
-bash: ./deploy.sh: Permission denied
The file is definitely there. cat deploy.sh prints it out fine. Nothing about the content is wrong. But the shell won't run it, and "Permission denied" sounds like something is badly broken — like the file itself is corrupted or off-limits. It isn't. It's missing one specific, easy-to-forget permission bit, and nothing else.
What's actually happening
Every file on a Linux (or macOS) system carries three separate permissions for three separate groups: the owner, the group, and everyone else. Each group can independently have read, write, and execute permission. ls -l shows this as a ten-character string:
$ ls -l deploy.sh
-rw-r--r-- 1 you staff 214 Sep 12 09:03 deploy.sh
Read that as three sets of three: rw- (owner: read, write, no execute), r-- (group: read only), r-- (everyone else: read only). Notice what's missing — there's no x anywhere in that string. The file is fully readable, which is why cat works and why the script's contents display just fine in an editor. But readable and executable are two completely different permissions, and creating a new file — via a text editor, touch, or copying one — doesn't grant execute permission by default. Nothing you did was wrong; that's simply not part of a new file's starting permissions.
Permission denied here isn't the system protecting something sensitive. It's the system accurately reporting that you haven't yet told it this particular file is meant to be run as a program.
The fix, step by step
Confirm this is actually the problem. Run
ls -lon the file and look for anxin the owner's permission set (the first three letters after the leading-). If it's not there, this is exactly what's happening.Add execute permission:
chmod +x deploy.sh
This adds execute permission for everyone the file's other permissions already allow — for a typical personal script, that's enough. Confirm it worked:
$ ls -l deploy.sh
-rwxr--r-- 1 you staff 214 Sep 12 09:03 deploy.sh
Now there's an x in the owner's set.
- Run it again the same way you did before:
./deploy.sh
No other change needed — the script's content was never the issue.
Two mistakes worth knowing about ahead of time
Reaching for sudo because "permission" sounds like an authority problem. sudo ./deploy.sh will not fix this — it re-runs the same command as another user, but the file still has no execute bit for anyone, so it fails the same way. sudo solves "you don't have rights to do this," not "this file hasn't been marked runnable yet." Those are genuinely different problems that happen to share the word "permission."
Forgetting the ./ and typing just deploy.sh. This produces a different error entirely — usually command not found — because the shell only searches directories listed in PATH for bare command names, and your current directory almost never is one of them. ./ explicitly means "run the file right here," which is what actually triggers the execute-permission check in the first place. If you're troubleshooting "permission denied" and you're not seeing that exact message, double check you're invoking the file the same way.
A habit that prevents the confusion entirely
Any time you write a new script you intend to run directly, chmod +x it in the same breath as saving it — before you ever try to run it the first time. Treat it as part of "finishing the script," not a fix you reach for after an error. Scripts you download or copy from elsewhere often already have execute permission preserved (or explicitly need it added once, on purpose) — but anything you create fresh with an editor starts without it, every time, and that's expected behavior, not a bug to work around.
If you'd like more posts like this sent straight to your inbox, subscribe to the newsletter.
Prefer to dig in yourself? The Command Line Essentials repo on GitHub has more free examples and exercises.
Top comments (0)