Linux & Bash · Part I · Module 2 · The Filesystem and Paths
Reading ls -l: What the Long Listing Tells You
A plain ls answers one question: what names are in here. That is often not the question you have. Is this a file or a directory? Has it actually been written to, or is it empty? When did it last change? Who owns it, and may I touch it? One option answers all of those at once, and its output is the single most-read line of text in day-to-day Linux work. It is also dense, unlabelled, and routinely misread in three specific ways. This chapter takes one line apart field by field, says which fields mean exactly what they appear to, and is honest about which do not.
Foundation16 min readLinuxPart IFundamentalsFilesReading Output
Part I · Module 2 · Chapter 2.5 · Reading ls -l
1. Why the Plain Listing Is Not Enough
Chapter 2.4 used ls to see what is in a directory:
$ pwd
/home/engineer/project
$ ls
docs rtl scripts simFour names. And that is genuinely all you learn — not whether they are files or directories, not whether any of them is empty, not when they last changed, not whether you are allowed to open them.
Add one option and every one of those questions is answered at once:
$ ls -l
total 16
drwxr-xr-x 2 engineer engineer 4096 Mar 14 09:12 docs
drwxr-xr-x 2 engineer engineer 4096 Mar 14 09:12 rtl
drwxr-xr-x 2 engineer engineer 4096 Mar 14 09:12 scripts
drwxr-xr-x 3 engineer engineer 4096 Mar 18 16:40 simThe -l is for long: one entry per line, with details. Chapter 1.5 taught how to read the command itself — ls is the command name and -l is a short option. This chapter is about reading what came back.
2. One Line, Seven Fields
Take a single line and separate it:
-rw-r--r-- 1 engineer engineer 482 Mar 14 09:12 alu.sv
│ │ │ │ │ │ └── 7. name
│ │ │ │ │ └──────────────── 6. last modified
│ │ │ │ └───────────────────── 5. size in bytes
│ │ │ └────────────────────────────── 4. group
│ │ └─────────────────────────────────────── 3. owner
│ └────────────────────────────────────────── 2. link count
└────────────────────────────────────────────────────── 1. type + permissionsSeven facts, printed side by side with no headings. The columns are separated by spaces, so they line up only because ls pads them — and they stop lining up the moment one entry has a much longer name or a much bigger size.
The rest of this chapter is those seven fields, in order.
3. Field 1a: the Type Character
The very first character of the line says what kind of thing this is. It is the fastest, most useful character in the whole listing.
| Character | Kind of thing |
|---|---|
- | an ordinary file |
d | a directory |
l | a symbolic link — a name that points at another path |
c or b | a device, of the kind that lives under /dev |
s or p | two ways processes talk to each other |
In practice you will see -, d and l, and the first two constantly.
$ ls -l
drwxr-xr-x 2 engineer engineer 4096 Mar 14 09:12 docs
-rw-r--r-- 1 engineer engineer 482 Mar 14 09:12 notes.txtdocs begins with d, so it is a directory. notes.txt begins with -, so it is an ordinary file. That is more dependable than colour, which Chapter 2.4 warned is configured rather than guaranteed, and more dependable than the name — nothing requires a directory to lack a dot in its name or a file to have one.
Symbolic links get a full treatment in Module 6. For now, recognising the l is enough; such a line also shows where the link points, with an arrow after the name.
4. Field 1b: the Permission String
The next nine characters describe who may do what.
rw-r--r--Read them as three groups of three:
rw- r-- r--
│ │ └── everyone else
│ └──────── members of the group
└────────────── the ownerWithin each group the three positions are always in the same order — read, write, execute — and a letter means allowed while a dash means not allowed.
So rw-r--r-- reads: the owner may read and write; the group may read; everyone else may read. Nobody may execute it.
A script that can be run looks different:
$ ls -l scripts
total 4
-rwxr-xr-x 1 engineer engineer 128 Mar 14 09:12 run.shThe x characters are the execute permission. Chapter 2.3 explained that ./run.sh tells the shell which file; this field is the other half — whether it is allowed to run at all. A file missing its x produces Permission denied rather than command not found, which is exactly the distinction Chapter 2.3 drew.
5. Field 2: the Link Count
A small number, usually 1 for a file:
-rw-r--r-- 1 engineer engineer 482 Mar 14 09:12 alu.sv
↑It counts how many names point at this same data. One file, one name, count of 1 — the ordinary case.
Directories show a larger number, and the reason is a detail you already know. Chapter 2.3 established that . and .. are real entries that genuinely exist. Each of those is a name, so each is counted. A directory therefore starts at 2 — its own name in its parent, plus the . inside it — and grows as subdirectories are added, because each subdirectory contains a .. that points back.
$ ls -l
drwxr-xr-x 2 engineer engineer 4096 Mar 14 09:12 rtl
drwxr-xr-x 3 engineer engineer 4096 Mar 18 16:40 simrtl holds two files and no subdirectories, so its count is 2. sim holds one subdirectory, logs, so its count is 3.
Notice what this does not count: rtl contains two files and the number is still 2. The count is about names pointing at this directory, not about what is inside it.
Module 6 is where names and data are separated properly. The reason to know the field now is to stop reading it as "how many things are inside" — it is not, and the number will mislead you if you do.
One honesty note: the arithmetic above is how the common Linux filesystems count. A few filesystems, including the one macOS uses, count directory links differently, so a directory there can show a larger number. The meaning of the field — names pointing at this thing — is the same everywhere.
6. Fields 3 and 4: Owner and Group
-rw-r--r-- 1 engineer engineer 482 Mar 14 09:12 alu.sv
↑ ↑
owner groupEvery file has an owner — normally the user who created it — and a group. Together with the permission string they decide what any given person may do.
Chapter 1.4's id command printed your user name and your groups. The connection is direct: if the owner column matches your name, the first group of three permission characters applies to you. If instead you are a member of the listed group, the second applies. Otherwise the third.
That is enough to read a line. Module 5 is where it becomes something you can act on.
7. Field 5: Size
-rw-r--r-- 1 engineer engineer 482 Mar 14 09:12 alu.sv
↑For an ordinary file this is the size in bytes, and it means exactly what you expect. It is the quickest way to answer "did anything actually get written?" — a size of 0 means an empty file.
$ ls -l sim/logs
total 0
-rw-r--r-- 1 engineer engineer 0 Mar 18 16:40 run.logThat log exists and is empty. A program created it and wrote nothing. Knowing the difference between absent and present but empty is worth a surprising amount of debugging time.
Bytes get hard to read quickly once numbers grow, so there is an option for that:
$ ls -lh rtl
total 8
-rw-r--r-- 1 engineer engineer 482 Mar 14 09:12 alu.sv
-rw-r--r-- 1 engineer engineer 1.2K Mar 14 09:12 counter.sv-h is for human-readable: sizes are rounded and suffixed with K, M or G. Chapter 1.5's rule applies — -l and -h are two short options, and ls -lh is the same request as ls -l -h, combined by ls itself.
8. Field 6: the Timestamp
-rw-r--r-- 1 engineer engineer 482 Mar 14 09:12 alu.sv
↑This is when the file's contents were last changed — not when it was created, and not when it was last read.
It is more useful than it sounds, because it answers a question you will ask constantly: is this the output of the run I just did, or something left over from yesterday?
The default format has an oddity worth knowing. Recent files show a time; older files show a year instead:
$ ls -l
-rw-r--r-- 1 engineer engineer 482 Mar 14 09:12 alu.sv
-rw-r--r-- 1 engineer engineer 1024 Nov 3 2025 old_notes.txtalu.sv changed recently enough to be shown with a time. old_notes.txt is old enough that the year is more useful than the minute. Nothing is wrong; the column simply switches format.
If you would rather have one unambiguous format, GNU ls offers one:
$ ls -l --time-style=long-iso
-rw-r--r-- 1 engineer engineer 482 2026-03-14 09:12 alu.sv
-rw-r--r-- 1 engineer engineer 1024 2025-11-03 15:41 old_notes.txtEvery line now carries a full date and time, in an order that sorts correctly as text. This is a long option in Chapter 1.5's sense, and it is a GNU extension — it is not available on BSD-derived systems including macOS, where the equivalent is spelled differently. Chapter 1.6's rule applies: check the manual on the machine you are on.
Sorting by time is often what you actually want:
$ ls -lt sim/logs-t sorts newest first. Combined with -l it answers "what changed most recently here" in one command. Two companions worth knowing: -S sorts by size, and -r reverses whatever order is in effect.
9. Field 7: the Name
Last, and the only one that needs no explanation — except for one thing it does not tell you.
A name does not determine a file's type. A directory can be called notes.txt and an ordinary file can be called rtl. Nothing prevents it. The type character in field 1 is the authority; the name is a convention people follow for their own convenience.
10. The total Line
Every long listing of a directory starts with one:
$ ls -l rtl
total 8
-rw-r--r-- 1 engineer engineer 482 Mar 14 09:12 alu.sv
-rw-r--r-- 1 engineer engineer 1228 Mar 14 09:12 counter.svtotal 8 is not a count of entries, and not the sum of the size column. It is the amount of disk space the listed files occupy, measured in blocks — and the size of a block depends on the system.
It is rarely the number you want. Mentioned here only so that it stops being mysterious: two files, total 8, and neither 2 nor 1710 appears anywhere.
11. Listing a Directory Itself
A trap worth meeting deliberately. Ask for a long listing of a directory and you get its contents:
$ ls -l rtl
total 8
-rw-r--r-- 1 engineer engineer 482 Mar 14 09:12 alu.sv
-rw-r--r-- 1 engineer engineer 1228 Mar 14 09:12 counter.svBut sometimes you want the line about rtl — its own permissions, its own owner, its own timestamp. The option for that is -d:
$ ls -ld rtl
drwxr-xr-x 2 engineer engineer 4096 Mar 14 09:12 rtlOne line, describing the directory rather than looking inside it. Read it with §3: the leading d confirms it is a directory, and everything after is about rtl itself.
This is the fastest way to answer "who owns this directory and may I write in it" — a question that comes up constantly on shared machines.
12. Putting It Together
A listing with one of everything, read end to end:
$ pwd
/home/engineer/project
$ ls -l
total 16
drwxr-xr-x 2 engineer engineer 4096 Mar 14 09:12 docs
drwxr-xr-x 2 engineer engineer 4096 Mar 14 09:12 rtl
drwxr-xr-x 2 engineer engineer 4096 Mar 14 09:12 scripts
drwxr-xr-x 3 engineer engineer 4096 Mar 18 16:40 simFour directories, all leading with d. sim has a link count of 3 and the others 2, so sim is the only one with a subdirectory — which matches the module's tree, where sim holds logs. sim also has the newest timestamp. All four are owned by engineer and readable by everyone.
Now one level down:
$ ls -l scripts
total 4
-rwxr-xr-x 1 engineer engineer 128 Mar 14 09:12 run.shAn ordinary file (-), executable by everyone (x in all three groups), owned by engineer, 128 bytes, one name pointing at it. Chapter 2.3's ./run.sh would work on this file: it has the execute permission that cd-adjacent chapter said you would need.
And the empty case:
$ ls -l sim/logs
total 0No lines at all after total. The directory exists — otherwise there would be an error — and it contains nothing. Again: exists and is empty is a different fact from does not exist, and the two have different fixes.
13. Misconceptions and Limits
"The size column tells me how big a directory is." It does not, per §7. That needs du, in Module 28.
"The link count is how many files are inside." It is not, per §5. It counts names pointing at the directory itself.
"The timestamp is when the file was created." It is when the contents last changed. Linux traditionally does not record a creation time in a way ls shows.
"A .txt file is a text file." The name is a convention. Field 1 tells you file-or-directory; what is actually inside a file is answered by the file command, which Chapter 4.7 covers.
"The columns always line up, so a script can read them." This is the one with teeth. ls output is designed for people, and it breaks as input to other programs: a file name containing a space makes the columns ambiguous, and names can contain almost any character. Every experienced engineer has seen a script break on a file called run log.txt.
When you need a list of files for a program to act on, the right tool is find, which Module 14 teaches, together with the option that makes the output unambiguous. Use ls -l to look; use something else to automate.
14. Practice
Read each line and answer from the listing alone.
drwxr-xr-x 3 engineer engineer 4096 Mar 18 16:40 sim
-rw-r--r-- 1 engineer engineer 0 Mar 18 16:41 run.log
-rwxr-xr-x 1 engineer engineer 2048 Mar 14 09:12 build.sh
-rw-rw-r-- 1 engineer design 8192 Mar 17 11:05 shared_notes.txt
lrwxrwxrwx 1 engineer engineer 18 Mar 18 09:00 currentQuestion 1. Which of the five is a directory, and which character told you?
Question 2. run.log exists. Did the program that created it write anything? Which field answers that, and what is the value?
Question 3. Which entries could be run as a program, and which field shows it?
Question 4. shared_notes.txt has a group of design rather than engineer. If you are a member of the design group but not the owner, which group of three permission characters applies to you, and what may you do?
Question 5. sim has a link count of 3 while the other directories in this module's tree have 2. What does that tell you about sim?
Question 6. You want to see the permissions and owner of sim itself rather than what is inside it. Write the command.
Question 7. Why would it be a mistake to use the size column to decide whether sim is worth deleting to free space, and which chapter covers the right tool?
15. Remember
ls -lprints seven facts per line: type and permissions, link count, owner, group, size, timestamp, name.- The first character is the type.
-is a file,dis a directory,lis a symbolic link. This is more reliable than colour or than the name. - The nine permission characters are three groups of three — owner, group, everyone else — each in read, write, execute order. Reading them is this chapter; changing them is Module 5.
- The link count is names pointing at the thing, not contents. A directory starts at 2 because
.and..are real entries, and grows with each subdirectory. - Size in bytes is exact for a file and misleading for a directory. A size of 0 means an empty file, which is a different fact from a missing one.
-hmakes sizes readable;-tsorts by time;-ddescribes the directory instead of listing it.- The timestamp is last modified, not created, and the format switches to a year for older entries.
totalis disk blocks, not a count and not a byte sum.lsoutput is for people. Do not have a program read it; file names can contain spaces, and Module 14'sfindexists for that job.
One field in this listing has gone unexplained: why ls showed four entries when Chapter 2.3 proved that every directory also contains . and ... The next chapter answers that, and introduces the files you have not been shown yet.
Where this fits
Part of the Linux & Bash curriculum.
