Understanding file permissions

Published: February 02, 2021   |   Updated: March 17, 2021   |   Read time:


Open a terminal on a Unix system and run ls -Al. You might get something like this.

ls screenshot -100%

Even if you know very little about Unix-based operating systems, you could probably guess that each row corresponds to a file or directory and each column contains information about the file. The first column is pretty cryptic, but in this post I’ll break down what these letter stand for and how to work with the chmod command.

Users and groups

On Unix systems, you are a user and your user is part of a user group. You probably know what your username is, but you can find out more information about it.

# what's my username?
> whoami

# find out information about your user and what groups you belong to
> id
uid=1000(james) gid=1000(james) groups=1000(james),4(adm),20(dialout),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),117(netdev)

# list all the user groups you are a part of
> groups
james adm dialout cdrom floppy sudo audio dip video plugdev netdev

Users control files they own, and they can permit other users in the same group to access files that they choose. Going back to the ls -Al command, you can see the user that owns the file in column 3, and the group that file belongs to in column 4.

ls screenshot with user and group annotation -100%

How does the system know whether or not a user can access a file? It checks the file permissions of a file before a user can do anything with it.

File permissions

On a Unix system, you can interact with a file in three fundamental ways: read, write, and execute. These file modes, as they’re called, are abbreviated as r, w, and x, respectively. These modes are specified to allow or restrict certain users from doing things with certain files. These are the cryptic letters in the first column of the ls -Al output.

ls screenshot with user and group annotation -100%

This string of letters and dashes is a way of representing the file modes for each item listed. For some files, the letters are repeated, like .bash_logout which has three rs. You can also see that all the directories (rows with a blue label) have a d at the beginning of its file mode. The string can be broken down like so.

File mode structure -100%

Each of these letters acts like a binary TRUE or FALSE. A dash means that the action is not permitted. For example, .bash_history has the mode -rw-------. This means that it is a file, the owner (user james) can read it and write to it, but not run it as an executable. All users in the group james who are not the user james cannot do anything with this file, and neither can all other users on the system who are not part of the james group.

Similarly, .bash_logout has the mode -rw-r--r--. This means that it is a file, the owner (user james) can read it and write to it, but not run it as an executable. All users the group james who are not the user james can read it, but not write to it nor run it as an executable. The same holds for users who are not part of the james group.

A different representation of permissions

For a given directory or folder, let’s just concern ourselves with the permissions, the last 9 characters in the string. We can represent the permissions in a different way. If we consider the positions of the letters in the string, since the letters act like a binary TRUE or FALSE, let’s represent them with 1s and 0s (1 for TRUE, 0 for FALSE). .bash_history in this form would have a permission string of 110000000, and .bash_logout would have a permission string of 110100100.

We can make these strings shorter, in a clever way, by thinking with binary numbers. We have different permissions for the owner, the group, and others. If we break the permission string into 3 parts, we can represent the permission with a single 3-digit number. 110000000 becomes 110 000 000 and 110100100 becomes 110 100 100.

In binary, 110 is 6, 010 is 2, etc.

Counting in binary -40%

Our file permissions can then be represented as 600 for .bash_history and 644 for .bash_logout.

Permission conversion -100%

These multiple representations allow us to intuitively interact with files, or even change their permissions, based on short and simple codes.

Changing permissions

You can change permissions of a file you are the owner of using the chmod command. You can set the mode explicitly using either the numeric representation. You can also use the string representation by specifying which users you’re assigning the permission (u for user, g for group, o for other, and a for all) and the permission you want to add, remove, or set with +, -, and =, respectively.

> ls -Al .bash_history
-rw------- 1 james james 19096 Feb  2 16:49 .bash_history

# both these commands will make .bash_history readable by members of the `james` group
> chmod 640 .bash_history
> chmod g+r .bash_history

> ls -Al .bash_history
-rw-r----- 1 james james 19096 Feb  2 16:49 .bash_history

# all these commands will set the group read permission back to FALSE
> chmod 600 .bash_history
> chmod g-r .bash_history

> ls -Al .bash_history
-rw------- 1 james james 19096 Feb  2 16:49 .bash_history

Using the string representation avoids converting binary numbers in your head, and is often easier. Both representations are helpful though, and having both recognized by the same chmod command exemplifies the Unix philosophy of doing only one thing really well.

Changing groups

The less-mentioned twin to chmod is chgrp, which changes the group a file or directory belongs to. It’s less-mentioned because it’s less-used, but is still helpful when sharing access to files with other users. You can either specify the group by its numeric value or its name, which are listed in after groups= in the id command.

> chmod o-r .bash_history
> ls -Al .bash_history
-rw-r----- 1 james james 19096 Feb  2 16:49 .bash_history

> id
uid=1000(james) gid=1000(james) groups=1000(james),4(adm),20(dialout),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),117(netdev)

# both these commands change the group of `.bash_logout` from `james` to `sudo`
> chgrp 27 .bash_logout
> chgrp sudo .bash_logout

# now users in the `sudo` group can read `.bash_logout` whereas other users can't
> ls -Al .bash_history
-rw-r----- 1 james sudo 19096 Feb  2 16:49 .bash_logout

# changing it back to james
> chgrp james .bash_logout
> ls -Al .bash_history
-rw-r----- 1 james james 19096 Feb  2 16:49 .bash_history


File permissions are relatively simple, but essential for interacting with Unix systems. You can save yourself a lot of trouble by manually removing write permissions for certain files to stop them from being accidentally deleted. I use this for handling raw sequencing data, since the data is precious and hard to get those files back if lost. With this knowledge, hopefully you can better protect yourself and better share data with others.