# Viewing and joining text

---

# Viewing and joining text

_Peios / Using Peios / Peiosutils / Viewing and joining text_

> The commands that print files to the screen, show parts of them, and combine or split text by line and by column.

Much of the work at a command line is reading text — looking at a file, checking the start or end of one, pulling a column out, stitching two files together. This topic covers the commands for that: viewing files, showing parts of them, and joining or splitting text by line and by column.

This page names every command in the topic. The companion topic, [Transforming text](/peios/using-peios/peiosutils/transforming-text/overview.md), covers the commands that *reshape* text — sorting, de-duplicating, substituting characters.

## The commands

**Viewing a whole file**

| Command | Purpose |
|---|---|
| [`cat`](/peios/using-peios/peiosutils/viewing-and-joining-text/cat.md) | Print one or more files straight through — and join several into one. |
| [`tac`](/peios/using-peios/peiosutils/viewing-and-joining-text/tac.md) | Print a file with its lines in reverse — last line first. |
| [`more`](/peios/using-peios/peiosutils/viewing-and-joining-text/more.md) | Show a file one screen at a time, pausing between screens. |
| [`od`](/peios/using-peios/peiosutils/viewing-and-joining-text/od.md) | Dump a file's raw bytes in octal, hex, decimal, or character form. |

**Viewing part of a file**

| Command | Purpose |
|---|---|
| [`head`](/peios/using-peios/peiosutils/viewing-and-joining-text/head.md) | Print the first lines (or bytes) of a file. |
| [`tail`](/peios/using-peios/peiosutils/viewing-and-joining-text/tail.md) | Print the last lines of a file — and, with `-f`, keep printing as the file grows. |
| [`nl`](/peios/using-peios/peiosutils/viewing-and-joining-text/nl.md) | Print a file with its lines numbered. |

**Cutting and combining**

| Command | Purpose |
|---|---|
| [`cut`](/peios/using-peios/peiosutils/viewing-and-joining-text/cut.md) | Pull selected columns — byte ranges or delimited fields — out of each line. |
| [`paste`](/peios/using-peios/peiosutils/viewing-and-joining-text/paste.md) | Join files side by side, line for line. |
| [`join`](/peios/using-peios/peiosutils/viewing-and-joining-text/join.md) | Join two files on a shared field, like a database join. |
| [`comm`](/peios/using-peios/peiosutils/viewing-and-joining-text/comm.md) | Compare two sorted files and report which lines they share. |

**Splitting a file into files**

| Command | Purpose |
|---|---|
| [`split`](/peios/using-peios/peiosutils/viewing-and-joining-text/split.md) | Break a file into equal-sized pieces. |
| [`csplit`](/peios/using-peios/peiosutils/viewing-and-joining-text/csplit.md) | Break a file into pieces at lines that match a pattern. |

## A note on input

Almost every command here follows the same convention for where its text comes from. Name one or more files and it reads those; name none and it reads from standard input, so it can sit in the middle of a pipeline. Where a command accepts files, the name `-` stands for standard input, so you can mix files and piped input in one invocation.

## Where to start

To simply print a file, or join a few together, read [`cat`](/peios/using-peios/peiosutils/viewing-and-joining-text/cat.md) — the most-used command in the topic.

---

# cat

_Peios / Using Peios / Peiosutils / Viewing and joining text_

> Print files to standard output, and concatenate several files into one stream.

`cat` prints the contents of files. Its name is short for "concatenate" — given several files, it prints them one after another, as a single stream.

```
cat [options] [file...]
```

```
$ cat notes.txt
$ cat part1.txt part2.txt part3.txt > whole.txt
```

With no file — or with the name `-` — `cat` reads standard input, which is what makes it useful in a pipeline or for capturing typed input into a file.

## Plain use

Most of the time `cat` is run with no options at all: it copies its input to its output, byte for byte, unchanged. The options exist for the times you want to *see* something about the text that is normally invisible, or to adjust spacing and numbering.

## Numbering lines

| Option | Effect |
|---|---|
| `-n`, `--number` | Number every output line. |
| `-b`, `--number-nonblank` | Number only the non-empty lines. Overrides `-n`. |

## Making invisible characters visible

These options reveal characters that normally print as nothing, or as whitespace — useful when a file is not behaving and you suspect a stray tab or control character.

| Option | Effect |
|---|---|
| `-E`, `--show-ends` | Print a `$` at the end of each line, so trailing spaces become visible. |
| `-T`, `--show-tabs` | Print tab characters as `^I` instead of as whitespace. |
| `-v`, `--show-nonprinting` | Print control and other non-printing characters using `^` and `M-` notation (leaving newline and tab as they are). |
| `-e` | Shorthand for `-vE`. |
| `-t` | Shorthand for `-vT`. |
| `-A`, `--show-all` | Shorthand for `-vET` — show ends, tabs, and all non-printing characters at once. |

