# Output and evaluation

---

# Output and evaluation

_Peios / Using Peios / Peiosutils / Output and evaluation_

> The commands that produce text, work with the environment, convert numbers, and evaluate expressions and conditions.

This topic gathers the small, sharp commands that scripts are built from: the ones that **print** something, that read or set the **environment**, that **evaluate** an expression or a condition, and that simply **succeed or fail**.

## The commands

**Producing text**

| Command | Purpose |
|---|---|
| [`echo`](/peios/using-peios/peiosutils/output-and-evaluation/echo.md) | Print its arguments as a line of text. |
| [`printf`](/peios/using-peios/peiosutils/output-and-evaluation/printf.md) | Print text from a format string, with precise control over layout. |
| [`yes`](/peios/using-peios/peiosutils/output-and-evaluation/yes.md) | Print a line over and over, without stopping. |
| [`seq`](/peios/using-peios/peiosutils/output-and-evaluation/seq.md) | Print a sequence of numbers. |
| [`tee`](/peios/using-peios/peiosutils/output-and-evaluation/tee.md) | Copy standard input to standard output and to each named file. |

**The environment**

| Command | Purpose |
|---|---|
| [`env`](/peios/using-peios/peiosutils/output-and-evaluation/env.md) | Run a command with a modified environment — or print the current one. |
| [`printenv`](/peios/using-peios/peiosutils/output-and-evaluation/printenv.md) | Print environment variables. |

**Numbers**

| Command | Purpose |
|---|---|
| [`numfmt`](/peios/using-peios/peiosutils/output-and-evaluation/numfmt.md) | Convert numbers to and from human-readable forms (`1.5G`, `1000000`). |
| [`factor`](/peios/using-peios/peiosutils/output-and-evaluation/factor.md) | Print the prime factors of a number. |

**Evaluating**

| Command | Purpose |
|---|---|
| [`expr`](/peios/using-peios/peiosutils/output-and-evaluation/expr.md) | Evaluate an arithmetic, string, or comparison expression. |
| [`test`](/peios/using-peios/peiosutils/output-and-evaluation/test.md) | Evaluate a condition — a file check or a comparison — as a true/false result. |

**Exit status**

| Command | Purpose |
|---|---|
| [`true` and `false`](/peios/using-peios/peiosutils/output-and-evaluation/true-and-false.md) | Do nothing, and succeed — or do nothing, and fail. |

## A note on exit status

Several commands here exist to be used for their **exit status** rather than their output. Every command, when it finishes, leaves behind a number: `0` means success, anything else means a kind of failure. A shell's `if`, `&&`, and `||` all act on that number.

[`test`](/peios/using-peios/peiosutils/output-and-evaluation/test.md) is the clearest case — it prints nothing and exists *only* to set an exit status from a condition. [`true` and `false`](/peios/using-peios/peiosutils/output-and-evaluation/true-and-false.md) are the most minimal: fixed success and fixed failure. Where this topic's pages give an exit-status table, that number is often the whole point of the command.

## Where to start

For everyday printing, [`echo`](/peios/using-peios/peiosutils/output-and-evaluation/echo.md); for anything that needs columns, padding, or precise formatting, [`printf`](/peios/using-peios/peiosutils/output-and-evaluation/printf.md).

---

# echo

_Peios / Using Peios / Peiosutils / Output and evaluation_

> Print arguments as a line of text to standard output.

`echo` prints its arguments, separated by single spaces, followed by a newline.

```
echo [options] [string...]
```

```
$ echo Hello, Peios
Hello, Peios
```

It is the simplest way to put a line of text on standard output — printing a message, or feeding a fixed string into a pipe.

## Options

| Option | Effect |
|---|---|
| `-n` | Do not print the trailing newline. |
| `-e` | Interpret backslash escape sequences in the arguments (see below). |
| `-E` | Do **not** interpret escape sequences. This is the default. |

## Escape sequences

