# 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 . .. .android .atom .bash_aliases [...] $ ls -A .android .atom .bash_aliases [...] ``` With many good UNIX tools, there's the tradition of saving backup files by appending some special character to the name of the file being saved. For instance, in Vim, backups get saved with the ``~`` character appended to the name. These kinds of backup files have saved me from stupid mistakes on several occasions, but after years of enjoying the sense of security they provide, I don't feel the need to have visual evidence that they exist. I trust Linux applications to generate backup files (if they claim to do so), and I'm happy to take it on faith that they exist. To hide backup files from view, use the ``-B`` or ``--ignore-backups`` to conceal common backup formats. This option is not available in BSD ``ls``. ``` $ ls bar.xfc baz.txt foo.asc~ foo.asc $ ls -B bar.xfc baz.txt foo.asc ``` Of course, the backup file still exists, it's just filtered out so you don't have to look at it. GNU Emacs saves backup files (unless otherwise configured) with a hash character (``#``) at the start and end of the file name (``#file#``). Other applications may use a different style. It doesn't matter what pattern is used, because you can create your own exclusions with the ``--hide`` option: ``` $ ls bar.xfc baz.txt #foo.asc# foo.asc $ ls --hide="#*#" bar.xfc baz.txt foo.asc ``` ## Listing directories with recursion The contents of directories are not listed with the ``ls`` command unless you run ``ls`` on that directory specifically: ``` $ ls -F example/ quux* xyz.txt $ ls -R quux xyz.txt ./example: bar.xfc baz.txt #foo.asc# foo.asc ``` ## Making it permanent with an alias The ``ls`` command is probably the command used most often during any given shell session. It's your eyes and ears, providing you with context and confirming results of commands. While it's useful to have lots of options, part of the beauty of ``ls`` is its brevity: two characters and the *Return* key, and you know exactly where you are and what's near by. If you have to stop to think about, much less type, several different options, it becomes less convenient and so typically even the most useful options are just left off. The solution is to alias your ``ls`` command so that when you do use it, you get the information you care about most. To create an alias for a command in the Bash shell, create a file in your home directory called ``.bash_aliases`` (you must include the dot at the beginning). In this file, list the command you want to create an alias for, and then the alias you want to create. For example: ``` alias ls='ls -A -F -B --human --color' ``` This line causes your Bash shell to interpret the ``ls`` command as ``ls -A -F -B --human --color``. You aren't limited to redefining existing commands. You can create your own aliases: ``` alias ll='ls -l' alias la='ls -A' alias lh='ls -h' ``` For aliases to work, your shell must know that the ``.bash_aliases`` configuration file exists. Open the ``.bashrc`` file in an editor (or create it, if it doesn't exist), and include this block of code: ``` if [ -e $HOME/.bash_aliases ]; then source $HOME/.bash_aliases fi ``` Each time ``.bashrc`` is loaded (which is any time a new Bash shell is launched), Bash will load ``.bash_aliases`` into your environment. You can close and re-launch your Bash session, or just force it to do that now: ``` $ source ~/.bashrc ``` If you forget whether you have aliased a command, the ``which`` command tells you: ``` $ which ls alias ls='ls -A -F -B --human --color' /usr/bin/ls ``` If you've aliased the ``ls`` command to itself with options, you can override your own alias at any time by prefacing ``ls`` with a back-slash. For instance, in the example alias, backup files are hidden using the ``-B`` option, which means there's no way to backup files with the ``ls`` command. Override the alias to see the backup files: ``` $ ls bar baz foo $ \ls bar baz baz~ foo ``` ## Do one thing and do it well The ``ls`` command has a staggering number of options, many of which are niche or highly dependent upon the terminal you use. Take a look at ``info ls`` on GNU systems, or ``man ls`` on GNU or BSD systems for more options. You might find it strange that a system with famous the premise that each tool "does one thing and does it well" would weigh down its most common command with 50 options. But ``ls`` does only one thing: it lists files. And with 50 options to allow you to control how you receive that list, ``ls`` does its one job very *very* well.