# Listing and paths

---

# Listing and paths

_Peios / Using Peios / Peiosutils / Listing and paths_

> The commands that show you what a directory contains and that inspect, resolve, and manipulate path names — ls, stat, pwd, readlink, realpath, and the rest.

Before you can do anything with a file you usually have to *find* it — see what a directory holds, learn one file's details, turn a relative name into an absolute one. This topic covers the commands for that: listing directories, inspecting a single file, and resolving path names.

This page names every command in the topic, says in one line what each is for, and points you at the page that covers it in full.

## The commands

| Command | Purpose |
|---|---|
| [`ls`](/peios/using-peios/peiosutils/listing-and-paths/ls.md) | List the contents of a directory. The everyday command for "what's in here?". |
| [`dir` and `vdir`](/peios/using-peios/peiosutils/listing-and-paths/dir-and-vdir.md) | `ls` with a fixed output style. `dir` lists in columns; `vdir` lists in long format. |
| [`stat`](/peios/using-peios/peiosutils/listing-and-paths/stat.md) | Show the detailed status of one file — its type, size, timestamps, and raw inode metadata. |
| [`pwd`](/peios/using-peios/peiosutils/listing-and-paths/pwd.md) | Print the directory you are currently working in. |
| [`readlink`](/peios/using-peios/peiosutils/listing-and-paths/readlink.md) | Print where a symbolic link points. |
| [`realpath`](/peios/using-peios/peiosutils/listing-and-paths/realpath.md) | Resolve a path to its canonical, absolute form — every symlink followed, every `.` and `..` removed. |
| [`basename`](/peios/using-peios/peiosutils/listing-and-paths/basename.md) | Strip the directory part off a path, leaving just the final name. |
| [`dirname`](/peios/using-peios/peiosutils/listing-and-paths/dirname.md) | The opposite of `basename` — strip the final name, leaving the directory. |
| [`pathchk`](/peios/using-peios/peiosutils/listing-and-paths/pathchk.md) | Check whether a path name is valid and portable before you try to create it. |
| [`dircolors`](/peios/using-peios/peiosutils/listing-and-paths/dircolors.md) | Produce the colour settings that `ls` uses when it colours its output. |

## These commands and file security

Most commands in this topic work purely on path strings — they never touch the file the path names. `basename`, `dirname`, `realpath`, and `pathchk` are all string operations.

Two report on real files, and they relate to file security differently:

- **`ls -l` surfaces security-descriptor information directly.** On Peios a file's access is governed by its **security descriptor** — the record of who owns the file and who may do what to it. The long listing shows the owner and the parts of the descriptor that fit in a one-line-per-file format.
- **`stat` is a low-level diagnostic.** It dumps the raw contents of a file's inode. The inode carries some numeric fields — an owner id, a group id, a mode value — that the Peios access model does **not** consult. `stat` reports them because it reports the inode verbatim, but they are not the file's access policy.

Neither command prints the full security descriptor; inspecting that is a job for the dedicated security tooling. If a line of `ls -l` looks unfamiliar, or you want to know why `stat` shows fields that "don't count", the explanation is in [Security descriptors](/peios/security-fundamentals/security-descriptors/overview.md).

## Where to start

If you want the everyday "what's in this directory" command and the meaning of every column it prints, read [`ls`](/peios/using-peios/peiosutils/listing-and-paths/ls.md).

If you need the full detail of one specific file, read [`stat`](/peios/using-peios/peiosutils/listing-and-paths/stat.md).

If you are writing a script and need to take a path apart or canonicalise it, the string commands — [`basename`](/peios/using-peios/peiosutils/listing-and-paths/basename.md), [`dirname`](/peios/using-peios/peiosutils/listing-and-paths/dirname.md), [`realpath`](/peios/using-peios/peiosutils/listing-and-paths/realpath.md) — are what you want.

---

# ls

_Peios / Using Peios / Peiosutils / Listing and paths_

> List the contents of a directory — the default listing, the Peios long format and its security-descriptor columns, and the sorting and formatting options.

`ls` lists the contents of a directory. It is the command you use to answer "what is in here?" — and, with the right options, "who owns these files, how big are they, and when were they last changed?".

```
ls [options] [file...]
```

Each `file` is a directory to list the contents of, or a single file to report on. With no `file` argument, `ls` lists the directory you are currently in.

```
$ ls
build.sh  notes.txt  projects
```

## The default listing

Run on its own, `ls` prints the names of the entries in a directory and nothing else. Three rules shape that default:

