# The secrets of ls
by Seth Kenlon

The ``ls`` command lists files on a [POSIX](LINK TO MY POSIX ARTICLE) system. It's a simple command, often underestimated not in what it can do (because it really does only one thing), but in how you can optimize your use of it.

Of the 10 most essential terminal commands to know, the humble ``ls`` command is the top 3, because ``ls`` doesn't *just* list files, it tells you important information about them. It tells you things like who owns a file or directory, when each file was lost modified, and it can even tell you what kind of file it is. And then there's its incidental function of giving you a sense of where you are, what nearby objects are lying around, and what you can do with them.

If your experience with ``ls`` has been limited to whatever your distribution aliases it to in ``.bashrc``, then you're probably missing out.


## GNU or BSD

Before looking at the hidden powers of ``ls``, you must determine which ``ls`` command you're running. The two most popular versions are the GNU version, included in the GNU **coreutils** package, and the BSD version. If you're running Linux, then you probably have ``ls`` installed. If you're running BSD or MacOS, then you have the BSD version. There are differences, for which this article accounts.

You can find out which version is on your computer with the ``--version`` option:

```
$ ls --version
```

If this returns information about GNU coreutils, then you have the GNU version. If it returns an error, you're probably running the BSD version (run ``man ls | head`` to be certain).

You should also investigate what presets your distribution may have put in place for you. Customizations to terminal commands are frequently placed in ``$HOME/.bashrc`` or ``$HOME/.bash_aliases`` or ``$HOME/.profile``, and they're accomplished by aliasing ``ls`` to a more complex ``ls`` command. For example:

```
alias ls='ls --color'
```

The presets provided by distributions are very helpful, but they do make it difficult to discern what ``ls`` does on its own, and what its additional options provide. Should you ever want to run ``ls`` and not the alias, you can "escape" the command with a back-slash:

```
$ \ls
```

## Classify

Run on its own, ``ls`` simply lists files in as many columns as can fit into your terminal.

```
$ ls ~/example
bunko        jdk-10.0.2
chapterize   otf2ttf.ff
despacer     overtar.sh
estimate.sh  pandoc-2.7.1
fop-2.3      safe_yaml
games        tt
```

It's useful information, but all of those files look basically the same without the convenience of icons to quickly convey which is a directory, or a text file, or an image, and so on.

Use the ``-F`` (or ``--classify`` on GNU) to show indicators after each entry, identifying the kind of file it is:

```
$ ls ~/example
bunko         jdk-10.0.2/
chapterize*   otf2ttf.ff*
despacer*     overtar.sh*
estimate.sh   pandoc@
fop-2.3/      pandoc-2.7.1/
games/        tt*
```

With this option, items listed in your terminal are classified by file type, using this shorthand:

* A slash (``/``) denotes a directory (or "folder").
* An asterisk (``*``) denotes an executable file. This includes a binary file (compiled code) as well as scripts (text files that have been given [executable permission](https://opensource.com/article/19/6/understanding-linux-permissions)).
* An at sign (``@``) denotes a symbolic link (or "alias").
* An equals sign (``=``) denotes a socket.
* On BSD, a percent sign (``%``) denotes a whiteout (a method of file removal on certain file systems).
* On GNU, an angle bracket (``>``) denotes a door (inter-process communication on [Illumos](https://www.illumos.org/) and Solaris).
* A vertical bar (``|``) denotes a FIFO.

A simpler version of this option is ``-p``, which only differentiates a file from a directory.

## Long list

Getting a "long list" from ``ls`` is so common that many distributions alias ``ll`` to ``ls -l``. The long list form provides many important file attributes, such as permissions, the user who owns each file, the group to which the file belongs, the file size in bytes, and the date the file was last changed.

```
$ ls -l
-rwxrwx---. 1 seth users         455 Mar  2  2017 estimate.sh
-rwxrwxr-x. 1 seth users         662 Apr 29 22:27 factorial
-rwxrwx---. 1 seth users    20697793 Jun 29  2018 fop-2.3-bin.tar.gz
-rwxrwxr-x. 1 seth users        6210 May 22 10:22 geteltorito
-rwxrwx---. 1 seth users         177 Nov 12  2018 html4mutt.sh
[...]
```

If you don't think in bytes, add the ``-h`` flag (or ``--human`` in GNU) to translate file sizes to a more human-friendly notation.

```
$ ls --human
-rwxrwx---. 1 seth users    455 Mar  2  2017 estimate.sh
-rwxrwxr-x. 1 seth seth     662 Apr 29 22:27 factorial
-rwxrwx---. 1 seth users    20M Jun 29  2018 fop-2.3-bin.tar.gz
-rwxrwxr-x. 1 seth seth    6.1K May 22 10:22 geteltorito
-rwxrwx---. 1 seth users    177 Nov 12  2018 html4mutt.sh
```

You can see just a little less information by showing only the owner column with ``-o`` or only the group column with ``-g``:

```
$ ls -o
-rwxrwx---. 1 seth    455 Mar  2  2017 estimate.sh
-rwxrwxr-x. 1 seth    662 Apr 29 22:27 factorial
-rwxrwx---. 1 seth    20M Jun 29  2018 fop-2.3-bin.tar.gz
-rwxrwxr-x. 1 seth   6.1K May 22 10:22 geteltorito
-rwxrwx---. 1 seth    177 Nov 12  2018 html4mutt.sh
```

Combine both options to show neither.

## Time date format

The long list format of ``ls`` usually looks like this:

```
-rwxrwx---. 1 seth users         455 Mar  2  2017 estimate.sh
-rwxrwxr-x. 1 seth users         662 Apr 29 22:27 factorial
-rwxrwx---. 1 seth users    20697793 Jun 29  2018 fop-2.3-bin.tar.gz
-rwxrwxr-x. 1 seth users        6210 May 22 10:22 geteltorito
-rwxrwx---. 1 seth users         177 Nov 12  2018 html4mutt.sh
```

The names of months aren't easy to sort, both computationally or, depending on whether your brain tends to prefer strings or integers, by recognition. You can change the format of the time stamp with the ``--time-style`` option, plus the name of a format. Available formats are:

* full-iso (1970-01-01 21:12:00)
* long-iso (1970-01-01 21:12)
* iso (01-01 21:12)
* locale (uses your locale settings)
* posix-STYLE (replace STYLE with a locale definition)

You can also create a custom style using the format notation of the ``date`` command.

## Sort by time

Normally, the ``ls`` command sorts alphabetically. You can make it sort according to which file was most recently changed (the newest is listed first) with the ``-t`` option.

For example:

```
$ touch foo bar baz
$ ls
bar  baz  foo
$ touch foo
$ ls -t
foo bar baz
```

## List type

The normal output of ``ls`` balances readability with space-efficiency, but sometimes you want your file list in a specific arrangement.

For a comma-separated list of files, use ``-m``:

```
ls -m ~/example
bar, baz, foo
```

To force one file per line, use the ``-1`` option (that's the number one, not a lowercase L):

```
$ ls -1 ~/bin/
bar
baz
foo
```

To sort entries by file extension rather than my file name, use ``-X`` (a capital X):

```
$ ls
bar.xfc  baz.txt  foo.asc
$ ls -X
foo.asc  baz.txt  bar.xfc
```

## Hiding the clutter

There are a few entries in some ``ls`` listings that you may not care about. For instance, the meta-characters ``.`` and ``..`` represent "here" and "back one level", respectively. If you're familiar with navigating in a terminal, you probably already know that each directory refers to itself as ``.``, and to its parent as ``..``, so you don't need to be constantly reminded of it when you use the ``-a`` option to show hidden files.

To show almost all hidden files (the ``.`` and ``..`` excluded), use the ``-A`` option.

```
$ ls -a