## Adjusting spacing

| Option | Effect |
|---|---|
| `-s`, `--squeeze-blank` | Collapse runs of blank lines into a single blank line. |

## Exit status

| Code | Meaning |
|---|---|
| `0` | Every file was printed. |
| `1` | A file could not be read. |

---

# tac

_Peios / Using Peios / Peiosutils / Viewing and joining text_

> Print files with their lines in reverse order — last line first.

`tac` prints a file with its lines in reverse — the last line first, the first line last. The name is `cat` spelled backwards, which is exactly what it does.

```
tac [options] [file...]
```

```
$ tac events.log
```

Reversing a log file so the newest entries come first is the everyday use. With no file, `tac` reads standard input.

## Reversing on something other than lines

`tac` does not have to split on newlines. You can tell it to treat some other string as the separator, and it will reverse the order of the pieces between those separators.

| Option | Effect |
|---|---|
| `-s`, `--separator=STRING` | Use `STRING` as the separator between records, instead of a newline. |
| `-r`, `--regex` | Treat the separator as a regular expression rather than a literal string. |
| `-b`, `--before` | Expect the separator *before* each record rather than after it. This matters for how the separator is reattached when the records are reordered. |

```
$ tac -s ', ' -r names.csv
```

## Exit status

| Code | Meaning |
|---|---|
| `0` | Every file was printed. |
| `1` | A file could not be read, or the separator regular expression was invalid. |

---

# head

_Peios / Using Peios / Peiosutils / Viewing and joining text_

> Print the first lines or bytes of a file.

`head` prints the **beginning** of a file — by default, the first 10 lines.

```
head [options] [file...]
```

```
$ head config.toml
```

It is the quick way to glance at the top of a file without printing the whole thing — a header, the first few records, the start of a log. With no file, `head` reads standard input.

## Choosing how much

| Option | Effect |
|---|---|
| `-n`, `--lines=NUM` | Print the first `NUM` lines instead of 10. |
| `-c`, `--bytes=NUM` | Print the first `NUM` bytes instead of counting lines. |

`NUM` accepts a unit suffix (`K`, `M`, …) when counting bytes.

### Counting from the end

If `NUM` is given a leading `-`, the meaning flips: `head` prints **everything except the last `NUM`**.

```
$ head -n -5 report.txt    # all but the final 5 lines
```

## Headers for multiple files

When given more than one file, `head` prints a header line before each one so you can tell them apart. Two options override that:

| Option | Effect |
|---|---|
| `-q`, `--quiet` | Never print the file-name headers. |
| `-v`, `--verbose` | Always print the header, even for a single file. |

## Other options

| Option | Effect |
|---|---|
| `-z`, `--zero-terminated` | Treat the NUL character as the line delimiter instead of newline. |

## Exit status

| Code | Meaning |
|---|---|
| `0` | Every file was printed. |
| `1` | A file could not be read. |

---

# tail

_Peios / Using Peios / Peiosutils / Viewing and joining text_

> Print the last lines of a file — and keep printing as the file grows.

`tail` prints the **end** of a file — by default, the last 10 lines.

```
tail [options] [file...]
```

```
$ tail server.log
```

It is the counterpart of [`head`](/peios/using-peios/peiosutils/viewing-and-joining-text/head.md): the quick way to see the most recent lines of a file. With no file, `tail` reads standard input.

## Choosing how much

| Option | Effect |
|---|---|
| `-n`, `--lines=NUM` | Print the last `NUM` lines instead of 10. |
| `-c`, `--bytes=NUM` | Print the last `NUM` bytes instead of counting lines. |

If `NUM` is given a leading `+`, the meaning flips: `tail` prints **everything from line `NUM` onward**.

```
$ tail -n +20 report.txt    # from line 20 to the end
```

## Following a growing file

`tail`'s most useful trick is `-f`. Instead of printing the end and exiting, it stays running and prints new lines as they are appended — the standard way to watch a log file live.

| Option | Effect |
|---|---|
| `-f`, `--follow` | Keep the file open and print new data as it is added. |
| `-F` | Follow the file *by name*, and keep retrying if it is missing. Equivalent to `--follow=name --retry`. This survives log rotation — when the file is replaced, `-F` picks up the new one. |
| `--retry` | Keep trying to open a file that is not yet accessible. |
| `--pid=PID` | While following, stop once process `PID` exits. |
| `-s`, `--sleep-interval=N` | Wait `N` seconds between checks of the file. |

Press Ctrl-C to stop a `tail -f`.