- **Hidden entries are skipped.** A name beginning with a dot (`.config`, `.cache`) is hidden. `ls` leaves hidden entries out unless you ask for them with [`-a` or `-A`](#choosing-what-to-list).
- **Entries are sorted by name.** Alphabetical order, case-sensitive. Other [sort orders](#sorting) are available.
- **The layout adapts to where output goes.** When `ls` is writing to a terminal it arranges names into columns sized to the terminal width. When output is redirected to a file or a pipe it prints one name per line, so the result is easy for another program to read.

Everything past this default is opt-in. The rest of this page is the options, grouped by what they do.

## The long format

`-l` (or `--long`) switches `ls` into the **long format**: one entry per line, each with its mode, owner, size, modification time, and name.

```
$ ls -l
total 28
d-- S-1-5-21-9f3a-1c4e-7b20-1001   4096 May 14 09:12 projects
-x- S-1-5-21-9f3a-1c4e-7b20-1001   8344 May 16 17:40 build.sh
--- S-1-5-21-9f3a-1c4e-7b20-1001    219 May 15 11:03 notes.txt
--+ S-1-5-18                      12048 May 10 22:15 policy.db
```

The `total` line at the top reports the combined disk space used by the listed files, measured in blocks.

Each entry line has five columns: **mode**, **owner**, **size**, **modification time**, **name**. There is no permission-bits column and no group column — the reason is below.

### The mode column

The mode column is three characters: `[type][executable][protected]`.

The **first character** is the file's type:

| Character | Type |
|---|---|
| `-` | Regular file |
| `d` | Directory |
| `l` | Symbolic link |
| `p` | Named pipe (FIFO) |
| `s` | Socket |
| `c` | Character device |
| `b` | Block device |

The **second character** is the executable mark. It is `x` when the entry is a regular file that is marked as an executable, and `-` otherwise (it is always `-` for directories, links, and other non-regular entries).

The executable mark describes the *file*, not your relationship to it. `x` means "this file is runnable code." It does **not** mean that you, specifically, are allowed to run it — whether a given principal may execute a file is a separate access decision made against the file's security descriptor. A file can show `x` and still be one you cannot run, and the reverse. See [Access decisions](/peios/security-fundamentals/access-decisions/overview.md) for how execution is actually authorised.

The **third character** is the protected mark. It is `+` when the file's access control is **inheritance-protected**, and `-` otherwise.

A `-` here means the file's access control is inherited from the directory it lives in: it tracks its parent. A `+` means the file's access control has been set deliberately and locked, so it no longer tracks the parent directory. The `+` is the signal that someone has tailored this file's security on purpose. See [Inheritance](/peios/security-fundamentals/security-descriptors/inheritance.md).

So in the example above: `projects` is a directory (`d--`); `build.sh` is an executable file (`-x-`); `notes.txt` is an ordinary file inheriting its security from its directory (`---`); and `policy.db` is an ordinary file whose access control has been protected (`--+`).

### Why there are no permission bits

A long listing does not carry a fixed block of permission characters. On Peios, what a principal may do to a file is decided by the file's **security descriptor** — a record that can contain any number of entries granting or denying specific rights to specific principals. There is no small, fixed set of bits that captures that, so `ls -l` does not pretend there is.

The mode column tells you the file's *type* and two *facts about it* (is it executable, is its security protected). To see *who may do what*, look at the security descriptor itself with [`stat`](/peios/using-peios/peiosutils/listing-and-paths/stat.md) or the dedicated security tooling. The concepts are in [Security descriptors](/peios/security-fundamentals/security-descriptors/overview.md).

### The owner column

The owner column is the **SID** of the file's owner — shown in full, in the `S-1-…` form. `ls` does not translate SIDs into account names; it prints the identifier exactly as the security descriptor stores it. A well-known owner such as the system itself appears as its fixed SID (`S-1-5-18`); an ordinary account appears as a longer domain-style SID.

For what a SID is and how to read one, see [SIDs](/peios/security-fundamentals/identity/sids.md). For what "owner" means and what it grants, see [Ownership](/peios/security-fundamentals/security-descriptors/ownership.md).

If `ls` cannot read a file's descriptor — for a dangling symlink, say — the owner column shows `?` and the mode column shows the type character followed by `??`.

## Choosing what to list

By default `ls` shows non-hidden entries, and for a directory argument it shows the directory's *contents*. These options change that.

| Option | Effect |
|---|---|
| `-a`, `--all` | Show hidden entries too, including `.` (the directory itself) and `..` (its parent). |
| `-A`, `--almost-all` | Show hidden entries, but leave out `.` and `..`. |
| `-d`, `--directory` | List a directory as an entry in its own right, instead of listing its contents. Useful with `-l` to see a directory's own owner and mode. |
| `-R`, `--recursive` | Descend into every subdirectory and list it too. |
| `-B`, `--ignore-backups` | Skip entries whose name ends in `~`. |
| `--ignore=PATTERN` | Skip entries whose name matches the shell pattern. May be given more than once. |
| `--hide=PATTERN` | Like `--ignore`, but overridden by `-a` or `-A` — so a hide rule can be cancelled by asking to see everything. |

## Sorting

`ls` sorts by name by default. These options change the sort key; `-r` reverses whatever order is in effect.

| Option | Sort order |
|---|---|
| `-t` | By modification time, newest first. |
| `-S` | By size, largest first. |
| `-X` | By file extension, alphabetically. |
| `-v` | By version: runs of digits in the name sort numerically, so `f2` comes before `f10`. |
| `-U` | No sorting at all — entries appear in the order the directory stores them. Fast for very large directories. |
| `-r`, `--reverse` | Reverse the current sort. |
| `--sort=WORD` | Choose the sort key by name: `none`, `time`, `size`, `extension`, `version`, or `width`. |
| `--group-directories-first` | List directories before other entries, with each group sorted normally. |

## Output layout

When several entries fit on a line, `ls` has to decide how to arrange them.

| Option | Layout |
|---|---|
| `-C` | Columns, filled top-to-bottom. The default when writing to a terminal. |
| `-x` | Columns, filled left-to-right (across the rows) instead. |
| `-1` | One entry per line. The default when output is not a terminal. |
| `-m` | All entries on as few lines as possible, separated by commas. |
| `-l`, `--long` | The long format described above. |
| `--format=WORD` | Choose the layout by name: `across`, `commas`, `horizontal`, `long`, `single-column`, or `vertical`. |
| `-w`, `--width=COLS` | Assume the terminal is `COLS` columns wide instead of detecting it. `0` means unlimited. |

## File-type indicators and colour

These options make a listing easier to scan by marking entries with a symbol or a colour.

| Option | Effect |
|---|---|
| `-F`, `--classify` | Append a type symbol to each name: `/` for a directory, `@` for a symlink, `\|` for a FIFO, `=` for a socket, and `*` for an executable file. |
| `--file-type` | The same, but without the `*` on executables. |
| `-p` | Append only the `/` on directories. |
| `--indicator-style=WORD` | Choose the indicator set: `none`, `slash`, `file-type`, or `classify`. |
| `--color[=WHEN]` | Colour entries by type. `WHEN` is `auto` (colour only when writing to a terminal — the usual choice), `always`, or `never`. |

The colours `ls` uses are configurable. [`dircolors`](/peios/using-peios/peiosutils/listing-and-paths/dircolors.md) generates the colour settings and explains how to install them.

## File sizes

In the long format, and with `-s`, sizes are printed in bytes by default. These options rescale them.

| Option | Effect |
|---|---|
| `-h`, `--human-readable` | Print sizes with a unit suffix — `4.0K`, `234M`, `56G` — using powers of 1024. |
| `--si` | Like `-h`, but using powers of 1000, so the suffixes are decimal. |
| `-s`, `--size` | Print the disk space each entry occupies, in blocks, before its name. |
| `-k`, `--kibibytes` | Use 1024-byte blocks for the size figures and directory totals. |
| `--block-size=SIZE` | Scale every size by `SIZE` (for example `--block-size=1M` to count in megabytes). |

## Timestamps

The long format shows the modification time by default. These options change which timestamp is shown — and, when sorting by time, which one is sorted on.

| Option | Timestamp |
|---|---|
| `-u` | Access time — when the file was last read. |
| `-c` | Status-change time — when the file's metadata last changed. |
| `--time=WORD` | Choose the timestamp by name: `atime`/`access`, `ctime`/`status`, `mtime`/`modification`, or `birth`/`creation`. |
| `--time-style=STYLE` | Choose the date format: `full-iso`, `long-iso`, `iso`, `locale`, or `+FORMAT` for a custom layout. |
| `--full-time` | Shorthand for the long format with `--time-style=full-iso` — a complete, unabbreviated timestamp. |

## Symbolic links

By default `ls` reports on a symbolic link itself — its type is `l`, its size is the length of the link text. These options make it report on the link's *target* instead.

| Option | Effect |
|---|---|
| `-L`, `--dereference` | Always report on the file a link points to, not the link. |
| `-H`, `--dereference-command-line` | Dereference only the links named directly on the command line, not links found inside a listed directory. |
| `--dereference-command-line-symlink-to-dir` | Dereference a command-line link only when it points to a directory. |

[`readlink`](/peios/using-peios/peiosutils/listing-and-paths/readlink.md) and [`realpath`](/peios/using-peios/peiosutils/listing-and-paths/realpath.md) are the dedicated tools for inspecting and resolving links.

## Other options

The long-tail options, each in one line.

| Option | Effect |
|---|---|
| `-i`, `--inode` | Print each entry's index number (its inode number). |
| `-Z`, `--context` | Print each entry's security context. Available only when the build enables it. |
| `-b`, `--escape` | Print non-printable characters in names using C-style backslash escapes. |
| `-q`, `--hide-control-chars` | Replace non-printable characters in names with `?`. The default when writing to a terminal. |
| `--show-control-chars` | Print names verbatim, control characters and all. |
| `-N`, `--literal` | Print names exactly, with no quoting. |
| `-Q`, `--quote-name` | Wrap each name in double quotes. |
| `--quoting-style=WORD` | Choose the quoting scheme: `literal`, `shell`, `shell-always`, `shell-escape`, `c`, `escape`, and others. |
| `-T`, `--tabsize=COLS` | Assume tab stops every `COLS` columns when laying out output. |
| `-f` | List everything, unsorted, including hidden entries — equivalent to `-aU`. Also turns colour off unless `--color` is given explicitly. |
| `--hyperlink[=WHEN]` | Emit terminal hyperlinks for file names, so a capable terminal can make them clickable. |
| `-D`, `--dired` | Emit extra position markers designed for the Emacs *dired* editing mode. |
| `--zero` | End each line with a NUL character instead of a newline, and list one entry per line. |

## Exit status

| Code | Meaning |
|---|---|
| `0` | Success — everything requested was listed. |
| `1` | A minor problem — for example, a named file could not be accessed. The rest of the listing still printed. |
| `2` | A serious problem — for example, a directory could not be read, or an option was invalid. |

---

# dir and vdir

_Peios / Using Peios / Peiosutils / Listing and paths_

> Two commands that list directory contents with a fixed output style — dir always lists in columns, vdir always lists in long format.

`dir` and `vdir` list the contents of a directory. They are [`ls`](/peios/using-peios/peiosutils/listing-and-paths/ls.md) with one decision already made for you: the output style is fixed instead of adapting to where the output is going.

```
dir [options] [file...]
vdir [options] [file...]
```

## What they fix

`ls` chooses its layout based on whether it is writing to a terminal — columns for a terminal, one name per line for a pipe or file. `dir` and `vdir` each pick one layout and always use it:

| Command | Layout | Equivalent `ls` |
|---|---|---|
| `dir` | Columns, regardless of where output goes. | `ls -C` |
| `vdir` | Long format, regardless of where output goes. | `ls -l` |

Both also default to a quoting style that escapes unusual characters in names without wrapping every name in quotes.

That is the *only* difference. The fixed style is just a default — pass an explicit format option (`-1`, `-m`, `-l`, `-C`, …) and it overrides the built-in choice, so `dir -l` produces a long listing and `vdir -C` produces columns.

## Everything else is `ls`

`dir` and `vdir` accept every option `ls` accepts and behave identically in every other respect — sorting, filtering, the long-format columns, colour, indicators, sizes, timestamps. `vdir`'s long format is the same Peios long format documented for `ls`, with the `[type][executable][protected]` mode column and the owner SID.

For the full option set and the meaning of every long-format column, see [`ls`](/peios/using-peios/peiosutils/listing-and-paths/ls.md). This page exists only to explain how `dir` and `vdir` differ from it — and the answer is "they pin the output style."

## Exit status

The same as `ls`:

| Code | Meaning |
|---|---|
| `0` | Success. |
| `1` | A minor problem — a named file could not be accessed. |
| `2` | A serious problem — a directory could not be read, or an option was invalid. |

---

# stat

_Peios / Using Peios / Peiosutils / Listing and paths_

> Display the detailed status of a file or a file system — type, size, timestamps, and raw inode metadata — with an optional custom output format.

`stat` displays the detailed status of a file. Where [`ls`](/peios/using-peios/peiosutils/listing-and-paths/ls.md) gives you a line per file, `stat` gives you everything the system records about *one* file: its type, its size, its timestamps, and the low-level metadata stored in its inode.

```
stat [options] file...
```

`stat` is a diagnostic tool. It dumps what a file's inode physically contains, verbatim. That makes it the right command for "tell me exactly what is recorded about this file" — and it means some of what it prints needs a word of explanation, below.

## The default output

With no options, `stat` prints a labelled, multi-line block per file:

```
$ stat notes.txt
  File: notes.txt
  Size: 219             Blocks: 8          IO Block: 4096   regular file
Device: 8,2     Inode: 1572931     Links: 1
Access: (0644/-rw-r--r--)  Uid: ( 1000/    jack)   Gid: ( 1000/    jack)
Access: 2026-05-15 11:03:42.000000000 +0000
Modify: 2026-05-15 11:03:42.000000000 +0000
Change: 2026-05-15 11:03:18.000000000 +0000
 Birth: 2026-05-15 11:03:18.000000000 +0000
```

Reading it line by line:

- **File** — the name, and for a symbolic link, what it points to.
- **Size / Blocks / IO Block / type** — the size in bytes, the number of allocated disk blocks, the preferred I/O block size, and the file type in words.
- **Device / Inode / Links** — the device the file lives on, its inode number (its unique index within that device), and the number of hard links to it.
- **Access / Uid / Gid** — a numeric owner id, a group id, and a mode value. See the caveat below — these are not the access policy.
- **Access / Modify / Change / Birth** — four timestamps: when the file was last read, last written, last had its metadata changed, and first created.

## The Uid, Gid, and mode fields are decorative

The `Access: (0644/-rw-r--r--)  Uid: (…)  Gid: (…)` line needs care.

A file's inode carries a numeric owner id, a numeric group id, and a mode value, and `stat` reports them because `stat` reports the inode verbatim. But **the Peios access model does not consult these fields.** What a principal may do to a file is decided by the file's **security descriptor** — see [Security descriptors](/peios/security-fundamentals/security-descriptors/overview.md). The numbers on the `Uid`/`Gid`/mode line are inert metadata: they are stored, they are reported, and they have no effect on any access decision.

Do not read that line as a permission summary. A file showing `0644` is not "world-readable" in any meaningful sense — whether anyone can read it depends entirely on its security descriptor. `stat` shows these fields for completeness as a low-level diagnostic; it does not claim they mean anything.

To see the parts of a file's security that *do* count, use [`ls -l`](/peios/using-peios/peiosutils/listing-and-paths/ls.md), which shows the owner SID and the mode column built from the security descriptor.

## Custom output formats

Two options replace the default block with output you control.

| Option | Effect |
|---|---|
| `-c FORMAT`, `--format=FORMAT` | Print `FORMAT` for each file, substituting `%` directives. A newline is added after each file. |
| `--printf=FORMAT` | Like `--format`, but interpret backslash escapes (`\n`, `\t`) in `FORMAT` and add no trailing newline. Include `\n` yourself if you want one. |

```
$ stat --format='%n is %s bytes' notes.txt
notes.txt is 219 bytes
```

### File directives

Used in the format string when stating files (the default mode):

| Directive | Substitutes |
|---|---|
| `%n` | File name. |
| `%N` | Quoted file name; for a symlink, with the target shown. |
| `%F` | File type in words (`regular file`, `directory`, …). |
| `%s` | Total size, in bytes. |
| `%b` | Number of allocated blocks. |
| `%B` | Size in bytes of each block counted by `%b`. |
| `%o` | Preferred I/O transfer block size. |
| `%i` | Inode number. |
| `%h` | Number of hard links. |
| `%d` / `%D` | Device number, in decimal / in hexadecimal. |
| `%t` / `%T` | For a device file, the major / minor device type, in hexadecimal. |
| `%m` | Mount point of the file system the file is on. |
| `%f` | Raw mode value, in hexadecimal. |
| `%x` / `%X` | Last access time — human-readable / seconds since the epoch. |
| `%y` / `%Y` | Last modification time — human-readable / seconds since the epoch. |
| `%z` / `%Z` | Last status-change time — human-readable / seconds since the epoch. |
| `%w` / `%W` | File creation (birth) time — human-readable / seconds since the epoch. `-` or `0` if unknown. |

The directives `%a` and `%A` (the mode in octal and in symbolic form) and `%u`, `%U`, `%g`, `%G` (the owner and group, numeric and by name) report the decorative inode fields described above. They are available for completeness; they are not the file's access policy.

The `%C` directive (security context) is inactive — it produces no meaningful value on a standard Peios system.

### File-system directives

With `-f`, `stat` reports on the *file system* a file lives on rather than the file itself, and the format string uses a different directive set:

| Directive | Substitutes |
|---|---|
| `%n` | File name. |
| `%i` | File-system ID, in hexadecimal. |
| `%t` / `%T` | File-system type — in hexadecimal / in words. |
| `%l` | Maximum length of a file name. |
| `%s` | Block size, for fast transfers. |
| `%S` | Fundamental block size, used for the block counts. |
| `%b` | Total data blocks in the file system. |
| `%f` | Free blocks. |
| `%a` | Free blocks available to an ordinary principal. |
| `%c` | Total inodes (file nodes). |
| `%d` | Free inodes. |

## Options

| Option | Effect |
|---|---|
| `-f`, `--file-system` | Report on the file system containing each file, instead of the file. |
| `-L`, `--dereference` | Follow symbolic links — report on the link's target rather than the link itself. |
| `-t`, `--terse` | Print the information on a single line, as bare values with no labels. Useful for scripts. |

## Exit status

| Code | Meaning |
|---|---|
| `0` | Every file was stated successfully. |
| `1` | A file could not be stated, or an option or format directive was invalid. |

---

# pwd

_Peios / Using Peios / Peiosutils / Listing and paths_

> Print the absolute path of the directory you are currently working in.

`pwd` — "print working directory" — prints the absolute path of the directory you are currently in.

```
pwd [options]
```

```
$ pwd
/home/jack/projects
```

Every process has a working directory: the directory that relative path names are interpreted against. `pwd` tells you what yours is.

## Physical and logical paths

There are two honest answers to "where am I", and they differ only when symbolic links are involved.

Suppose `/home/jack/work` is a symbolic link pointing at `/data/projects/jack`, and you move into it. The **physical** path — the real location, with every link resolved — is `/data/projects/jack`. The **logical** path — the route you took to get there — is `/home/jack/work`.

| Option | Path printed |
|---|---|
| `-P`, `--physical` | The physical path: every symbolic link resolved to its target. |
| `-L`, `--logical` | The logical path: the route recorded as you navigated, taken from the `PWD` environment variable when it is accurate. |

By default `pwd` prints the **physical** path — `-P` is the default, and naming it explicitly just makes that choice visible. Use `-L` when you want the path as you navigated it, links and all.

If `-L` is requested but the recorded `PWD` value is missing or does not actually match the current directory, `pwd` falls back to the physical path rather than print something wrong.

## A note on shells

Many command shells provide their own built-in `pwd`, and the shell's version is what runs when you type `pwd` at a prompt. The two behave the same for everyday use. To be certain you are running this command rather than the shell built-in, invoke it by its full path.

## Exit status

| Code | Meaning |
|---|---|
| `0` | The working directory was printed. |
| `1` | The working directory could not be determined or could not be printed. |

---

# readlink

_Peios / Using Peios / Peiosutils / Listing and paths_

> Print the target of a symbolic link, or canonicalise a path by resolving every link in it.

`readlink` prints where a symbolic link points.

```
readlink [options] file...
```

A symbolic link is a file whose contents are another path. `readlink` reads that path and prints it:

```
$ readlink /home/jack/work
/data/projects/jack
```

By default `readlink` resolves exactly one level: it prints the link's immediate target, whether or not that target is itself a link, and whether or not it exists. If the named file is not a symbolic link, `readlink` prints nothing and reports failure.

## Canonicalising a whole path

The canonicalise options change `readlink` from "read this one link" into "resolve this entire path to its real, absolute form" — following every symbolic link in every component, collapsing `.` and `..`. The three differ only in how strict they are about components existing:

| Option | Resolves | Existence requirement |
|---|---|---|
| `-f`, `--canonicalize` | Every link in the path. | Every component except the last must exist. |
| `-e`, `--canonicalize-existing` | Every link in the path. | Every component must exist. |
| `-m`, `--canonicalize-missing` | Every link in the path. | No component need exist. |

With any of these, `readlink` succeeds on an ordinary (non-link) file too — it simply returns the canonical path. [`realpath`](/peios/using-peios/peiosutils/listing-and-paths/realpath.md) is the dedicated command for this canonicalising job and has more options for it; the canonicalise flags here exist so `readlink` can do it without a second tool.

## Output and error control

| Option | Effect |
|---|---|
| `-n`, `--no-newline` | Do not print the trailing newline. Ignored, with a warning, when more than one file is given. |
| `-z`, `--zero` | End each output line with a NUL character instead of a newline. |
| `-q`, `--quiet` / `-s`, `--silent` | Suppress most error messages. This is the default. |
| `-v`, `--verbose` | Report error messages that the quiet default would suppress. |

## Exit status

| Code | Meaning |
|---|---|
| `0` | Every named file was resolved and printed. |
| `1` | A file was not a symbolic link, or a path could not be resolved under the chosen strictness. |

---

# realpath

_Peios / Using Peios / Peiosutils / Listing and paths_

> Resolve a path to its canonical, absolute form — every symbolic link followed and every . and .. component removed.

`realpath` resolves a path to its **canonical** form: absolute, with every symbolic link followed and every `.` and `..` component removed. Given any path, it tells you the one true location it refers to.

```
realpath [options] file...
```

```
$ realpath ../work/./notes.txt
/data/projects/jack/notes.txt
```

A single file can be named many ways — through links, through relative paths, with redundant components. `realpath` reduces all of them to the single canonical path, which makes it the right tool for comparing two paths, or for turning a path a user typed into one a script can rely on.

## How much must exist

By default `realpath` requires every component of the path *except the last* to exist. These options change that requirement:

| Option | Existence requirement |
|---|---|
| (default) | Every component except the last must exist. |
| `-e`, `--canonicalize-existing` | Every component must exist — including the final one. |
| `-m`, `--canonicalize-missing` | No component need exist. The path is canonicalised purely as text where it cannot be walked. |

## How symbolic links are handled

| Option | Effect |
|---|---|
| `-P`, `--physical` | Resolve each symbolic link as it is encountered. This is the default. |
| `-L`, `--logical` | Resolve `..` components *before* resolving the symbolic links they follow. |
| `-s`, `--strip`, `--no-symlinks` | Do not resolve symbolic links at all — only remove `.` and `..` components. The result is canonical as text, but a link in the path is left as-is. |

## Output options

| Option | Effect |
|---|---|
| `--relative-to=DIR` | Print the result as a path relative to `DIR` instead of as an absolute path. |
| `--relative-base=DIR` | Print an absolute path, unless the result lies inside `DIR`, in which case print it relative to `DIR`. |
| `-z`, `--zero` | End each output line with a NUL character instead of a newline. |
| `-q`, `--quiet` | Do not print a warning when a path is invalid. The exit status still reports the failure. |

## `realpath` and `readlink`

[`readlink`](/peios/using-peios/peiosutils/listing-and-paths/readlink.md) with `-f`/`-e`/`-m` does the same canonicalising job. The difference is focus: `readlink` is primarily for reading a single link's target, with canonicalising as an extra; `realpath` is built for canonicalising and carries the richer option set — relative output, the symlink-handling modes, the strip-only mode. Use `realpath` when canonicalising is the actual goal.

## Exit status

| Code | Meaning |
|---|---|
| `0` | Every path was resolved and printed. |
| `1` | A path could not be resolved under the chosen options. |

---

# basename

_Peios / Using Peios / Peiosutils / Listing and paths_

> Strip the directory part off a path, leaving just the final name — and optionally remove a trailing suffix.

`basename` takes a path and prints just its final component — the file name, with all the leading directories removed.

```
basename name [suffix]
basename [options] name...
```

```
$ basename /home/jack/projects/notes.txt
notes.txt
```

It is a pure text operation: `basename` never looks at the file system. It works on the string you give it, so the path need not exist.

## Removing a suffix

Give a second argument and `basename` also strips that suffix from the end of the name — handy for turning a file name into a bare stem:

```
$ basename /home/jack/projects/notes.txt .txt
notes
```

The suffix is only removed if it is actually there, and never if it would leave an empty string.

## Options

`basename` takes one name by default. The options let it process several at once.

| Option | Effect |
|---|---|
| `-a`, `--multiple` | Treat every argument as a name to process, instead of treating the second argument as a suffix. Required to pass more than one name. |
| `-s`, `--suffix=SUFFIX` | Remove `SUFFIX` from each name. Implies `-a`, so it applies to every name given. |
| `-z`, `--zero` | End each output line with a NUL character instead of a newline. |

```
$ basename -s .txt notes.txt readme.txt changelog.txt
notes
readme
changelog
```

## Exit status

| Code | Meaning |
|---|---|
| `0` | Success. |
| `1` | A usage error — a missing or extra operand. |

---

# dirname

_Peios / Using Peios / Peiosutils / Listing and paths_

> Strip the final component off a path, leaving the directory part.

`dirname` takes a path and prints everything *except* its final component — the directory the name lives in. It is the counterpart of [`basename`](/peios/using-peios/peiosutils/listing-and-paths/basename.md).

```
dirname [options] name...
```

```
$ dirname /home/jack/projects/notes.txt
/home/jack/projects
```

Like `basename`, it is a pure text operation — `dirname` never touches the file system, so the path need not exist.

## How it handles edge cases

- If the name has no `/` in it at all, there is no directory part, so `dirname` prints `.` — the current directory.
- Trailing slashes on the name are ignored before the final component is removed.

```
$ dirname notes.txt
.
$ dirname /home/jack/projects/
/home
```

## Multiple names

`dirname` accepts any number of names and prints the directory part of each on its own line:

```
$ dirname /etc/hosts /var/log/messages report.txt
/etc
/var/log
.
```

## Options

| Option | Effect |
|---|---|
| `-z`, `--zero` | End each output line with a NUL character instead of a newline. |

## Exit status

| Code | Meaning |
|---|---|
| `0` | Success. |
| `1` | A usage error — no name was given. |

---

# pathchk

_Peios / Using Peios / Peiosutils / Listing and paths_

> Check whether path names are valid and usable before you try to create the files they name.

`pathchk` checks whether a path name is valid and usable. It tells you, *before* you try to create a file, whether the name would be rejected — because it is too long, contains an unusable component, or could not be reached.

```
pathchk [options] name...
```

```
$ pathchk /home/jack/projects/notes.txt
$ echo $?
0
```

`pathchk` prints nothing when a name is fine; it prints a diagnostic and fails when a name is not. It is meant for scripts that build up path names and want to fail early, with a clear message, instead of discovering the problem halfway through an operation.

Like the other name commands in this topic, `pathchk` does not require the file to exist — it is checking the *name*, not looking for the file.

## What the default check covers

With no options, for each name `pathchk` checks:

- that the name is not empty;
- that no part of the name exceeds the length limits of the file systems the path would actually touch;
- that the leading directories of the name can be searched.

## Stricter checks

The options replace "valid on *this* system" with "valid across a wide range of systems" — useful when a name has to work somewhere other than where you are checking it.

| Option | Adds |
|---|---|
| `-p` | Check against a fixed, conservative set of length limits instead of the local file system's, and flag characters that are not broadly portable. |
| `-P` | Reject an empty name, and reject any component that begins with `-`. |
| `--portability` | Apply both `-p` and `-P` — the strictest check. |

A name with a leading `-` on a component is worth catching: many commands would read it as an option rather than a file name. `-P` flags exactly that class of trouble.

## Exit status

| Code | Meaning |
|---|---|
| `0` | Every name passed every requested check. |
| `1` | At least one name failed. A diagnostic naming the problem was printed. |

---

# dircolors

_Peios / Using Peios / Peiosutils / Listing and paths_

> Produce the shell commands that set LS_COLORS — the variable that controls how ls colours its output.

When [`ls`](/peios/using-peios/peiosutils/listing-and-paths/ls.md) colours its output, it reads the colours from an environment variable named `LS_COLORS`. `dircolors` is the command that produces the value of that variable.

```
dircolors [options] [file]
```

`dircolors` does not set the variable itself — a command cannot change its parent shell's environment. Instead it *prints shell commands* that, when run by the shell, set `LS_COLORS`. The usual way to use it is to have the shell evaluate that output:

```
eval "$(dircolors)"
```

Put that line in a shell startup file and every `ls --color` afterwards picks up the colours. With no arguments, `dircolors` uses a built-in default colour scheme.

## Choosing the shell syntax

The commands `dircolors` prints have to match the shell that will run them. By default it guesses the syntax from the `SHELL` environment variable; these options state it outright.

| Option | Output syntax |
|---|---|
| `-b`, `--sh`, `--bourne-shell` | Bourne-shell-family syntax. |
| `-c`, `--csh`, `--c-shell` | C-shell-family syntax. |

If no shell option is given and `SHELL` is not set, `dircolors` cannot guess and reports an error.

## Customising the colours

To change the colours, you start from the default scheme, edit it, and feed it back.

| Option | Effect |
|---|---|
| `-p`, `--print-database` | Print the built-in colour database in its editable source form, instead of shell commands. |
| `--print-ls-colors` | Print the colours fully escaped, one per line, for inspection. |

The workflow is:

```
dircolors -p > ~/.dircolors      # save the default scheme to a file
# ...edit ~/.dircolors to taste...
eval "$(dircolors ~/.dircolors)" # load the edited scheme
```

When `dircolors` is given a `file` argument, it reads the colour definitions from that file instead of using the built-in database. The file maps file types and name extensions to colours; `dircolors -p` shows the format, with each line commented.

## Exit status

| Code | Meaning |
|---|---|
| `0` | Success. |
| `1` | A usage error, or a colour-definition file that could not be read or parsed. |
