Peios Learn
Products
PePeios pkpekit PvProvium UDUniversal Directory TrTrail PrProject WiWispist
Using Peios Security Basics Technical Documentation Source
Using Peios Security Basics Technical Documentation Source
Peios

Transforming text

Single-page view · as markdown

Transforming text

Peios / Using Peios / Peiosutils / Transforming text

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, covers printing and combining files; this topic is about changing the text itself.

The commands #

Ordering lines

CommandPurpose
sortSort lines — alphabetically, numerically, and many other ways.
shufThe opposite of sorting: put lines into a random order.
tsortTopological sort — order items so that each comes after the things it depends on.

Filtering lines

CommandPurpose
uniqCollapse or report adjacent repeated lines.

Substituting characters

CommandPurpose
trTranslate, squeeze, or delete individual characters.

Whitespace

CommandPurpose
expandConvert tabs into spaces.
unexpandConvert runs of spaces back into tabs.

Reflowing and paginating

CommandPurpose
fmtReflow paragraphs to a target width.
foldHard-wrap long lines at a fixed width.
prPaginate and columnate text for printing.

Indexing and counting

CommandPurpose
ptxProduce a permuted index of the words in a file.
wcCount the lines, words, and bytes in a file.

Two commands that need sorted input #

A theme worth knowing before you start: uniq 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 is the workhorse of the topic and the one with the most depth — start there.

sort

Peios / Using Peios / Peiosutils / Transforming text

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:

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

And these adjust what is compared:

OptionEffect
-f, --ignore-caseTreat lower and upper case as the same.
-d, --dictionary-orderConsider only letters, digits, and blanks.
-i, --ignore-nonprintingIgnore non-printing characters.
-b, --ignore-leading-blanksIgnore blanks at the start of a line (or field).

Sort order options #

OptionEffect
-r, --reverseReverse the result.
-u, --uniqueOutput only the first line of each run of equal lines — sort and de-duplicate in one step.
-s, --stableKeep 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
OptionEffect
-k, --key=KEYDEFSort on the key KEYDEF. May be given more than once; keys are tried in order.
-t, --field-separator=SEPUse SEP to split fields, instead of the whitespace default.

Checking and merging #

OptionEffect
-c, --checkDo not sort — just check whether the input is already sorted, and report the first line that is out of order.
-C, --check=silentCheck, but report only through the exit status.
-m, --mergeTreat the inputs as already-sorted files and merge them, which is faster than a full sort.

Output and resources #

OptionEffect
-o, --output=FILEWrite to FILE instead of standard output. FILE may be one of the inputs.
-z, --zero-terminatedTreat the NUL character as the line delimiter.
--parallel=NUse N threads.
-S, --buffer-size=SIZESet the size of the in-memory sort buffer.
-T, --temporary-directory=DIRPut temporary files in DIR rather than the default location.
--files0-from=FTake the list of input files from F, NUL-separated.
--debugUnderline the part of each line that was actually used as the sort key — invaluable when a -k key is not behaving.

Exit status #

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

uniq

Peios / Using Peios / Peiosutils / Transforming text

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, 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:

OptionEffect
-c, --countPrefix each line with the number of times it occurred.
-d, --repeatedPrint only lines that were repeated — one copy of each.
-DPrint all copies of every repeated line, not just one.
-u, --uniquePrint 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" #

OptionEffect
-i, --ignore-caseTreat lines differing only in letter case as the same.
-f, --skip-fields=NIgnore the first N fields when comparing.
-s, --skip-chars=NIgnore the first N characters when comparing.
-w, --check-chars=NCompare at most N characters of each line.

Other options #

OptionEffect
-z, --zero-terminatedTreat the NUL character as the line delimiter.

Exit status #

CodeMeaning
0Success.
1A file could not be read or written.

tr

Peios / Using Peios / Peiosutils / Transforming 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:

NotationMeans
a-zA 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, \\, \NNNEscapes — newline, tab, backslash, an octal byte.

Options #

OptionEffect
-d, --deleteDelete the characters in set1 instead of translating.
-s, --squeeze-repeatsCollapse each run of a repeated character listed in the last set into one.
-c, -C, --complementOperate on the complement of set1 — every character it does not list.
-t, --truncate-set1Before translating, shorten set1 to the length of set2, rather than reusing set2's last character to cover the surplus.

Exit status #

CodeMeaning
0Success.
1A usage error — the wrong number of sets, or a malformed set.

expand

Peios / Using Peios / Peiosutils / Transforming text

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 is the reverse operation.

Options #

OptionEffect
-t, --tabs=NSet tab stops every N columns instead of the default 8.
-t, --tabs=LISTGiven a comma-separated list, place tab stops at those explicit column positions.
-i, --initialConvert 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 #

CodeMeaning
0Success.
1A file could not be read, or a tab specification was invalid.

unexpand

Peios / Using Peios / Peiosutils / Transforming text

unexpand is the reverse of expand: 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 #

OptionEffect
-t, --tabs=NSet 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, --allConvert all runs of spaces that reach a tab stop, not only the leading indentation.
--first-onlyConvert only the leading run of blanks on each line. Overrides -a.

Exit status #

CodeMeaning
0Success.
1A file could not be read, or a tab specification was invalid.

fmt

Peios / Using Peios / Peiosutils / Transforming text

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, which simply cuts every line at a fixed column without regard to words.

With no file, fmt reads standard input.

Setting the width #

OptionEffect
-w, --width=WIDTHFill lines up to at most WIDTH columns. The default is 75.
-g, --goal=WIDTHAim for WIDTH columns — the width fmt targets, while -w is the hard maximum. Defaults to about 93% of the maximum.