## Headers for multiple files

As with `head`, when given more than one file `tail` prints a header before each.

| Option | Effect |
|---|---|
| `-q`, `--quiet` | Never print the file-name headers. |
| `-v`, `--verbose` | Always print the header, even for a single file. |

## Other options

| Option | Effect |
|---|---|
| `-z`, `--zero-terminated` | Treat the NUL character as the line delimiter instead of newline. |

## Exit status

| Code | Meaning |
|---|---|
| `0` | Success. |
| `1` | A file could not be read. |

---

# more

_Peios / Using Peios / Peiosutils / Viewing and joining text_

> View a file one screen at a time, pausing between screens.

`more` displays a file one screenful at a time. Where [`cat`](/peios/using-peios/peiosutils/viewing-and-joining-text/cat.md) prints a whole file at once — and a long file scrolls straight past — `more` shows the first screen, then waits for you before showing the next.

```
more [options] file...
```

```
$ more long-report.txt
```

## Moving through the file

While `more` is paused, it is waiting for a keypress:

| Key | Action |
|---|---|
| Space | Show the next screenful. |
| Return | Show the next line. |
| `q` | Quit. |
| `/` | Search forward for a string. |
| `h` | Show the built-in help. |

`more` moves *forward* through a file. It is the simple, always-available pager — enough for reading something through once.

## Options

| Option | Effect |
|---|---|
| `-n`, `--lines=NUM` | Show `NUM` lines per screenful instead of filling the terminal. `--number=NUM` is the same. |
| `-F`, `--from-line=NUM` | Begin displaying at line `NUM`. |
| `-P`, `--pattern=STRING` | Search for `STRING` and begin displaying at the first match. |
| `-e`, `--exit-on-eof` | Exit automatically at the end of the file, rather than waiting. |
| `-s`, `--squeeze` | Collapse runs of blank lines into one. |
| `-u`, `--plain` | Suppress underlining in the displayed text. |
| `-p`, `--print-over` | Clear the screen and print the next page, instead of scrolling. |
| `-c`, `--clean-print` | Redraw each page in place, cleaning line ends, instead of scrolling. |
| `-d`, `--silent` | When an unrecognised key is pressed, show a short hint instead of ringing the terminal bell. |
| `-l`, `--logical` | Do not pause when a line contains a form-feed character. |
| `-f`, `--no-pause` | Count logical lines rather than screen lines when deciding where to pause. |

## Exit status

| Code | Meaning |
|---|---|
| `0` | The file was displayed. |
| `1` | A file could not be opened. |

---

# nl

_Peios / Using Peios / Peiosutils / Viewing and joining text_

> Print files with their lines numbered, with control over which lines are counted and how the number is formatted.

`nl` prints a file with its lines numbered. [`cat -n`](/peios/using-peios/peiosutils/viewing-and-joining-text/cat.md) also numbers lines; `nl` is the command for when you need *control* over the numbering — which lines count, how the number looks, where it restarts.

```
nl [options] [file...]
```

```
$ nl chapter.txt
     1  Once the system is installed,
     2  the first boot brings up
       
     3  the configuration service.
```

## Which lines get a number

By default `nl` numbers only the non-empty lines. `-b` sets the rule:

| `-b STYLE` | Numbers… |
|---|---|
| `-b a` | every line. |
| `-b t` | only non-empty lines. This is the default. |
| `-b n` | no lines. |
| `-b pBRE` | only lines that match the basic regular expression `BRE`. |

| Option | Effect |
|---|---|
| `-b`, `--body-numbering=STYLE` | The numbering rule, as above. |
| `-l`, `--join-blank-lines=N` | Count a run of `N` blank lines as one numbered line. |

## How the number looks

| Option | Effect |
|---|---|
| `-n`, `--number-format=FORMAT` | `ln` = left-justified; `rn` = right-justified; `rz` = right-justified with leading zeros. |
| `-w`, `--number-width=N` | Use `N` columns for the number. |
| `-s`, `--number-separator=STRING` | Put `STRING` between the number and the line text. |
| `-v`, `--starting-line-number=N` | Start counting from `N`. |
| `-i`, `--line-increment=N` | Increase the number by `N` at each counted line. |

## Logical pages

`nl` can treat one file as a sequence of **logical pages**, each with a header, a body, and a footer, and number the three parts by different rules. Pages are separated by special delimiter lines in the input.

| Option | Effect |
|---|---|
| `-h`, `--header-numbering=STYLE` | Numbering style for header sections. |
| `-f`, `--footer-numbering=STYLE` | Numbering style for footer sections. |
| `-d`, `--section-delimiter=CC` | The characters that mark a section boundary in the input. |
| `-p`, `--no-renumber` | Do not reset the line number at the start of each logical page. |

