# Transforming text

---

# Transforming text

_Peios / Using Peios / Peiosutils / Transforming text_

> The commands that reshape text — reordering lines, removing duplicates, substituting characters, reflowing paragraphs, and counting.

This topic covers the commands that **reshape** text: putting lines in order, dropping duplicates, swapping characters, reflowing paragraphs to a width, counting what is there. Its companion, [Viewing and joining text](/peios/using-peios/peiosutils/viewing-and-joining-text/overview.md), covers printing and combining files; this topic is about changing the text itself.

## The commands

**Ordering lines**

| Command | Purpose |
|---|---|
| [`sort`](/peios/using-peios/peiosutils/transforming-text/sort.md) | Sort lines — alphabetically, numerically, and many other ways. |
| [`shuf`](/peios/using-peios/peiosutils/transforming-text/shuf.md) | The opposite of sorting: put lines into a random order. |
| [`tsort`](/peios/using-peios/peiosutils/transforming-text/tsort.md) | Topological sort — order items so that each comes after the things it depends on. |

**Filtering lines**

| Command | Purpose |
|---|---|
| [`uniq`](/peios/using-peios/peiosutils/transforming-text/uniq.md) | Collapse or report adjacent repeated lines. |

**Substituting characters**

| Command | Purpose |
|---|---|
| [`tr`](/peios/using-peios/peiosutils/transforming-text/tr.md) | Translate, squeeze, or delete individual characters. |

**Whitespace**

| Command | Purpose |
|---|---|
| [`expand`](/peios/using-peios/peiosutils/transforming-text/expand.md) | Convert tabs into spaces. |
| [`unexpand`](/peios/using-peios/peiosutils/transforming-text/unexpand.md) | Convert runs of spaces back into tabs. |

**Reflowing and paginating**

| Command | Purpose |
|---|---|
| [`fmt`](/peios/using-peios/peiosutils/transforming-text/fmt.md) | Reflow paragraphs to a target width. |
| [`fold`](/peios/using-peios/peiosutils/transforming-text/fold.md) | Hard-wrap long lines at a fixed width. |
| [`pr`](/peios/using-peios/peiosutils/transforming-text/pr.md) | Paginate and columnate text for printing. |

**Indexing and counting**

| Command | Purpose |
|---|---|
| [`ptx`](/peios/using-peios/peiosutils/transforming-text/ptx.md) | Produce a permuted index of the words in a file. |
| [`wc`](/peios/using-peios/peiosutils/transforming-text/wc.md) | Count the lines, words, and bytes in a file. |

## Two commands that need sorted input

A theme worth knowing before you start: [`uniq`](/peios/using-peios/peiosutils/transforming-text/uniq.md) only collapses *adjacent* duplicate lines, so duplicates scattered through a file are not caught unless the file is sorted first. `sort` and `uniq` are almost always used together — and `sort -u` does both jobs in one step.

## Where to start

[`sort`](/peios/using-peios/peiosutils/transforming-text/sort.md) is the workhorse of the topic and the one with the most depth — start there.

---

# sort

_Peios / Using Peios / Peiosutils / Transforming text_

> Sort the lines of files — alphabetically, numerically, by field, and many other ways.

`sort` reads lines and writes them out in order.

```
sort [options] [file...]
```

```
$ sort names.txt
```

With no file, `sort` reads standard input. Given several files, it sorts all of their lines together as one stream. By default it compares lines as plain text, character by character.

## How lines are compared

The default text comparison is often not the order you want — `10` sorts before `9`, and case matters. These options change the comparison:

| Option | Compares lines as… |
|---|---|
| `-n`, `--numeric-sort` | numbers. `9` sorts before `10`. |
| `-g`, `--general-numeric-sort` | numbers, including scientific notation. Slower than `-n`; use it only when `-n` is not enough. |
| `-h`, `--human-numeric-sort` | human-readable sizes — `2K` before `1M` before `3G`. |
| `-M`, `--month-sort` | month names — `JAN` before `FEB`. |
| `-V`, `--version-sort` | version numbers — `1.2.10` after `1.2.9`. |
| `-R`, `--random-sort` | a random order (a shuffle that groups equal lines together). |

And these adjust *what* is compared:

| Option | Effect |
|---|---|
| `-f`, `--ignore-case` | Treat lower and upper case as the same. |
| `-d`, `--dictionary-order` | Consider only letters, digits, and blanks. |
| `-i`, `--ignore-nonprinting` | Ignore non-printing characters. |
| `-b`, `--ignore-leading-blanks` | Ignore blanks at the start of a line (or field). |