With `-e`, `echo` recognises these backslash sequences and prints the character they stand for:

| Sequence | Character |
|---|---|
| `\\` | A literal backslash. |
| `\n` | Newline. |
| `\t` | Horizontal tab. |
| `\r` | Carriage return. |
| `\b` | Backspace. |
| `\f` | Form feed. |
| `\v` | Vertical tab. |
| `\a` | Alert (the terminal bell). |
| `\e` | Escape. |
| `\0NNN` | The byte with octal value `NNN`. |
| `\xHH` | The byte with hexadecimal value `HH`. |
| `\c` | Stop — produce no further output. |

## `echo` and `printf`

`echo` is fixed: arguments, spaces, a newline. The moment you need *control* over the output — columns, padding, a number formatted a particular way, output with no spaces between pieces — use [`printf`](/peios/using-peios/peiosutils/output-and-evaluation/printf.md) instead. `printf` is also more predictable across environments, since `echo`'s handling of escapes and `-n` varies.

## A note on shells

Many command shells provide their own built-in `echo`, and the shell's version is what runs when you type `echo` at a prompt. Built-in versions vary — especially in how they treat `-n`, `-e`, and escape sequences — so their behaviour may differ from what is described here. 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 output was written. |
| `1` | The output could not be written. |

---

# printf

_Peios / Using Peios / Peiosutils / Output and evaluation_

> Print formatted text from a format string and a list of arguments.

`printf` prints text built from a **format string**. The format string is printed literally, except that escape sequences become characters and substitution fields are replaced by the arguments that follow.

```
printf format [argument...]
```

```
$ printf 'the letter %X comes before %X\n' 10 11
the letter A comes before B
```

Where [`echo`](/peios/using-peios/peiosutils/output-and-evaluation/echo.md) prints arguments as-is, `printf` gives you control: padding, column widths, number bases, fixed decimal places. It is the command for output that has to *line up* or *be exact*.

`printf` writes only what the format string says — there is no automatic trailing newline. Include `\n` yourself where you want one.

## Escape sequences

The format string interprets these backslash sequences:

| Sequence | Character |
|---|---|
| `\\` | Backslash. |
| `\n` `\t` `\r` | Newline, tab, carriage return. |
| `\b` `\f` `\v` `\a` | Backspace, form feed, vertical tab, alert. |
| `\e` | Escape. |
| `\NNN` | The byte with octal value `NNN`. |
| `\xHH` | The byte with hexadecimal value `HH`. |
| `\uHHHH`, `\UHHHHHHHH` | A Unicode character by hexadecimal code point. |
| `%%` | A literal `%`. |

## Substitution fields

A field begins with `%` and is replaced by the next argument, formatted accordingly.

| Field | Formats the argument as… |
|---|---|
| `%s` | a string. |
| `%b` | a string, with backslash escapes in it interpreted. |
| `%q` | a string, quoted so it is safe to reuse as shell input. |
| `%c` | a single character. |
| `%d`, `%i` | a signed integer. |
| `%u` | an unsigned integer. |
| `%x`, `%X` | an unsigned integer in hexadecimal (lower- or upper-case). |
| `%o` | an unsigned integer in octal. |
| `%f`, `%F` | a decimal floating-point number. |
| `%e`, `%E` | a number in scientific notation. |
| `%g`, `%G` | whichever of decimal or scientific notation is shorter. |

## Width and precision

Between the `%` and the field letter you may put two numbers — `%[width][.precision]field`:

- **width** — the minimum number of columns. Output narrower than this is padded with leading spaces; a negative width pads on the right instead.
- **precision** — after a `.`; its meaning depends on the field. For a string it is a *maximum length*; for an integer, a minimum digit count (zero-padded); for a float, the number of decimal places.

```
$ printf '%-10s %5.2f\n' apples 3.1
apples         3.10
```

## Reusing the format string

If more arguments are supplied than the format string has fields, `printf` **repeats the format string** until the arguments run out. If there are too few, the leftover fields default to an empty string (or `0` for a number).