The styles for `-h` and `-f` are the same `a` / `t` / `n` / `pBRE` set as `-b`. For an ordinary file with no delimiter lines, the whole file is one body and only `-b` matters.

## Exit status

| Code | Meaning |
|---|---|
| `0` | Success. |
| `1` | A file could not be read, or an option value was invalid. |

---

# cut

_Peios / Using Peios / Peiosutils / Viewing and joining text_

> Pull selected columns — byte ranges or delimited fields — out of each line of input.

`cut` extracts **columns** from text. For each line of input it prints only the parts you select, dropping the rest.

```
cut option... [file...]
```

```
$ cut -d , -f 1,3 people.csv     # the 1st and 3rd comma-separated field
$ cut -c 1-8 log.txt             # the first 8 characters of each line
```

Every run of `cut` needs two decisions: **what counts as a column**, and **which columns to keep**.

## What counts as a column

Choose exactly one mode:

| Option | A column is… |
|---|---|
| `-b`, `--bytes` | a single byte. |
| `-c`, `--characters` | a single character. |
| `-f`, `--fields` | a field — a stretch of text between delimiters. |

`-b` and `-c` cut by position. `-f` cuts by *field*, which is what you want for tabular data — a CSV, a table, the columns of a report.

## Which columns to keep

The mode option takes a **sequence**: numbers and inclusive ranges, separated by commas.

| Sequence | Selects |
|---|---|
| `3` | column 3 only. |
| `2,5,9` | columns 2, 5, and 9. |
| `5-7` | columns 5 through 7. |
| `3-` | column 3 to the end of the line. |
| `-4` | the start of the line through column 4. |
| `1,4-6,9` | any mixture of the above. |

| Option | Effect |
|---|---|
| `--complement` | Invert the selection — keep every column *except* those named. |

## Field mode: the delimiter

In field mode, `cut` needs to know what separates the fields.

| Option | Effect |
|---|---|
| `-d`, `--delimiter=CHAR` | The character that separates fields. The default is a tab. |
| `-w` | Separate fields on runs of whitespace (spaces and tabs) instead of a single character. Cannot be combined with `-d`. |
| `-s`, `--only-delimited` | Print only lines that actually contain the delimiter; drop lines that have no fields to cut. |
| `--output-delimiter=STRING` | Put `STRING` between the kept fields in the output, instead of repeating the input delimiter — handy for converting one delimited format to another. |

## Other options

| Option | Effect |
|---|---|
| `-z`, `--zero-terminated` | Treat the NUL character as the line delimiter, so a "line" may itself contain newlines. |

## Exit status

| Code | Meaning |
|---|---|
| `0` | Success. |
| `1` | A mode was missing or given twice, an option was misused, or a file could not be read. |

---

# paste

_Peios / Using Peios / Peiosutils / Viewing and joining text_

> Join files side by side, line for line.

`paste` joins files **side by side**. It takes the first line of each file and prints them on one line, then the second line of each, and so on — merging files into columns.

```
paste [options] [file...]
```

```
$ paste names.txt ages.txt
Ada      36
Grace    41
Linus    29
```

By default the merged pieces are separated by a tab. `paste` is the column-wise counterpart of [`cat`](/peios/using-peios/peiosutils/viewing-and-joining-text/cat.md), which joins files end to end.

## Pasting one file at a time

| Option | Effect |
|---|---|
| `-s`, `--serial` | Paste each file's lines onto a *single line*, one file at a time, instead of merging files in parallel. A file's lines become a row. |

```
$ paste -s -d , names.txt
Ada,Grace,Linus
```

## Choosing the separator

| Option | Effect |
|---|---|
| `-d`, `--delimiters=LIST` | Use the characters in `LIST` as separators instead of a tab. When `LIST` has more than one character, `paste` cycles through them. |
| `-z`, `--zero-terminated` | Treat the NUL character as the line delimiter instead of newline. |

## `paste` and `join`

`paste` merges by *position* — line 1 with line 1, line 2 with line 2, blind to content. When you want to merge by a *matching value* — pairing rows that share a key — that is [`join`](/peios/using-peios/peiosutils/viewing-and-joining-text/join.md).

## Exit status

| Code | Meaning |
|---|---|
| `0` | Success. |
| `1` | A file could not be read, or the delimiter list was malformed. |

---

# join

_Peios / Using Peios / Peiosutils / Viewing and joining text_

> Join two files on a shared field, pairing lines that have the same key.

`join` merges two files on a **shared field**. For every pair of lines — one from each file — that have the same value in their join field, it prints a combined line. It is the command-line form of a database join.

```
join [options] file1 file2
```