## Sort order options

| Option | Effect |
|---|---|
| `-r`, `--reverse` | Reverse the result. |
| `-u`, `--unique` | Output only the first line of each run of equal lines — sort and de-duplicate in one step. |
| `-s`, `--stable` | Keep equal lines in their original relative order. |

## Sorting by a field

By default `sort` compares whole lines. `-k` sorts on a **key** — a chosen part of each line — which is what you need for tabular data.

A line is split into fields (by default at whitespace). A key is written `FIELD[.CHAR][OPTIONS][,FIELD[.CHAR]]` — a start field, an optional start character within it, and an optional end. The single-letter comparison options above can be appended to a key to apply only to it.

```
$ sort -k 2 -n scores.txt        # sort on the 2nd field, numerically
$ sort -t , -k 3 people.csv      # sort a CSV on the 3rd field
```

| Option | Effect |
|---|---|
| `-k`, `--key=KEYDEF` | Sort on the key `KEYDEF`. May be given more than once; keys are tried in order. |
| `-t`, `--field-separator=SEP` | Use `SEP` to split fields, instead of the whitespace default. |

## Checking and merging

| Option | Effect |
|---|---|
| `-c`, `--check` | Do not sort — just check whether the input is already sorted, and report the first line that is out of order. |
| `-C`, `--check=silent` | Check, but report only through the exit status. |
| `-m`, `--merge` | Treat the inputs as already-sorted files and merge them, which is faster than a full sort. |

## Output and resources

| Option | Effect |
|---|---|
| `-o`, `--output=FILE` | Write to `FILE` instead of standard output. `FILE` may be one of the inputs. |
| `-z`, `--zero-terminated` | Treat the NUL character as the line delimiter. |
| `--parallel=N` | Use `N` threads. |
| `-S`, `--buffer-size=SIZE` | Set the size of the in-memory sort buffer. |
| `-T`, `--temporary-directory=DIR` | Put temporary files in `DIR` rather than the default location. |
| `--files0-from=F` | Take the list of input files from `F`, NUL-separated. |
| `--debug` | Underline the part of each line that was actually used as the sort key — invaluable when a `-k` key is not behaving. |

## Exit status

| Code | Meaning |
|---|---|
| `0` | The lines were sorted — or, with `-c`/`-C`, the input was already sorted. |
| `1` | With `-c`/`-C`, the input was *not* sorted. |
| `2` | An error — a file could not be read, or an option was invalid. |

---

# uniq

_Peios / Using Peios / Peiosutils / Transforming text_

> Collapse or report adjacent repeated lines in a file.

`uniq` deals with repeated lines: it can collapse a run of identical lines into one, count them, or print only the ones that repeated.

```
uniq [options] [input [output]]
```

```
$ uniq events.txt
```

`input` and `output` may be given as operands; with neither, `uniq` reads standard input and writes standard output.

## uniq only sees adjacent duplicates

This is the one thing to know about `uniq`: it only compares **each line with the one before it**. It collapses *adjacent* repeats. Duplicate lines scattered through a file, with other lines between them, are not caught.

So `uniq` is almost always paired with [`sort`](/peios/using-peios/peiosutils/transforming-text/sort.md), which brings every copy of a line together first:

```
$ sort events.txt | uniq
```

If collapsing duplicates is all you need, `sort -u` does both jobs in one command. Use `uniq` itself when you want what `sort -u` cannot do — counting repeats, or printing only the duplicated lines.

## What to output

By default `uniq` prints every line, with each run of adjacent duplicates reduced to a single copy. These options change that:

| Option | Effect |
|---|---|
| `-c`, `--count` | Prefix each line with the number of times it occurred. |
| `-d`, `--repeated` | Print only lines that *were* repeated — one copy of each. |
| `-D` | Print *all* copies of every repeated line, not just one. |
| `-u`, `--unique` | Print only lines that were *not* repeated. |
| `--group[=WHICH]` | Print every line, with runs separated by a blank line. `WHICH` is `separate`, `prepend`, `append`, or `both`. |

## What counts as "the same"

| Option | Effect |
|---|---|
| `-i`, `--ignore-case` | Treat lines differing only in letter case as the same. |
| `-f`, `--skip-fields=N` | Ignore the first `N` fields when comparing. |
| `-s`, `--skip-chars=N` | Ignore the first `N` characters when comparing. |
| `-w`, `--check-chars=N` | Compare at most `N` characters of each line. |