```
$ printf '%s: %d\n' alpha 1 beta 2 gamma 3
alpha: 1
beta: 2
gamma: 3
```

## Exit status

| Code | Meaning |
|---|---|
| `0` | Success. |
| `1` | A missing operand, a bad format string, or a write failure. |

---

# yes

_Peios / Using Peios / Peiosutils / Output and evaluation_

> Print a line repeatedly until stopped.

`yes` prints a line over and over, without stopping.

```
yes [string...]
```

```
$ yes
y
y
y
...
```

With no argument it prints `y` forever. Given arguments, it prints them — joined by spaces — as the repeated line instead.

```
$ yes retry
retry
retry
...
```

`yes` never stops on its own. It ends when something downstream closes the pipe, or when you interrupt it with Ctrl-C.

## What it is for

`yes` exists to **answer prompts**. An older interactive command that asks "are you sure? [y/n]" again and again can be fed a stream of confirmations:

```
$ yes | slow-interactive-command
```

Most modern commands have a proper option for this — `rm -f`, and similar — and that is the better way when it exists. `yes` is the fallback for a command that offers no such option. It is also a quick way to generate an endless stream of identical lines for a test.

## Exit status

| Code | Meaning |
|---|---|
| `0` | The output was closed normally. |
| `1` | A write error occurred. |

---

# seq

_Peios / Using Peios / Peiosutils / Output and evaluation_

> Print a sequence of numbers from a start to an end.

`seq` prints a sequence of numbers, one per line.

```
seq [options] last
seq [options] first last
seq [options] first increment last
```

```
$ seq 3
1
2
3
$ seq 2 2 10
2
4
6
8
10
```

The three forms control where the sequence starts and how it steps:

- `seq last` — count from 1 up to `last`.
- `seq first last` — count from `first` up to `last`.
- `seq first increment last` — count from `first` to `last`, stepping by `increment`.

The increment may be negative, to count down, and the numbers may be fractional. `seq` is most often used to drive a loop a fixed number of times.

## Options

| Option | Effect |
|---|---|
| `-s`, `--separator=STRING` | Separate the numbers with `STRING` instead of a newline. |
| `-t`, `--terminator=STRING` | End the output with `STRING` instead of a newline. |
| `-w`, `--equal-width` | Pad the numbers with leading zeros so they all have the same width. |
| `-f`, `--format=FORMAT` | Format each number with a `printf`-style floating-point `FORMAT`. |

```
$ seq -s , 1 5
1,2,3,4,5
$ seq -w 8 10
08
09
10
```

`-f` takes a single floating-point conversion — see [`printf`](/peios/using-peios/peiosutils/output-and-evaluation/printf.md) for the format syntax — and cannot be combined with `-w`.

## Exit status

| Code | Meaning |
|---|---|
| `0` | The sequence was printed. |
| `1` | An argument was not a valid number, the increment was zero, or no argument was given. |

---

# env

_Peios / Using Peios / Peiosutils / Output and evaluation_

> Run a command with a modified environment, or print the current environment.

`env` runs a command with a changed **environment** — the set of `NAME=VALUE` variables a process inherits. Run with no command, it prints the current environment instead.

```
env [options] [NAME=VALUE]... [command [arg]...]
```

```
$ env LANG=C TZ=UTC my-program
$ env
PATH=/bin
HOME=/home/jack
...
```

## How it works

You give `env` a list of `NAME=VALUE` assignments, then a command. `env` applies the assignments to its own environment and then runs the command, which inherits the result. The assignments affect only that one run — your shell's environment is untouched.

This is the clean way to run something with a particular variable set, without changing it for everything else, and the standard way to run a command with one variable temporarily different.

With **no command**, `env` simply prints the environment it would have used — which, with no options, is the current one.

## Building the environment

