ls Command in Linux: 17 Useful Examples Explained


The ls command is one of the first commands we learn when discovering the shell. And after that, whatever is your skill level, it will remain one of the most often used.

Despite that popularity, we rarely go beyond the -l, -d and -a options. It is unfortunate since a typical ls implementation has tens of options available! I, therefore, propose you to follow me in my search for the ls command hidden gems.

Sample file hierarchy we use in this ls command guide

Before getting to the heart of the matter, we need a little bit of preparation: it would be hard to study the ls command without some directory to work on. So that you will be able to try on your computer the commands given in this article, here is how to create the sample file hierarchy I will use in all my examples. Just copy-paste that list of commands to your terminal, and you will be ready:

If you have any trouble with these commands, don’t hesitate to use the comment section to ask for some help. Assuming now everything is in order, it is time to dive into our main topic.

The well-known use cases of ls command

As every journey starts with a first step, let’s review first the very basic use cases for the ls command. Of course, if you consider yourself as an expert, feel free to jump immediately to the more advanced sections. But if you prefer staying with me for now, great: you might learn a thing or two!

<no option>: the default behavior

The ls command gives information about each file-like objects pointed by the paths given on the command line. When used without any option:

  • the only information displayed is the name of the file-like object pointed by the path;

  • if that path points to a directory (or symbolic link to a directory), the ls command also lists the content of that directory;

  • if several entries are displayed, they are sorted in the alphabetical order of their filename.

Finally, when no path is given on the command line, the ls commands assumes ./–that is the current directory.

Let see now all those rules in action:

-d: do not list directory content

With the -d option, ls no longer displays the content of the directory given on the command line but instead will treat directory entries just like file entries. Let’s compare:

When using the -d option alone, there isn’t much difference between ls and a plain echo command:

But the -d option becomes more useful when associated with another option to display extra information, like when using the -l flag we will see now.

-l: the long format option

In the ls options popularity contest, the -l (lowercase ell letter) option would probably be the winner. It’s so useful that many systems offer an ll alias for ls -l (or ls -l<something>)

The -l stands for the long format. With that option, the ls command will display each entry on its own line containing the following information: * file mode * number of links * owner name * group name * number of bytes in the file * date and time * pathname

Also, with the -l option, ls will no longer follow symbolic links. So, it will display the information (file mode, number of links and so on) about the link itself, and not about its destination. For the same reason, the ls command will not display the content of directories pointed by symbolic links:

To conclude this section, I let you examine the output we obtain by combining both the -l and -d options:

-a: display all files

With the -a option, ls includes hidden files when displaying the content of a directory. But what is a hidden file?

By convention, on Unix-like systems, a file whose name is starting by a dot is considered as hidden. In addition, each directory also contains two special, normally hidden, entries: . and ..

In each directory:

  • the . entry points to the directory itself. That kind of self-reference may seem curious. But it is sometimes useful, a bit like having your own phone number into your smartphone repertory.

  • the .. entry points to the parent directory. Since the file hierarchy on Unix-like systems is strictly organized as a tree, each directory has one and only one parent. Except the root directory / maybe? Well, not really: the parent of the root directory is … the root directory itself.

The useful options of ls command

After having reviewed the well known -l, -d and -a options, let’s turn our attention on a couple of lesser-known options I find particularly useful.

-s: display allocated size

You may remember the -l option displayed the number of bytes in the file. The -s option displays the allocated size in blocks. What’s a block? Well, a group of bytes whose size is implementation dependent. It is usually 512 bytes on BSD and 1024 bytes on Linux.

Why would I bother with size in blocks when I already have access to the size in bytes? Well, the -s options display the allocated size. Not the logical size of the file. Those may be two completely different things for sparse files. Sparse files are files that contain “holes”. When read, those holes behave like normal file blocks containing only zeros. But they take virtually no space on the disk. We can use the dd command with the seek option to create sparse files as I did it for the b file in my sample hierarchy:

As you can see, both my a and b files appear to be two mebibytes long. But the b file being sparse, it takes only 1028 blocks on the disk (roughly one mebibyte).

-h display human-readable sizes

With the -h option, ls will display file sizes using unit suffixes to make them more user-friendly. This option is only meaningful when used in combination with the -l option (Linux, BSD) or -s (Linux):

You may have noticed sizes are displayed using powers of 1024 units, where K stands for 2^10=1024 bytes, M for 1024^2=1048576 bytes and so on. Worth mentioning here the ls implementation provided as part of the GNU Coreutils has an extra --si options to use power 1000 instead of powers of 1024:

-i display inode number

On a Unix-style filesystem, an inode number (or file serial number in the POSIX terminology) is a number that uniquely identifies a filesystem object (a file, a directory, a named pipe, … ). With the -i option, the ls command will display its inode number alongside each path.

Even if it seems somewhat exotic, I find myself using the -i option from time to time, especially to identify directory entries that are referencing the same filesystem object. You will use that option mostly when investigating hard links or bind mounts. Take a look at that video for a practical example:

In the example above, you can see each filename prefixed by the inode number associated with that path. On your system, the numbers will surely differ. Anyway, take a closer look at the hardlink-to-file and dir/e entries. Both have the same inode number (8264 in my case). That means they are two entries referencing the same underlying filesystem object— which is, in fact, the exact definition of what is a hard link.

You may remember I said earlier the parent of the root directory was the root directory itself. By using the -i option, it is quite easy to verify that assertion:

As you can see, on my system, the root directory is associated with the inode number 2, which is also the inode of its parent. So that proves the root directory is its own parent.

The rarely used options of ls command

I regularly use the options described in the previous section, but those I will talk about now… well… I know they exists. However I must admit when I need them, I often have to look at the man to refresh my memory.

This option modify the behavior of the ls command when applied to symbolic links. With the -L option, ls will display the information about to the target of the symbolic link instead of displaying those related to the symbolic link itself. By examining the following example, the difference will be obvious:

-F: append a classification character to the filename

The -F option adds an extra character after the pathname of some categories of file system objects to identify them. It will add:

  • a after each pathname that is a directory,

  • a @ after each pathname that is a symbolic link,

  • a * after each executable file,

  • and a | after each FIFO (see mkfifo for more information about that)

In my early Unix days, I used that option a lot. But since ls can colorize its output (and since we have color monitors!), I rarely need that. But I remember it. And from time to time, on a remote terminal, I find an occasion to use it:

t: sort entries by modification time

With the -t option, the ls command with display directory entries sorted by modification time (most recent first) instead of sorting them by their name:

If I change a file, it will now appear as the first (ie: most recently modified) entry in the list:

-S: sort entries by size

With the -S option, ls will display entries sorted by size, largest file first. In case of a tie, the entries are sorted according to their pathname:

-r: reverse sort order

This option reverses the sort order. I find it most useful when associated with the -t option to have the least recently modified file displayed first or with the -S option to display the smallest file first. But it also works with the default, by pathname, sort order:

-n: Display numeric UID/GID

This option is exactly the same as the -l option— except with -n the owner’s group id (GID) and user id (UID) are displayed as numbers rather than using their associated name:

The really exotic usage of ls command

No one can claim to know everything. And while writing this article, I (re-)discovered a couple of ls options. I can’t remember having used them myself, but maybe did you? If it is the case, I would be curious to read in the comment section in which circumstances you find them useful. Anyway, here is a selection that you might find interesting.

-R: recursively list subdirectories

By default, the ls command only display the content of the directories explicitly given on the command line. With the -R option, it will also recursively display the content of the directories encountered:

While intersting in theory, I find (pun intended) the output produced by the find . command more readable for that purpose. But your mileage may vary, of course:

-A: display almost all files

While not defined in the POSIX standard, the -A options appear both in the GNU and BSD world. In both cases, it works like -a, but excluding the . and .. entries. Worth mentioning on BSD systems, -A is implied for the superuser:

-f: do not sort

With the -f option, ls will display entries in the order in which they appear in the directory. That order is dependent on the underlying filesystem, and the order files were created, so it is hardly predictable. The -f option also implies the -a option:

Amusingly enough, with the GNU Coreutils 8.26 ls implementation, you can use both the -l and -f options if you spell it -fl–but not if you write -lf. On OpenBSD both are working as expected:

-q: Display non-printable filename characters as ?

On Unix-style filesystems, a filename may contain any character except the and the NUL characters. This means a filename may contain unprintable characters or even control sequences that may interfere with your terminal. Let’s try something amusing:

Obviously, that filename contains non-printable characters. On modern implementations of ls, the -q option is implied when the output is a terminal, to avoid potential nefarious effects. So the non-printable characters will be replaced by a question mark:

However, things will be different if you write that instead:

The | cat is useless, but as a side effect, the ls command now sees a pipe on its standard output instead of a tty (a “terminal”). Since the output is no longer a terminal, the -q option is no longer implied, and ls will display the filename verbatim. In that case, if all works as expected, to present the file name with a funky video effect.

Explicitly using the -q option would fix that. I will let you try that by yourself (and eventually playing with other ANSI escape sequences). But I take that occasion to warn you against using the ls command in shell scripts. In practice, ls is designed for “human consumption”. There are many side cases regarding specially crafted filenames that are very difficult to handle properly. If you need to walk through a list of files, I strongly encourage you to use the find command instead. In the simplest cases, a simple for loop is even sufficient— but that would be another story.

The end?

So that concludes our tour of the ls command options. No need to mention it was far from being exhaustive and I tried to focus here on the most useful and most portable options. But each ls implementation has its share of cool features, so if you know some nice option I missed in this article, don’t hesitate to share that with us using the comment section. If we have enough feedbacks, we may even compile and publish them in a follow-up article!


Facebook Comments

Show More

Related Articles

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to top button