## Other options

| Option | Effect |
|---|---|
| `-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 written. |

---

# tr

_Peios / Using Peios / Peiosutils / Transforming text_

> Translate, squeeze, or delete individual characters in a stream of text.

`tr` — "translate" — works on text one **character** at a time. It can replace characters with other characters, remove characters, or collapse runs of a character into one.

```
tr [options] set1 [set2]
```

`tr` reads standard input and writes standard output — it has no file arguments, so it always sits in a pipeline.

```
$ tr 'a-z' 'A-Z' < notes.txt        # lower-case to upper-case
$ tr -d ' ' < spaced.txt            # delete every space
$ tr -s ' ' < padded.txt            # collapse runs of spaces to one
```

## The three jobs

What `tr` does depends on the options and how many sets you give it.

- **Translate** — give two sets. Each character in `set1` is replaced by the character at the same position in `set2`. `tr 'abc' 'xyz'` turns every `a` into `x`, `b` into `y`, `c` into `z`.
- **Delete** (`-d`) — give one set. Every character in `set1` is removed.
- **Squeeze** (`-s`) — each run of a repeated character that appears in the relevant set is collapsed to a single occurrence.

`-d` and `-s` can be combined: delete one set of characters, then squeeze another.

## Writing a set

A set is a string of characters, with a few shorthands:

| Notation | Means |
|---|---|
| `a-z` | A range — every character from `a` to `z`. |
| `[:alpha:]`, `[:digit:]`, `[:space:]`, … | A named character class. |
| `[=c=]` | An equivalence class — every character that sorts the same as `c`. |
| `[c*n]` | The character `c` repeated `n` times — for padding a set to a length. |
| `\n`, `\t`, `\\`, `\NNN` | Escapes — newline, tab, backslash, an octal byte. |

## Options

| Option | Effect |
|---|---|
| `-d`, `--delete` | Delete the characters in `set1` instead of translating. |
| `-s`, `--squeeze-repeats` | Collapse each run of a repeated character listed in the last set into one. |
| `-c`, `-C`, `--complement` | Operate on the *complement* of `set1` — every character it does **not** list. |
| `-t`, `--truncate-set1` | Before translating, shorten `set1` to the length of `set2`, rather than reusing `set2`'s last character to cover the surplus. |

## Exit status

| Code | Meaning |
|---|---|
| `0` | Success. |
| `1` | A usage error — the wrong number of sets, or a malformed set. |

---

# expand

_Peios / Using Peios / Peiosutils / Transforming text_

> Convert tab characters in a file into spaces.

`expand` converts tab characters into spaces, so that text lines up the same way no matter what tab width something is viewed with.

```
expand [options] [file...]
```

```
$ expand source.txt > source-spaces.txt
```

A tab is not a fixed number of spaces — it jumps to the next tab stop, and where those stops are is a display setting. `expand` removes the ambiguity: it replaces each tab with exactly the number of spaces needed to reach the same column, baking the layout in. With no file, it reads standard input.

[`unexpand`](/peios/using-peios/peiosutils/transforming-text/unexpand.md) is the reverse operation.

## Options

| Option | Effect |
|---|---|
| `-t`, `--tabs=N` | Set tab stops every `N` columns instead of the default 8. |
| `-t`, `--tabs=LIST` | Given a comma-separated list, place tab stops at those explicit column positions. |
| `-i`, `--initial` | Convert only the tabs that come before the first non-blank character on each line — leave tabs *within* the text alone. Useful for re-indenting code without disturbing aligned tabs inside it. |

## Exit status

| Code | Meaning |
|---|---|
| `0` | Success. |
| `1` | A file could not be read, or a tab specification was invalid. |

---

# unexpand

_Peios / Using Peios / Peiosutils / Transforming text_

> Convert runs of spaces in a file back into tab characters.

`unexpand` is the reverse of [`expand`](/peios/using-peios/peiosutils/transforming-text/expand.md): it converts runs of spaces back into tab characters.

```
unexpand [options] [file...]
```

```
$ unexpand spaced.txt > tabbed.txt
```

Where a run of spaces reaches a tab stop, `unexpand` replaces it with a tab. By default it only converts the **leading** spaces on each line — the indentation — and leaves spacing within the text alone. With no file, it reads standard input.

## Options

| Option | Effect |
|---|---|
| `-t`, `--tabs=N` | Set tab stops every `N` columns instead of the default 8. A comma-separated list places stops at explicit column positions. Using `-t` also enables `-a`. |
| `-a`, `--all` | Convert *all* runs of spaces that reach a tab stop, not only the leading indentation. |
| `--first-only` | Convert only the leading run of blanks on each line. Overrides `-a`. |

## Exit status

| Code | Meaning |
|---|---|
| `0` | Success. |
| `1` | A file could not be read, or a tab specification was invalid. |

---

# fmt

_Peios / Using Peios / Peiosutils / Transforming text_

> Reflow paragraphs of text to a target line width.

`fmt` reflows paragraphs: it rejoins the lines of a paragraph and re-breaks them so each comes out close to a target width. Words move freely between lines to make the result fit.

```
fmt [options] [file...]
```

```
$ fmt -w 72 draft.txt
```

`fmt` works on **paragraphs** — runs of non-blank lines separated by blank lines — and treats word boundaries as places it may break. The result reads naturally. This is what distinguishes it from [`fold`](/peios/using-peios/peiosutils/transforming-text/fold.md), which simply cuts every line at a fixed column without regard to words.

With no file, `fmt` reads standard input.

## Setting the width

| Option | Effect |
|---|---|
| `-w`, `--width=WIDTH` | Fill lines up to at most `WIDTH` columns. The default is 75. |
| `-g`, `--goal=WIDTH` | Aim for `WIDTH` columns — the width `fmt` targets, while `-w` is the hard maximum. Defaults to about 93% of the maximum. |

## Controlling the reflow

| Option | Effect |
|---|---|
| `-s`, `--split-only` | Only split lines that are too long; never join short lines together. |
| `-u`, `--uniform-spacing` | Put exactly one space between words and two between sentences. |
| `-c`, `--crown-margin` | Preserve the indentation of a paragraph's first two lines; indent the rest to match the second. |
| `-t`, `--tagged-paragraph` | Like `-c`, but the first line *must* be indented differently from the second, or the two are treated as separate paragraphs. |
| `-q`, `--quick` | Break lines faster, accepting a more ragged right edge. |

## Selecting which lines to format

| Option | Effect |
|---|---|
| `-p`, `--prefix=PREFIX` | Reformat only lines that begin with `PREFIX`; reattach `PREFIX` afterwards. Useful for reflowing comment blocks in source code. |
| `-m`, `--preserve-headers` | Detect and preserve mail-style header lines rather than reflowing them. |
| `--tab-width=N` | Treat a tab as `N` columns when measuring line length. Tabs are kept in the output; this affects measurement only. |

## Exit status

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

---

# fold

_Peios / Using Peios / Peiosutils / Transforming text_

> Hard-wrap long lines at a fixed width.

`fold` breaks long lines so that none exceeds a fixed width. Every line longer than the limit is cut into pieces.

```
fold [options] [file...]
```

```
$ fold -w 80 wide.txt
```

By default `fold` wraps at 80 columns, and it cuts at exactly that column — even in the middle of a word. That hard cut is the difference between `fold` and [`fmt`](/peios/using-peios/peiosutils/transforming-text/fmt.md): `fmt` reflows paragraphs and breaks between words; `fold` just enforces a width, mechanically. Use `fold` when you need a guarantee that no line is wider than `N`; use `fmt` when you want the result to read well.

With no file, `fold` reads standard input.

## Options

| Option | Effect |
|---|---|
| `-w`, `--width=WIDTH` | Wrap at `WIDTH` columns instead of 80. |
| `-s`, `--spaces` | Break at a space within the width where one exists, rather than mid-word — a gentler wrap. |
| `-b`, `--bytes` | Count bytes rather than display columns. Control characters such as tab and newline then count as ordinary bytes. |
| `-c`, `--characters` | Count character positions rather than display columns. |

## Exit status

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

---

# pr

_Peios / Using Peios / Peiosutils / Transforming text_

> Paginate and columnate text for printing.

`pr` prepares text for printing on paper. It breaks a file into **pages**, puts a header and a trailer on each, and can arrange the text into columns.

```
pr [options] [file...]
```

```
$ pr report.txt
```

Run plainly, `pr` divides the input into 66-line pages, each beginning with a five-line header — the date, the file name, and a page number — and ending with a trailing margin. With no file, it reads standard input.

## Columns

`pr` can lay text out in several columns per page.

| Option | Effect |
|---|---|
| `-COLUMN` | Produce `COLUMN` columns per page (e.g. `-3` for three). Text fills down the first column, then the next. |
| `-a`, `--across` | Fill the columns *across* — line 1 in column 1, line 2 in column 2, and so on — rather than down. |
| `-m`, `--merge` | Print several files side by side, one per column. |
| `-w`, `--width=WIDTH` | Set the page width, for multi-column output. |

## The header and the page

| Option | Effect |
|---|---|
| `-h`, `--header=TEXT` | Use `TEXT` in the header instead of the file name. |
| `-t`, `--omit-header` | Print neither the header nor the trailer. |
| `-T`, `--omit-pagination` | Drop the header, the trailer, and all pagination — just the text. |
| `-l`, `--length=LINES` | Set the page length to `LINES` instead of 66. |
| `-o`, `--indent=N` | Indent every line by `N` spaces. |
| `-D`, `--date-format=FORMAT` | Format the header's date with `FORMAT`. |
| `-F`, `-f`, `--form-feed` | Separate pages with a form-feed character rather than blank lines. |

## Selecting and numbering

| Option | Effect |
|---|---|
| `--pages=FIRST[:LAST]` | Print only pages `FIRST` through `LAST`. |
| `-n`, `--number-lines[=SEP[WIDTH]]` | Number every line. |
| `-N`, `--first-line-number=N` | Begin line numbering at `N`. |
| `-d`, `--double-space` | Double-space the output. |

## Other options

| Option | Effect |
|---|---|
| `-s`, `--separator-char[=CHAR]` | Separate columns with a single `CHAR` (default tab) rather than padding with spaces. |
| `-S`, `--sep-string[=STRING]` | Separate columns with `STRING`. |
| `-e`, `--expand-tabs[=CHAR[WIDTH]]` | Expand input tabs to spaces. |
| `-J`, `--join-lines` | Merge full lines, turning off width truncation. |
| `-r`, `--no-file-warnings` | Do not warn when a file cannot be opened. |

## Exit status

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

---

# ptx

_Peios / Using Peios / Peiosutils / Transforming text_

> Produce a permuted index of the words in a file.

`ptx` produces a **permuted index** — a concordance. For each significant word in the input, it prints a line showing that word together with the text around it, so the same passage appears once per keyword it contains.

```
ptx [options] [input...]
```

```
$ ptx manual.txt
```

A permuted index is the kind of index found at the back of a reference book: every keyword, in alphabetical order, each shown in its context. `ptx` builds one from plain text. With no file, it reads standard input.

## Choosing the keywords

| Option | Effect |
|---|---|
| `-W`, `--word-regexp=REGEXP` | Treat anything matching `REGEXP` as a keyword. |
| `-b`, `--break-file=FILE` | Take the set of word-break characters from `FILE`. |
| `-i`, `--ignore-file=FILE` | Read a list of words to *exclude* from `FILE`. |
| `-o`, `--only-file=FILE` | Index *only* the words listed in `FILE`. |
| `-f`, `--ignore-case` | Fold case together when sorting. |

## Output format

| Option | Effect |
|---|---|
| `-w`, `--width=N` | Set the output width, in columns. |
| `-g`, `--gap-size=N` | Set the gap, in columns, between the output fields. |
| `-A`, `--auto-reference` | Generate a reference (file name and line number) for each entry automatically. |
| `-r`, `--references` | Treat the first field of each input line as a reference for that line. |
| `-R`, `--right-side-refs` | Put references on the right, and exclude them from the width count. |
| `-F`, `--flag-truncation=STRING` | Use `STRING` to mark where a line was truncated. |
| `-O`, `--format=roff` | Emit the index as `roff` typesetting directives. |
| `-T`, `--format=tex` | Emit the index as TeX typesetting directives. |
| `-M`, `--macro-name=NAME` | Use `NAME` as the macro name in `roff`/TeX output. |
| `-G`, `--traditional` | Behave like the older System V `ptx`, without the extended features. |

## Exit status

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

---

# tsort

_Peios / Using Peios / Peiosutils / Transforming text_

> Topologically sort items so that each comes after the things it depends on.

`tsort` performs a **topological sort**. Given a set of "this must come before that" rules, it produces an order in which everything appears after the things it depends on.

```
tsort [file]
```

```
$ tsort dependencies.txt
```

With no file, `tsort` reads standard input.

## The input

`tsort` reads its input as a flat sequence of whitespace-separated tokens, taken **in pairs**. Each pair `A B` means "A must come before B" — an edge in a dependency graph.

```
compiler  linker
linker    installer
compiler  installer
```

That input says the linker depends on the compiler, the installer on the linker, and the installer on the compiler. `tsort` reads the pairs and prints the items in a valid order:

```
compiler
linker
installer
```

A token paired with itself (`A A`) simply introduces `A` with no dependency — a way to list an item that nothing else mentions.

## Cycles

A topological order only exists if the dependencies form no **cycle**. If A must come before B and B must come before A, there is no valid order. `tsort` detects this, reports the loop it found, and exits with a failure status — it still prints an order, but the cycle means that order cannot satisfy every rule.

## Where it is used

`tsort` answers "what order do I do these in?" — building components in dependency order, scheduling tasks, sequencing anything where some steps must precede others. It is the dependency-aware counterpart to [`sort`](/peios/using-peios/peiosutils/transforming-text/sort.md), which orders by value rather than by dependency.

## Exit status

| Code | Meaning |
|---|---|
| `0` | A valid order was produced. |
| `1` | The input contained a cycle, had an odd number of tokens, or could not be read. |

---

# wc

_Peios / Using Peios / Peiosutils / Transforming text_

> Count the lines, words, and bytes in files.

`wc` — "word count" — counts what is in a file: its lines, its words, and its bytes.

```
wc [options] [file...]
```

```
$ wc report.txt
  214  1832 12044 report.txt