| Option | Effect |
|---|---|
| `-i`, `--ignore-environment` | Start from an *empty* environment, not the inherited one — so the command sees only what you assign. A bare `-` argument means the same. |
| `-u`, `--unset=NAME` | Remove `NAME` from the environment. |
| `--file=FILE` | Read `NAME=VALUE` lines from a `.env`-style `FILE` and apply them. |

The order is: start (inherited, or empty with `-i`), apply `--file`, apply `--unset`, apply the `NAME=VALUE` arguments.

## Running the command

| Option | Effect |
|---|---|
| `-C`, `--chdir=DIR` | Change to `DIR` before running the command. |
| `--argv0=NAME` | Run the command but present `NAME` as its zeroth argument. |
| `-S`, `--split-string=S` | Split `S` into separate arguments. This exists for script interpreter lines, where everything after the interpreter arrives as one string. |

## Signal handling

`env` can adjust how the command treats signals before launching it:

| Option | Effect |
|---|---|
| `--ignore-signal[=SIG]` | Set the named signals to be ignored. |
| `--default-signal[=SIG]` | Reset the named signals to their default handling. |
| `--block-signal[=SIG]` | Block delivery of the named signals while the command runs. |
| `--list-signal-handling` | List the signal-handling changes the other options requested. |

## Other options

| Option | Effect |
|---|---|
| `-0`, `--null` | When printing the environment, end each line with a NUL character instead of a newline. Not valid together with a command. |
| `-v`, `--debug` | Print each processing step `env` performs. |

## Exit status

When `env` runs a command, it exits with **that command's** status. The exception is a failure in `env` itself:

| Code | Meaning |
|---|---|
| (command's own) | The command ran; this is its exit status. |
| `125` | `env` itself failed — for example, a bad option. |
| `126` | The command was found but could not be run. |
| `127` | The command was not found. |

---

# printenv

_Peios / Using Peios / Peiosutils / Output and evaluation_

> Print the values of environment variables.

`printenv` prints environment variables.

```
printenv [options] [variable...]
```

Name one or more variables and `printenv` prints the value of each. Name none and it prints the whole environment, one `NAME=VALUE` pair per line.

```
$ printenv HOME
/home/jack
$ printenv
PATH=/bin
HOME=/home/jack
...
```

## Options

| Option | Effect |
|---|---|
| `-0`, `--null` | End each output line with a NUL character instead of a newline — so values that themselves contain newlines can still be told apart. |

## `printenv` and `env`

Both can print the environment. `printenv` is the one built for *reading* it — it can pick out a single variable by name. [`env`](/peios/using-peios/peiosutils/output-and-evaluation/env.md) prints the environment too, but its real job is *running a command* with a modified one. Use `printenv` to look something up; use `env` to change something for a command.

## Exit status

| Code | Meaning |
|---|---|
| `0` | Every named variable was found and printed. |
| `1` | A named variable was not set. |
| `2` | A usage error. |

---

# numfmt

_Peios / Using Peios / Peiosutils / Output and evaluation_

> Convert numbers between plain digits and human-readable forms.

`numfmt` converts numbers between plain digits and **human-readable** forms — turning `1500000` into `1.5M`, or `1.5M` back into `1500000`.

```
numfmt [options] [number...]
```

```
$ numfmt --to=si 1500000
1.5M
$ numfmt --from=si 1.5M
1500000
```

`numfmt` takes numbers as arguments, or — with none — reads them from standard input, which lets it rescale a column of numbers flowing through a pipe.

## The direction of conversion

| Option | Effect |
|---|---|
| `--from=UNIT` | Parse input numbers that carry a `UNIT` suffix, scaling them up to plain digits. |
| `--to=UNIT` | Scale output numbers down and add a `UNIT` suffix. |

A `UNIT` is one of:

| Unit | Suffixes mean |
|---|---|
| `none` | No suffixes — a suffix is an error. The default. |
| `si` | Powers of 1000: `1K` = 1000, `1M` = 1000000. |
| `iec` | Powers of 1024: `1K` = 1024, `1M` = 1048576. |
| `iec-i` | Powers of 1024 with a two-letter suffix: `1Ki` = 1024, `1Mi` = 1048576. |
| `auto` | Accept any of the above on input, reading `Ki`/`Mi` as powers of 1024 and bare `K`/`M` as powers of 1000. |

## Working on fields

By default `numfmt` converts the whole input line. To convert numbers sitting in a *column* of wider text, name the field:

| Option | Effect |
|---|---|
| `--field=FIELDS` | Convert only the numbers in these fields. `FIELDS` uses the same range syntax as `cut` — `3`, `2-5`, `2-`. |
| `-d`, `--delimiter=X` | Use `X` to separate fields instead of whitespace. |
| `--header[=N]` | Pass the first `N` lines through unconverted, as a header. |

## Shaping the output

| Option | Effect |
|---|---|
| `--format=FORMAT` | Format the number with a `printf`-style floating-point `FORMAT`, controlling width, padding, and precision. |
| `--padding=N` | Pad the output to `N` columns — positive right-aligns, negative left-aligns. |
| `--grouping` | Group digits according to the locale (for example, `1,000,000`). |
| `--round=METHOD` | Choose the rounding method used when scaling. |
| `--suffix=SUFFIX` | Append `SUFFIX` to each result, and accept it on input. |
| `--from-unit=N` / `--to-unit=N` | Set the unit size the input or output is counted in. |

## Other options

| Option | Effect |
|---|---|
| `--invalid=MODE` | Choose what to do with input that is not a valid number: `abort`, `fail`, `warn`, or `ignore`. |
| `-z`, `--zero-terminated` | Treat the NUL character as the line delimiter. |
| `--debug` | Print warnings about questionable input. |

## Exit status

| Code | Meaning |
|---|---|
| `0` | Every number was converted. |
| `2` | An input was not a valid number, or an option was misused. |

---

# expr

_Peios / Using Peios / Peiosutils / Output and evaluation_

> Evaluate an arithmetic, string, or comparison expression and print the result.

`expr` evaluates a single expression and prints its value.

```
expr expression
```

```
$ expr 6 + 7
13
$ expr length "Peios"
5
```

Each part of the expression — every number, operator, and keyword — is a separate argument. That is why the spaces matter: `expr 6+7` is one argument and not an expression, while `expr 6 + 7` is three.

## Arithmetic

| Operator | Result |
|---|---|
| `ARG1 + ARG2` | Sum. |
| `ARG1 - ARG2` | Difference. |
| `ARG1 * ARG2` | Product. |
| `ARG1 / ARG2` | Integer quotient. |
| `ARG1 % ARG2` | Remainder. |

## Comparison

A comparison yields `1` for true and `0` for false. It is arithmetic when both sides are numbers, and lexical otherwise.

| Operator | True when… |
|---|---|
| `ARG1 = ARG2` | the two are equal. |
| `ARG1 != ARG2` | they are unequal. |
| `ARG1 < ARG2` | `ARG1` is less. |
| `ARG1 <= ARG2` | `ARG1` is less or equal. |
| `ARG1 > ARG2` | `ARG1` is greater. |
| `ARG1 >= ARG2` | `ARG1` is greater or equal. |

## Logic

| Operator | Result |
|---|---|
| `ARG1 \| ARG2` | `ARG1` if it is neither null nor `0`; otherwise `ARG2`. |
| `ARG1 & ARG2` | `ARG1` if neither argument is null or `0`; otherwise `0`. |

## String operations

| Form | Result |
|---|---|
| `length STRING` | The number of characters in `STRING`. |
| `substr STRING POS LENGTH` | `LENGTH` characters of `STRING`, counting `POS` from 1. |
| `index STRING CHARS` | The position of the first of any of `CHARS` in `STRING`, or `0`. |
| `STRING : REGEXP` | Match `REGEXP` anchored at the start of `STRING`. Returns the matched length, or the text captured by `\(…\)`. |
| `match STRING REGEXP` | The same as `STRING : REGEXP`. |

Many of these operators — `*`, `<`, `|`, `(` — are also meaningful to a shell, so quote or escape them so they reach `expr` intact.

## Exit status

`expr`'s exit status reports on the *value* it computed:

| Code | Meaning |
|---|---|
| `0` | The result was neither null nor `0`. |
| `1` | The result was null or `0`. |
| `2` | The expression was syntactically invalid. |
| `3` | An error occurred during evaluation — such as division by zero. |

---

# factor

_Peios / Using Peios / Peiosutils / Output and evaluation_

> Print the prime factors of numbers.

`factor` prints the prime factors of a number.

```
factor [options] [number...]
```

```
$ factor 360
360: 2 2 2 3 3 5
```

Each line of output is the original number, a colon, and its prime factors in increasing order, repeated as often as they divide in. Give several numbers and `factor` factors each; give none and it reads numbers from standard input.

## Options

| Option | Effect |
|---|---|
| `-h`, `--exponents` | Write a repeated factor in exponent form — `p^e` — instead of repeating it. |

```
$ factor -h 360
360: 2^3 3^2 5
```

## Exit status

| Code | Meaning |
|---|---|
| `0` | Every number was factored. |
| `1` | An input was not a valid positive integer. |

---

# test

_Peios / Using Peios / Peiosutils / Output and evaluation_

> Evaluate a condition — a file check or a comparison — and report the result as an exit status.

`test` evaluates a single condition and reports whether it is **true** or **false**. It prints nothing — the answer is its exit status: `0` for true, `1` for false. That makes it the command a shell's `if`, `while`, `&&`, and `||` are built on.

```
test expression
[ expression ]
```

The two forms are the same command. `[` is `test` under another name; when invoked as `[`, it requires a closing `]` as its last argument. `[ -f notes.txt ]` and `test -f notes.txt` are identical.

```
$ test -f notes.txt && echo "the file exists"
```

## File tests

### Existence and type

| Test | True when the file… |
|---|---|
| `-e FILE` | exists. |
| `-f FILE` | exists and is a regular file. |
| `-d FILE` | exists and is a directory. |
| `-L FILE`, `-h FILE` | exists and is a symbolic link. |
| `-p FILE` | exists and is a named pipe (FIFO). |
| `-S FILE` | exists and is a socket. |
| `-b FILE` | exists and is a block device. |
| `-c FILE` | exists and is a character device. |
| `-s FILE` | exists and is not empty. |

### Access

These three tests ask whether you may actually *use* the file:

| Test | True when… |
|---|---|
| `-r FILE` | you may read the file. |
| `-w FILE` | you may write the file. |
| `-x FILE` | you may execute the file, or search the directory. |

On Peios these are **real access checks**. `test` asks the kernel whether your token is granted the right in question — a live check against the file's [security descriptor](/peios/security-fundamentals/security-descriptors/overview.md), the same decision any actual read, write, or execute would face. The answer is therefore honest: `test -w FILE` is true exactly when a write would be permitted.

`-x` on a regular file means "you are permitted to execute it" — which is a different question from whether the file *is* an executable. A file can be runnable code and still fail `-x` for you, and the two are decided separately; see [Access decisions](/peios/security-fundamentals/access-decisions/overview.md).

### Comparing two files

| Test | True when… |
|---|---|
| `FILE1 -nt FILE2` | `FILE1` is newer than `FILE2`. |
| `FILE1 -ot FILE2` | `FILE1` is older than `FILE2`. |
| `FILE1 -ef FILE2` | both name the same file (same device and inode). |

### Other file tests

| Test | True when the file… |
|---|---|
| `-t FD` | file descriptor `FD` is open on a terminal. |
| `-N FILE` | has been modified since it was last read. |
| `-O FILE`, `-G FILE` | carries an owner-id / group-id field matching the caller's. |
| `-g FILE`, `-u FILE`, `-k FILE` | has its set-group-id, set-user-id, or sticky inode bit set. |

The last two rows probe **decorative inode fields**. The Peios access model does not consult them — they are stored on the inode and reported for completeness, but they carry no authority. For a true picture of what may be done to a file, use the access tests `-r`, `-w`, `-x` above, not `-O`, `-g`, or `-u`.

## String tests

| Test | True when… |
|---|---|
| `-n STRING` | `STRING` is not empty. A bare `STRING` means the same. |
| `-z STRING` | `STRING` is empty. |
| `STRING1 = STRING2` | the strings are equal. |
| `STRING1 != STRING2` | the strings are unequal. |
| `STRING1 < STRING2` | `STRING1` sorts before `STRING2`. |
| `STRING1 > STRING2` | `STRING1` sorts after `STRING2`. |

## Integer comparisons

| Test | True when… |
|---|---|
| `A -eq B` | `A` equals `B`. |
| `A -ne B` | `A` does not equal `B`. |
| `A -lt B` | `A` is less than `B`. |
| `A -le B` | `A` is less than or equal to `B`. |
| `A -gt B` | `A` is greater than `B`. |
| `A -ge B` | `A` is greater than or equal to `B`. |

## Combining conditions

| Form | Result |
|---|---|
| `! EXPRESSION` | The negation. |
| `( EXPRESSION )` | Grouping — escape the parentheses so the shell does not take them. |
| `EXPR1 -a EXPR2` | True when both are true. |
| `EXPR1 -o EXPR2` | True when either is true. |

`-a` and `-o` are genuinely ambiguous to parse and are best avoided. Combine separate `test` calls with the shell's own `&&` and `||` instead:

```
test -f notes.txt && test -r notes.txt
```

## A note on shells

Many command shells provide their own built-in `test` and `[`, and the shell's version is what runs when you type `test` at a prompt or in a script. A built-in may not behave as described here — in particular, the access tests `-r`, `-w`, and `-x` are the real access checks described above only when *this* command runs. 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 expression was true. |
| `1` | The expression was false. |
| `2` | The expression was malformed. |

---

# true and false

_Peios / Using Peios / Peiosutils / Output and evaluation_

> Two commands that do nothing — one always succeeds, the other always fails.

`true` and `false` do nothing at all. Their only product is an **exit status**: `true` always succeeds, `false` always fails.

```
true
false
```

```
$ true ; echo $?
0
$ false ; echo $?
1
```

`true` exits `0`. `false` exits `1`. They take no arguments that matter, produce no output, and have no effect on anything.

## What they are for

A command that is *only* an exit status is useful as a fixed value in places that expect a command:

- **An always-true or always-false loop.** `while true` is the standard way to write a loop that runs until something inside it breaks out.
- **A deliberate placeholder.** Setting a configurable command to `true` makes that step do nothing and "succeed"; `false` makes it a step that always fails.
- **A known result in a test.** When a script or a condition needs a guaranteed pass or fail to check against, `true` and `false` provide it.

They are the simplest commands there are — and the [overview](/peios/using-peios/peiosutils/output-and-evaluation/overview.md)'s note on exit status is the whole idea behind them.

## Exit status

| Code | Meaning |
|---|---|
| `0` | Returned by `true`, always. |
| `1` | Returned by `false`, always. |

---

# tee

_Peios / Using Peios / Peiosutils / Output and evaluation_

> Copy standard input to standard output and to each named file at once.

`tee` reads standard input and writes it, unchanged, to standard output **and** to each file you name. It is the T-junction of a pipeline: the data keeps flowing down the pipe while a copy is also captured on disk.

```
tee [options] [file...]
```

```
$ echo saved | tee note.txt
saved
$ cat note.txt
saved
```

The name is the shape of the letter T — one stream in, the same stream out two ways. That makes `tee` the tool for the moment you want to both *see* (or keep piping) some data and *keep* it at the same time.

## Writing to several places at once

Every byte that arrives on standard input is written to standard output and to each named file. Name more than one file and each one receives a full, identical copy:

```
$ producer | tee a.log b.log c.log | consumer
```

Here `producer`'s output reaches `consumer` down the pipe exactly as if `tee` were not there, and `a.log`, `b.log`, and `c.log` each end up holding the same complete copy of it. With no files named, `tee` copies input straight to standard output and nothing else — a plain pass-through.

`tee` does not buffer between reads: it writes each chunk out as it is read, so a file being written by `tee` fills up as the data flows, rather than all at once when the input ends.

## Overwrite or append

By default, each named file is **truncated** — opened fresh, so any existing contents are discarded before the new data is written. A file that does not exist is created.

With `-a` (`--append`), `tee` **appends** to each named file instead: existing contents are kept and the new data is added to the end. A file that does not exist is still created.

```
$ echo first  | tee log.txt        # log.txt now holds "first"
$ echo second | tee -a log.txt     # log.txt now holds "first" then "second"
```

## Creating a file inherits a security descriptor

When `tee` **creates** a new output file — a named file that did not already exist — that file needs a [security descriptor](/peios/security-fundamentals/security-descriptors/overview.md), and it inherits one from the directory it is created in. This is the same creation-inherits-a-descriptor rule that governs every file-creating tool on Peios; see [Files and directories](/peios/using-peios/peiosutils/files-and-directories/overview.md) for the shared model.

With `-a`, when the named file already exists, `tee` opens that existing file to append and creates nothing, so no new descriptor is involved. Whether opening a file to write succeeds — whether creating a new one or writing an existing one — is decided by the normal access check against the relevant directory or file. `tee` reports a file it cannot open and, by default, carries on with the outputs it *can* write.

## Files named `-`

`tee` gives no special meaning to `-`. A file argument of `-` refers to a file literally named `-` in the current directory; it is opened, created, and written exactly like any other named file. It is **not** a stand-in for standard output — standard output is always written and needs no naming.

## Ignoring interrupts

With `-i` (`--ignore-interrupts`), `tee` ignores the interrupt signal (the one a terminal sends on Ctrl-C). This lets `tee` keep copying to its files even as an interrupt tears down the rest of a pipeline, so the capture is not cut short.

## Behaviour on write errors

By default, if a write to one output fails, `tee` reports it and stops writing to *that* output, but keeps writing to the others; a broken-pipe error on standard output is treated quietly. Two options change this policy.

`-p` sets write-error behaviour so that errors on a pipe (a downstream reader that has gone away) are ignored while other write errors are still reported.

`--output-error[=MODE]` sets the policy explicitly. Given on its own, with no `=MODE`, it selects `warn-nopipe`. The modes are:

| Mode | Behaviour |
|---|---|
| `warn` | Warn on a write error to **any** output, including a broken pipe, and continue with the remaining outputs. |
| `warn-nopipe` | Warn on a write error that is **not** a pipe error, and continue. Broken-pipe errors are ignored. This is the mode selected by a bare `--output-error`. |
| `exit` | **Exit** on a write error to any output, including a broken pipe. |
| `exit-nopipe` | Exit on a write error that is **not** a pipe error. Broken-pipe errors are ignored. |

## Options

| Option | Effect |
|---|---|
| `-a`, `--append` | Append to each named file rather than truncating it. |
| `-i`, `--ignore-interrupts` | Ignore the interrupt signal. |
| `-p` | Ignore errors from writing to a broken pipe, still reporting other write errors. |
| `--output-error[=MODE]` | Set the write-error policy: `warn`, `warn-nopipe`, `exit`, or `exit-nopipe`. A bare `--output-error` means `warn-nopipe`. |

## Exit status

| Code | Meaning |
|---|---|
| `0` | The input was copied to standard output and every named file without error. |
| `1` | A file could not be opened, a write failed under a policy that reports or exits on it, or the input could not be read. |