Controlling the reflow #

OptionEffect
-s, --split-onlyOnly split lines that are too long; never join short lines together.
-u, --uniform-spacingPut exactly one space between words and two between sentences.
-c, --crown-marginPreserve the indentation of a paragraph's first two lines; indent the rest to match the second.
-t, --tagged-paragraphLike -c, but the first line must be indented differently from the second, or the two are treated as separate paragraphs.
-q, --quickBreak lines faster, accepting a more ragged right edge.

Selecting which lines to format #

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

Exit status #

CodeMeaning
0Success.
1A file could not be read, or an option value was invalid.

fold

Peios / Using Peios / Peiosutils / Transforming text

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: 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 #

OptionEffect
-w, --width=WIDTHWrap at WIDTH columns instead of 80.
-s, --spacesBreak at a space within the width where one exists, rather than mid-word — a gentler wrap.
-b, --bytesCount bytes rather than display columns. Control characters such as tab and newline then count as ordinary bytes.
-c, --charactersCount character positions rather than display columns.

Exit status #

CodeMeaning
0Success.
1A file could not be read, or the width was invalid.

pr

Peios / Using Peios / Peiosutils / Transforming text

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.

OptionEffect
-COLUMNProduce COLUMN columns per page (e.g. -3 for three). Text fills down the first column, then the next.
-a, --acrossFill the columns across — line 1 in column 1, line 2 in column 2, and so on — rather than down.
-m, --mergePrint several files side by side, one per column.
-w, --width=WIDTHSet the page width, for multi-column output.

The header and the page #

OptionEffect
-h, --header=TEXTUse TEXT in the header instead of the file name.
-t, --omit-headerPrint neither the header nor the trailer.
-T, --omit-paginationDrop the header, the trailer, and all pagination — just the text.
-l, --length=LINESSet the page length to LINES instead of 66.
-o, --indent=NIndent every line by N spaces.
-D, --date-format=FORMATFormat the header's date with FORMAT.
-F, -f, --form-feedSeparate pages with a form-feed character rather than blank lines.

Selecting and numbering #

OptionEffect
--pages=FIRST[:LAST]Print only pages FIRST through LAST.
-n, --number-lines[=SEP[WIDTH]]Number every line.
-N, --first-line-number=NBegin line numbering at N.
-d, --double-spaceDouble-space the output.

Other options #

OptionEffect
-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-linesMerge full lines, turning off width truncation.
-r, --no-file-warningsDo not warn when a file cannot be opened.

Exit status #

CodeMeaning
0Success.
1A file could not be read, or an option was invalid.

ptx

Peios / Using Peios / Peiosutils / Transforming text

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 #

OptionEffect
-W, --word-regexp=REGEXPTreat anything matching REGEXP as a keyword.
-b, --break-file=FILETake the set of word-break characters from FILE.
-i, --ignore-file=FILERead a list of words to exclude from FILE.
-o, --only-file=FILEIndex only the words listed in FILE.
-f, --ignore-caseFold case together when sorting.

Output format #

OptionEffect
-w, --width=NSet the output width, in columns.
-g, --gap-size=NSet the gap, in columns, between the output fields.
-A, --auto-referenceGenerate a reference (file name and line number) for each entry automatically.
-r, --referencesTreat the first field of each input line as a reference for that line.
-R, --right-side-refsPut references on the right, and exclude them from the width count.
-F, --flag-truncation=STRINGUse STRING to mark where a line was truncated.
-O, --format=roffEmit the index as roff typesetting directives.
-T, --format=texEmit the index as TeX typesetting directives.
-M, --macro-name=NAMEUse NAME as the macro name in roff/TeX output.
-G, --traditionalBehave like the older System V ptx, without the extended features.

Exit status #

CodeMeaning
0Success.
1A file could not be read, or an option value was invalid.

tsort

Peios / Using Peios / Peiosutils / Transforming text

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, which orders by value rather than by dependency.

Exit status #

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

wc

Peios / Using Peios / Peiosutils / Transforming text

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:

OptionCounts
-l, --linesThe number of lines.
-w, --wordsThe number of words — runs of non-whitespace.
-c, --bytesThe number of bytes.
-m, --charsThe number of characters. This differs from -c for multi-byte text, where one character is several bytes.
-L, --max-line-lengthThe length of the longest line.
$ wc -l report.txt        # just the line count
214 report.txt

Other options #

OptionEffect
--files0-from=FTake the list of files to count from F, as NUL-terminated names. - reads the list from standard input.
--total=WHENControl 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 #

CodeMeaning
0Every file was counted.
1A file could not be read.

shuf

Peios / Using Peios / Peiosutils / Transforming text

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 — 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:

OptionInput is…
(a file, or stdin)the lines of the file.
-e, --echothe command-line arguments, each treated as one line.
-i, --input-range=LO-HIthe 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 #

OptionEffect
-n, --head-count=COUNTOutput at most COUNT lines — a random sample rather than the whole shuffle.
-r, --repeatAllow lines to be repeated, so output can be longer than the input. Pair with -n to set how many.
-o, --output=FILEWrite to FILE instead of standard output.
-z, --zero-terminatedTreat 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:

OptionEffect
--random-seed=STRINGSeed the shuffle with STRING. The same seed gives the same shuffle.
--random-source=FILETake the random bytes from FILE. The same file gives the same shuffle. Cannot be combined with --random-seed.

Exit status #

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

Peios Learn — documentation for the Peios project.

Built with Trail.