```
$ join employees.txt salaries.txt
```

If `employees.txt` has `101 Ada` and `salaries.txt` has `101 80000`, `join` pairs them on the shared `101` and prints `101 Ada 80000`.

## The input must be sorted

`join` works by stepping through both files together, so **both files must be sorted on the join field**. If they are not, `join` will miss matches. Sort them first with [`sort`](/peios/using-peios/peiosutils/transforming-text/sort.md), on the same field `join` will use.

`join` checks the ordering as it goes and reports a file that is out of order; `--nocheck-order` turns that check off, and `--check-order` forces it on.

## Choosing the join field

By default `join` joins on the **first** field of each file, and fields are separated by whitespace.

| Option | Effect |
|---|---|
| `-1 FIELD` | Join on `FIELD` of file 1. |
| `-2 FIELD` | Join on `FIELD` of file 2. |
| `-j FIELD` | Join on `FIELD` of *both* files — shorthand for `-1 FIELD -2 FIELD`. |
| `-t CHAR` | Use `CHAR` as the field separator for input and output. |

## Unmatched lines

By default `join` prints only the lines that *paired*. A line with no match on the other side is dropped. These options bring unmatched lines back:

| Option | Effect |
|---|---|
| `-a FILENUM` | Also print unpaired lines from file `FILENUM` (`1` or `2`). |
| `-v FILENUM` | Print *only* the unpaired lines from file `FILENUM`, and suppress the joined output. |
| `-e EMPTY` | Fill in any missing field with the string `EMPTY`. |

## Shaping the output

| Option | Effect |
|---|---|
| `-o FORMAT` | Build each output line from the field list `FORMAT`, rather than the default layout. |
| `-i`, `--ignore-case` | Ignore letter case when comparing join fields. |
| `--header` | Treat the first line of each file as column headers — print them, paired, without trying to match them. |
| `-z`, `--zero-terminated` | Treat the NUL character as the line delimiter. |

## Exit status

| Code | Meaning |
|---|---|
| `0` | Success. |
| `1` | A file could not be read, was not sorted, or an option was invalid. |

---

# comm

_Peios / Using Peios / Peiosutils / Viewing and joining text_

> Compare two sorted files line by line and report which lines they share.

`comm` compares two sorted files and tells you which lines are **unique to each** and which are **common to both**.

```
comm [options] file1 file2
```

By default it prints three columns:

```
$ comm list-a.txt list-b.txt
            apple
banana
                        cherry
date
```

- **Column 1** — lines only in `file1`.
- **Column 2** — lines only in `file2`.
- **Column 3** — lines in both.

Each column is indented past the one before, so a line's column position tells you where it was found.

## The input must be sorted

`comm` steps through both files together, so **both must be sorted**. On unsorted input the comparison is meaningless. Sort the files first with [`sort`](/peios/using-peios/peiosutils/transforming-text/sort.md).

`comm` checks the ordering and reports a file that is out of order. `--check-order` forces the check; `--nocheck-order` disables it.

## Showing only the columns you want

Each column can be switched off. The remaining columns close up to fill the gap.

| Option | Effect |
|---|---|
| `-1` | Suppress column 1 — hide lines unique to `file1`. |
| `-2` | Suppress column 2 — hide lines unique to `file2`. |
| `-3` | Suppress column 3 — hide lines common to both. |

These combine to answer specific questions. `comm -12` shows *only* the common lines — the intersection of the two files. `comm -23` shows lines in `file1` that are not in `file2` — the difference.

## Other options

| Option | Effect |
|---|---|
| `--output-delimiter=STR` | Separate the columns with `STR` instead of spaces. |
| `--total` | Print a final summary line with the count in each column. |
| `-z`, `--zero-terminated` | Treat the NUL character as the line delimiter. |

## Exit status

| Code | Meaning |
|---|---|
| `0` | Success. |
| `1` | A file could not be read, or was not sorted. |

---

# split

_Peios / Using Peios / Peiosutils / Viewing and joining text_

> Break a file into equal-sized pieces, each written to its own output file.

`split` breaks one file into several smaller files of roughly equal size.

```
split [options] [input [prefix]]
```

```
$ split -l 1000 big.log
$ ls
xaa  xab  xac  xad
```

By default `split` writes 1000 lines per piece, names the pieces `xaa`, `xab`, `xac`, … — a `prefix` of `x` followed by a two-letter suffix — and reads its input from a named file or from standard input.

To put the file back together, concatenate the pieces in order: [`cat`](/peios/using-peios/peiosutils/viewing-and-joining-text/cat.md)` xaa xab xac … > original`.

Each piece is a newly created file, and a new file needs a [security descriptor](/peios/security-fundamentals/security-descriptors/overview.md); each piece inherits one from the directory it is created in.