```

By default `wc` prints three numbers per file — **lines, words, bytes** — followed by the file name. Given several files, it adds a `total` line. With no file, it reads standard input.

## Choosing what to count

Pass any of these and `wc` prints only the counts you ask for, in the fixed order lines, words, characters/bytes, longest-line:

| Option | Counts |
|---|---|
| `-l`, `--lines` | The number of lines. |
| `-w`, `--words` | The number of words — runs of non-whitespace. |
| `-c`, `--bytes` | The number of bytes. |
| `-m`, `--chars` | The number of characters. This differs from `-c` for multi-byte text, where one character is several bytes. |
| `-L`, `--max-line-length` | The length of the longest line. |

```
$ wc -l report.txt        # just the line count
214 report.txt
```

## Other options

| Option | Effect |
|---|---|
| `--files0-from=F` | Take the list of files to count from `F`, as NUL-terminated names. `-` reads the list from standard input. |
| `--total=WHEN` | Control the `total` line: `auto` (the default — shown for more than one file), `always`, `only` (just the total, no per-file lines), or `never`. |

## Exit status

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

---

# shuf

_Peios / Using Peios / Peiosutils / Transforming text_

> Output the input lines in a random order.

`shuf` shuffles: it outputs its input lines in a random order. Every possible ordering is equally likely.

```
shuf [options] [file]
shuf -e [options] arg...
shuf -i lo-hi [options]
```

```
$ shuf playlist.txt
```

`shuf` is the opposite of [`sort`](/peios/using-peios/peiosutils/transforming-text/sort.md) — instead of imposing an order, it removes one. With no file, it reads standard input.

## Where the lines come from

`shuf` has three ways of getting its input, one per usage form:

| Option | Input is… |
|---|---|
| (a file, or stdin) | the lines of the file. |
| `-e`, `--echo` | the command-line arguments, each treated as one line. |
| `-i`, `--input-range=LO-HI` | the integers from `LO` to `HI`, each treated as one line. |

```
$ shuf -e red green blue          # shuffle three given words
$ shuf -i 1-100                   # the numbers 1..100 in random order
```

## Shaping the output

| Option | Effect |
|---|---|
| `-n`, `--head-count=COUNT` | Output at most `COUNT` lines — a random *sample* rather than the whole shuffle. |
| `-r`, `--repeat` | Allow lines to be repeated, so output can be longer than the input. Pair with `-n` to set how many. |
| `-o`, `--output=FILE` | Write to `FILE` instead of standard output. |
| `-z`, `--zero-terminated` | Treat the NUL character as the line delimiter. |

`shuf -n 1` is a common idiom — pick one random line.

## Reproducible shuffles

A shuffle is random by default. To get the *same* shuffle every time — for a repeatable test, say — fix the randomness:

| Option | Effect |
|---|---|
| `--random-seed=STRING` | Seed the shuffle with `STRING`. The same seed gives the same shuffle. |
| `--random-source=FILE` | Take the random bytes from `FILE`. The same file gives the same shuffle. Cannot be combined with `--random-seed`. |

## Exit status

| Code | Meaning |
|---|---|
| `0` | Success. |
| `1` | A failure — the input could not be read, or `-r` was used with no lines to repeat. |
