Skip to content

Permission Denied in Linux: How to Read ls -l and Use chmod

Why a script says Permission denied, how to read the rwx columns in ls -l, and how to fix it with chmod u+x or numeric modes such as 755 and 644.

Computing··7 min read

You've written a script, or downloaded one, and you try to run it:

$ ./hello.sh
bash: ./hello.sh: Permission denied

Nine times out of ten the file is fine and the fix is one command. But it's worth thirty seconds to see why, because the same few characters explain every "Permission denied" you'll meet. All the terminal output on this page comes from the practice shell in our Linux lessons, so you can type the same commands and get the same answers.

Step 1: Look with ls -l

ls -l (a lowercase L, for long) lists files with their details:

$ ls -l scripts
total 4
-rw-r--r-- 1 learner learner 128 Jan 12 09:00 hello.sh

The line has seven fields, in the order the POSIX standard for ls sets out:

Field Here Meaning
File mode -rw-r--r-- The type, then the permissions
Links 1 How many names point to this file
Owner learner The user who owns it
Group learner The group it belongs to
Size 128 Size in bytes
Date and time Jan 12 09:00 Last modified
Name hello.sh The file

The first field is the one that matters here.

Step 2: Read the ten characters

-rw-r--r-- is one character for the type and then three groups of three:

Characters Who Allowed
- (type) - is a regular file, d a directory
rw- user: the owner read and write
r-- group: members of the file's group read only
r-- others: everyone else read only

Each group always has the same three slots in the same order: r (read), w (write) and x (execute). A - in a slot means that permission is missing. So rw- is "read and write, but not execute".

For a directory the letters mean slightly different things. The GNU coreutils manual puts it this way: read lets you list the directory's contents, write lets you create and remove files in it, and execute lets you access the files inside it. That's why directories normally have x:

$ ls -ld scripts
drwxr-xr-x 2 learner learner 4096 Jan 12 09:00 scripts

Step 3: See why the script was refused

Look again at -rw-r--r--. There is no x anywhere, so nobody, not even the owner, may run the file as a program. When you type ./hello.sh, the shell asks the Linux kernel to execute it, and the kernel refuses: the execve manual page lists "Execute permission is denied for the file" as one of the causes of exactly this error (EACCES).

Notice what does work:

$ bash scripts/hello.sh
Hello from your first script!
Today is a good day to learn Linux.

Here the program being run is bash, which has x. It only needs to read hello.sh, and everyone has r. That's a handy check, but the proper fix is to give the script its x.

Step 4: Fix it with chmod u+x

chmod (change mode) takes three parts: who, an operator and the permissions.

  • Who: u (user/owner), g (group), o (others) or a (all three).
  • Operator: + adds, - removes, = sets exactly.
  • Permissions: any of r, w and x.

So u+x means "add execute for the owner":

$ cd scripts
$ chmod u+x hello.sh
$ ls -l hello.sh
-rwxr--r-- 1 learner learner 128 Jan 12 09:00 hello.sh
$ ./hello.sh
Hello from your first script!
Today is a good day to learn Linux.

The owner's group of three changed from rw- to rwx, and the script runs. A few more you'll use:

Command Result on a -rw-r--r-- file What it does
chmod a+x hello.sh -rwxr-xr-x Everyone may run it
chmod go-r notes.txt -rw------- Group and others can no longer read it
chmod u=rw,go=r notes.txt -rw-r--r-- Sets all nine at once, in letters

Step 5: Numeric modes (755, 644 and friends)

Instead of letters, chmod also takes three digits: one for the owner, one for the group and one for others. Each digit is a sum of:

Permission Value
read (r) 4
write (w) 2
execute (x) 1

So 7 = 4 + 2 + 1 = rwx, 6 = 4 + 2 = rw-, 5 = 4 + 1 = r-x, 4 = r-- and 0 = ---. The modes you'll see most:

Mode Letters Typical use
644 rw-r--r-- Ordinary files: you edit, everyone reads
600 rw------- Private files: only you read or write
755 rwxr-xr-x Scripts, programs and directories: you change, everyone runs or enters
700 rwx------ Private scripts or directories

In the practice shell:

$ chmod 600 diary.txt
$ chmod 755 scripts/deploy.sh
$ ls -l diary.txt scripts
-rw------- 1 learner learner 35 Jan 12 09:00 diary.txt

scripts:
total 4
-rwxr-xr-x 1 learner learner 45 Jan 12 09:00 deploy.sh

The digits aren't arbitrary: they're octal (base 8). Each octal digit is exactly three bits, one per slot, and the GNU manual describes the mode that way: rwx is binary 111, which is the digit 7. Write 755 in binary and the permissions appear as ones and zeros: 111 101 101, the same pattern as rwxr-xr-x. Our octal to binary converter, with 755 filled in, works it through digit by digit: 7 → 111, 5 → 101, 5 → 101.

Letters and numbers do the same job. Letters such as u+x change one thing and leave the rest alone; digits set all nine at once, which is quicker when you know the result you want.

When chmod isn't the answer

A few other things produce "Permission denied" or something close to it:

  • The file belongs to someone else. Only a file's owner (or the administrator, root) may change its mode. The chmod(2) manual page lists this as EPERM, and the command says so:

    $ ls -l /etc/passwd
    -rw-r--r-- 1 root root 84 Jan 12 09:00 /etc/passwd
    $ chmod 666 /etc/passwd
    chmod: changing permissions of '/etc/passwd': Operation not permitted
    

    For system files, use sudo for the one command that needs it, if you're allowed to, rather than changing the file's permissions.

  • A directory on the way is missing x. You can't reach a file inside a directory you can't enter. execve lists "search permission is denied on a component of the path prefix" as another cause of the same error.

    $ chmod u-x scripts
    $ cd scripts
    bash: cd: scripts: Permission denied
    
  • The disk doesn't allow programs. Some drives and partitions are mounted noexec, and nothing on them runs, whatever its mode. The execve page lists this too. Copy the script somewhere else, or run it with bash script.sh.

  • "command not found" instead. That's a different problem: typing hello.sh without a path makes the shell search its usual program directories. Give the path, ./hello.sh.

One answer to avoid: chmod 777. It does make the error go away, by letting every user on the machine change and run the file. That is almost never what you want.

Practise it

Two short lessons have a practice terminal in the page, set up with the files above, that checks your work as you type:

The command pages for chmod and ls list every option with an example to try. Nothing you type leaves your browser.

The short version

  1. ls -l file and read the first column: type, then owner, group and others, each rwx.
  2. A script needs x to run as ./script. Add it with chmod u+x script (or chmod 755 script).
  3. Digits are sums: read 4, write 2, execute 1. 644 for files, 755 for scripts and directories, 600 for private files.
  4. "Operation not permitted" means you don't own the file. Never reach for 777.

Sources

engineeringlinuxcommand linechmodpermissionsshell