## How big each piece is

Choose one of these to set the piece size:

| Option | Each piece holds… |
|---|---|
| `-l`, `--lines=N` | `N` lines. This is the default behaviour, with `N` = 1000. |
| `-b`, `--bytes=SIZE` | `SIZE` bytes. |
| `-C`, `--line-bytes=SIZE` | up to `SIZE` bytes, but only whole lines — never a line split across two pieces. |
| `-n`, `--number=CHUNKS` | the input divided into a fixed number of pieces (see below). |

A `SIZE` accepts a unit suffix: `K`, `M`, `G`, … as powers of 1024, or `KB`, `MB`, … as powers of 1000.

### Fixed number of chunks (`-n`)

`-n` divides the input into a set number of pieces rather than fixing each piece's size. `CHUNKS` may be:

| Form | Effect |
|---|---|
| `N` | Split into `N` pieces by size. |
| `l/N` | Split into `N` pieces without splitting any line across pieces. |
| `r/N` | Like `l/N`, but distribute lines round-robin across the pieces. |
| `K/N` | Write only the `K`th of `N` pieces, to standard output. |

## Naming the pieces

| Option | Effect |
|---|---|
| `prefix` (operand) | The leading part of each output name. Default `x`. |
| `-a`, `--suffix-length=N` | Use `N` characters for the suffix. Default 2. |
| `-d`, `--numeric-suffixes[=START]` | Use numeric suffixes (`00`, `01`, …) instead of letters, optionally from `START`. |
| `-x`, `--hex-suffixes[=START]` | Use hexadecimal suffixes. |
| `--additional-suffix=SUFFIX` | Append a fixed `SUFFIX` to every output name — for giving the pieces an extension. |

## Other options

| Option | Effect |
|---|---|
| `-e`, `--elide-empty-files` | With `-n`, do not write out pieces that would be empty. |
| `-t`, `--separator=SEP` | Use `SEP` as the line separator instead of newline. |
| `--verbose` | Print a line as each output file is opened. |

## Exit status

| Code | Meaning |
|---|---|
| `0` | The file was split. |
| `1` | A failure — the input could not be read, or the suffixes were exhausted. |

---

# csplit

_Peios / Using Peios / Peiosutils / Viewing and joining text_

> Break a file into pieces at lines chosen by line number or by a matching pattern.

`csplit` — "context split" — breaks a file into pieces at points *you* choose: a line number, or a line that matches a pattern. Where [`split`](/peios/using-peios/peiosutils/viewing-and-joining-text/split.md) cuts a file into equal sizes, `csplit` cuts it at meaningful boundaries.

```
csplit [options] file pattern...
```

```
$ csplit report.txt '/^Chapter/' '{*}'
```

That splits `report.txt` into one piece per chapter, cutting at every line beginning with `Chapter`. The pieces are written to `xx00`, `xx01`, `xx02`, … and `csplit` prints the byte size of each.

Each piece is a newly created file, and a new file needs a [security descriptor](/peios/security-fundamentals/security-descriptors/overview.md); each piece inherits one from the directory it is created in.

## Patterns

Each `pattern` argument marks a cut point. `csplit` copies everything up to that point into the next output file, then continues.

| Pattern | Cut where… |
|---|---|
| `N` (a number) | line `N` is reached — the piece is lines up to `N-1`. |
| `/REGEX/` | a line matches `REGEX`; that line starts the *next* piece. |
| `%REGEX%` | a line matches `REGEX` — but **skip** the text up to it instead of writing it to a piece. |
| `/REGEX/+N` or `/REGEX/-N` | an offset of `N` lines from the matching line. |
| `{N}` | repeat the *previous* pattern `N` more times. |
| `{*}` | repeat the previous pattern as many times as the file allows. |

A pattern that finds no match is an error, and by default `csplit` removes the pieces it had already written. `-k` keeps them.

## Naming the pieces

| Option | Effect |
|---|---|
| `-f`, `--prefix=PREFIX` | Use `PREFIX` instead of `xx` at the start of each output name. |
| `-n`, `--digits=N` | Use `N` digits in the numeric part of the name instead of 2. |
| `-b`, `--suffix-format=FORMAT` | Use a custom `printf`-style `FORMAT` for the numeric suffix. |

## Other options

| Option | Effect |
|---|---|
| `-k`, `--keep-files` | Do not delete the output files if `csplit` fails partway. |
| `-z`, `--elide-empty-files` | Do not write out pieces that would be empty. |
| `--suppress-matched` | Drop the lines that the patterns matched, rather than keeping them in a piece. |
| `-s`, `--quiet` | Do not print the byte size of each piece. |

## Exit status

| Code | Meaning |
|---|---|
| `0` | The file was split. |
| `1` | A pattern did not match, a line number was out of range, or the input could not be read. |

---

# od

_Peios / Using Peios / Peiosutils / Viewing and joining text_

> Dump the raw bytes of a file in octal, hexadecimal, decimal, floating-point, or character form — a low-level view of exactly what a file contains.

`od` — short for "octal dump" — prints the raw bytes of a file. Where [`cat`](/peios/using-peios/peiosutils/viewing-and-joining-text/cat.md) shows you a file as text, `od` shows you the actual bytes underneath: each one rendered as a number, a character, or a floating-point value, in whatever base you ask for. It is the tool for looking at binary files, checking exactly which bytes a text file contains, or finding a stray control character that isn't visible on screen.

```
od [options] [file...]
```

```
$ od hello.txt
0000000 062510 066154 020157 067527 066162 020144 000012
0000015
```

With no file — or with the name `-` — `od` reads standard input, so it can sit at the end of a pipeline. Given several files, it reads them one after another as a single continuous stream, and the byte offsets run straight through from one file into the next.

## How the output is laid out

Every line of output has two parts:

- An **offset** on the left: the position, counted in bytes from the start of the input, of the first byte on that line. By default it is printed in octal (see [`-A`](#the-offset-column) to change the base).
- One or more **format columns** on the right: the bytes of that line rendered in the format(s) you chose.

With no format option, `od` prints the input as **octal, two bytes at a time** — the traditional default. The very last line of output is a lone offset marking the total length of the input.

If you ask for more than one format at once, each format is printed on its own line, stacked under a single shared offset. Only the first line of the group carries the offset; the rest are indented to line up beneath it.

## Choosing what the bytes look like

There are two ways to say how bytes should be rendered: a set of single-letter **named shortcuts** for the common cases, and the general **`-t` / `--format`** option for full control. You can give several at once, and they are applied in the order they appear on the command line.

### Named format shortcuts

Each of these selects one output format. Combine them freely (`od -cx` prints characters and hex together).

| Option | Renders each unit as |
|---|---|
| `-a` | Named characters, ignoring the high-order bit (control characters shown by name, e.g. `nul`, `sp`, `del`). |
| `-b` | Octal, one byte at a time. |
| `-c` | Printable ASCII / UTF-8 characters, with backslash escapes (`\n`, `\t`, …) for the rest. |
| `-d` | Unsigned decimal, 2-byte units. |
| `-D` | Unsigned decimal, 4-byte units. |
| `-o` | Octal, 2-byte units. |
| `-O` | Octal, 4-byte units. |
| `-s` | Signed decimal, 2-byte units. |
| `-i` | Signed decimal, 4-byte units. |
| `-l` | Signed decimal, 8-byte units. |
| `-I`, `-L` | Signed decimal, 8-byte units. |
| `-x`, `-h` | Hexadecimal, 2-byte units. |
| `-X`, `-H` | Hexadecimal, 4-byte units. |
| `-f` | Floating point, single precision (32-bit). |
| `-e`, `-F` | Floating point, double precision (64-bit). |

### Type specifications (`-t`, `--format`)

`-t` takes a **type specification** and gives you every combination the named shortcuts cover and more. Repeat `-t` (or list several specs in one argument) to print multiple formats.

A type specification is a **type letter**, an optional **size**, and an optional **`z`** suffix:

| Type letter | Meaning |
|---|---|
| `a` | Printable 7-bit ASCII, named (like `-a`). |
| `c` | UTF-8 characters, with octal escapes for undefined bytes (like `-c`). |
| `d` | Signed decimal. |
| `u` | Unsigned decimal. |
| `o` | Octal. |
| `x` | Hexadecimal. |
| `f` | Floating point. |

For the numeric types (`d`, `u`, `o`, `x`, `f`) a **size** says how many bytes make up one unit. It can be a number, or a letter:

| Size | Applies to | Bytes per unit |
|---|---|---|
| `1` / `C` | integer types | 1 |
| `2` / `S` | integer types | 2 |
| `4` / `I` | integer types | 4 |
| `8` / `L` | integer types | 8 |
| `4` / `F` | floating point | 4 (single precision) |
| `8` / `D` | floating point | 8 (double precision) |
| `16` / `L` | floating point | 16 (extended / long double) |
| `2` / `H` | floating point | 2 (IEEE half precision) |
| `2` / `B` | floating point | 2 (bfloat16) |

If you leave the size off, integer types default to **4 bytes** and floating point defaults to **8 bytes**. For the character types `a` and `c`, a size is not allowed.

Add a **`z`** at the end of a spec to append an ASCII dump — the bytes of that line shown as text, `.` for anything non-printable — to the right of the numbers. For example, `od -t x1z` gives the familiar hex-plus-text layout:

```
$ od -A x -t x1z file.bin
000000 48 65 6c 6c 6f 2c 20 77 6f 72 6c 64 21 0a           >Hello, world!.<
```

Examples: `od -t d2` is signed decimal in 2-byte units; `od -t x1` is hex byte-by-byte; `od -t fD` is double-precision floats; `od -t c` is characters. `od -t x1 -t c` prints hex and characters as two stacked lines.

### Byte order (`--endian`)

For multi-byte numeric formats, `--endian` sets the byte order used to assemble each unit. Without it, `od` uses the machine's native byte order. Use `--endian=big` or `--endian=little` to force one regardless of the host.

## The offset column

| Option | Effect |
|---|---|
| `-A RADIX`, `--address-radix=RADIX` | Print offsets in the given base. `RADIX` is one of `o` (octal, the default), `d` (decimal), `x` (hexadecimal), or `n` (none — omit the offset column entirely). |

Only the first character of the value is examined, so `od -A n` and `od -Anone` mean the same thing.

## Which bytes to read

By default `od` dumps the whole input. Two options narrow that to a window:

| Option | Effect |
|---|---|
| `-j BYTES`, `--skip-bytes=BYTES` | Skip `BYTES` bytes of input before starting to dump. When several files are given, the skip runs across the concatenated stream. |
| `-N BYTES`, `--read-bytes=BYTES` | Dump at most `BYTES` bytes, then stop. |

In both, `BYTES` is decimal by default, octal if it starts with `0`, or hexadecimal if it starts with `0x`. A suffix scales it: `b` = ×512, `KB`/`K` = ×1000 / ×1024, `MB`/`M` = ×1000² / ×1024², `GB`/`G` = ×1000³ / ×1024³.

## Collapsing repeated lines

When several output lines in a row would be identical, `od` prints the first one, then a single line containing just `*` to stand for the run, and resumes at the next line that differs. This keeps a dump of a large block of identical bytes (a file full of zeros, say) short.

| Option | Effect |
|---|---|
| `-v`, `--output-duplicates` | Turn the collapsing off — print every line, including repeats, with no `*` markers. |

## Output width

| Option | Effect |
|---|---|
| `-w[BYTES]`, `--width[=BYTES]` | Print `BYTES` input bytes per output line. The default is 16; giving `-w` with no value uses 32. |

The width must be a whole multiple of the size of the largest format unit in play; if it isn't, `od` warns and rounds it to a usable value.

## Finding printable strings

| Option | Effect |
|---|---|
| `-S[BYTES]`, `--strings[=BYTES]` | Instead of dumping bytes, scan the input and print only runs of at least `BYTES` printable characters, one per line, each preceded by its offset. `BYTES` defaults to 3 when omitted. |

This turns `od` into a quick way to pull the human-readable text out of a binary file. The offset in front of each string honours `-A` (and is dropped entirely under `-A n`). `-j` and `-N` still apply, so you can restrict the scan to a window.

## The traditional offset form

`od` also accepts the historical calling convention, where an **offset** (and, in `--traditional` mode, a **label**) is given as a bare operand rather than an option:

```
od [named-format-options] [file] [[+]offset[.][b]]
od --traditional [options] [file] [[+]offset[.][b] [[+]label[.][b]]]
```

The **offset** says where in the input to begin, exactly like `-j`. It is read as **octal by default**, hexadecimal if prefixed with `0x`, or decimal if it carries a trailing `.`; a trailing `b` multiplies it by 512. The optional leading `+` is allowed everywhere and is required when there is no filename (so `od +20` reads standard input starting at octal offset 20).

The **label** (only in `--traditional` mode) is a second such number: the dump still begins at `offset`, but the offset column is *displayed* as if it started at `label` — useful for making a partial dump's offsets match the original file.

`od` only reads an operand as an offset in the plain form when none of `-A`, `-j`, `-N`, `-t`, `-v`, or `-w` are present. So if a real filename happens to look like a number, add a harmless option such as `-j0` to force it to be treated as a filename.

## A note on reading files

`od` has no access rules of its own — it simply opens a file and reads its bytes. That read is subject to the same check as every read on Peios: whether you may open the file for reading is decided by the file's **security descriptor** (see [Security descriptors](/peios/security-fundamentals/security-descriptors/overview.md)). `od` never reveals bytes you could not already read another way; it only presents the bytes you can read in a different form.

## Exit status

| Code | Meaning |
|---|---|
| `0` | The input was dumped successfully. |
| `1` | A file could not be read, or an option, format, or offset was invalid. |
