Skip to content

Built-in Commands

Endo provides a set of built-in commands that are executed directly by the shell, without spawning an external process. These builtins handle core shell operations, I/O, and environment management.


echo

Print arguments to standard output.

Syntax:

echo [arguments...]

Description: Writes its arguments to stdout, separated by spaces, followed by a newline.

Example:

echo "Hello, World!"
echo "The value is" $x

cd

Change the current working directory.

Syntax:

cd [directory]
cd -

Description: Changes the shell's working directory. With no argument, changes to $HOME. Supports tilde expansion (~, ~user). Use cd - to switch to the previous working directory ($OLDPWD).

Example:

cd /tmp
cd ~
cd ~/projects/endo
cd -          # returns to the previous directory

Tilde expansion for other users:

cd ~alice              # go to alice's home directory
cd ~bob/Documents      # go to bob's Documents folder
echo ~alice            # prints the resolved path

On POSIX systems, ~username is resolved via the system user database (getpwnam). On Windows, Endo derives the path from the current user's USERPROFILE parent directory -- for example, if USERPROFILE is C:\Users\chris, then ~alice resolves to C:\Users\alice (if that directory exists). See Platform Differences for details.


pwd

Print the current working directory.

Syntax:

pwd

Description: Outputs the absolute path of the current working directory.

Example:

pwd
# /home/alice/projects

exit

Exit the shell.

Syntax:

exit [code]

Description: Terminates the shell with the given exit code. Defaults to 0 (success) if no code is provided.

Example:

exit
exit 1

export

Export an environment variable.

Syntax:

export NAME=VALUE
export NAME

Description: Sets an environment variable and marks it for export to child processes. When called with just a name, exports an existing variable.

Example:

export PATH="/usr/local/bin:$PATH"
export EDITOR=nvim

F#-style export is also supported:

let export MY_VAR = "value"

set

Set a shell variable.

Syntax:

set NAME VALUE

Description: Sets a shell variable. Unlike export, this does not export the variable to child processes.

Example:

set greeting "hello"
echo $greeting

unset

Unset a shell variable.

Syntax:

unset NAME

Description: Removes a variable from the shell environment.

Example:

unset MY_VAR

read

Read input from the user or a file descriptor.

Syntax:

read [options] [variable...]

Description: Reads a line of input and splits it into variables using $IFS.

Flags:

Flag Description
-p PROMPT Display a prompt string before reading
-r Do not interpret backslash escapes
-s Silent mode (do not echo input, useful for passwords)
-n COUNT Read at most COUNT characters
-t SECONDS Timeout after SECONDS (returns failure if exceeded)
-d DELIM Use DELIM as the line delimiter instead of newline

Example:

read -p "Enter your name: " name
echo "Hello, $name!"

read -s -p "Password: " password

read -n 1 -p "Continue? (y/n) " answer

true

Return a successful (zero) exit code.

Syntax:

true

Description: Always returns exit code 0. Useful in conditionals and loops.

Example:

while true do
    echo "loop"
    break
end

false

Return a failure (non-zero) exit code.

Syntax:

false

Description: Always returns exit code 1. Useful in conditionals.

Example:

if false then println "unreachable"

which

Locate a command in $PATH.

Description: which is a dual-mode builtin that searches the system $PATH for a given command. In shell mode (bare argument), it prints the resolved path to stdout and sets the exit code. In F# mode (quoted or parenthesized argument), it returns an Option<string> value suitable for pattern matching, pipelines, and functional composition.

The mode is determined by syntax: bare identifiers like which git use shell mode, while quoted strings like which "git" or parenthesized expressions like which (name) use F# mode.

Shell form

Syntax:

which command

Searches $PATH for command and prints its absolute path to stdout. Returns exit code 0 on success or 1 if the command is not found.

Examples:

which git
# /usr/bin/git

which nonexistent
# (returns exit code 1)

# Use in a conditional
match which "cargo" with
| Some _ -> println "Rust toolchain available"
| None -> ()

F# form

Syntax:

which "command"
which (expr)

Return type: Option<string>

Returns Some path if the program is found in $PATH, or None otherwise. The returned path is the fully resolved absolute path to the executable.

Examples:

# Pattern match on the result
match which "git" with
| Some path -> println path
| None -> println "git not found"

# With default operator
let gitPath = which "git" ?| "/usr/bin/git"

# In a pipeline
"ls" |> which |> fun opt -> match opt with | Some p -> println p | None -> println "not found"

# Bind to a variable
let result = which "cargo"

Tip

Use the shell form (which git) for quick interactive lookups. Use the F# form (which "git") when you need to branch on the result or compose it into a larger expression.


cat

Concatenate and display files.

Syntax:

cat [OPTIONS] [FILE...]

Description: Reads files sequentially and writes their contents to standard output. If no files are given (or when FILE is -), reads from standard input. When output goes to a terminal, syntax highlighting is applied automatically based on the file extension.

Options:

Option Long form Description
-n --number Number all output lines
-b --number-nonblank Number non-blank output lines (overrides -n)
-s --squeeze-blank Suppress repeated empty output lines
-E --show-ends Display $ at end of each line
-T --show-tabs Display TAB characters as ^I
-A --show-all Equivalent to -ET
-r --range START..END Show only lines in the given range
-h --help Display help and exit

Range syntax:

  • 3..7 — show lines 3 through 7
  • ..5 — show lines 1 through 5
  • 10.. — show from line 10 to the end of the file

When -n or -b is combined with --range, line numbers reflect the original file positions (not re-numbered from 1).

Examples:

cat README.md
cat file1.txt file2.txt > combined.txt
echo "hello" | cat
cat -n script.sh
cat --range 10..20 main.cpp
cat -nr 5..15 data.txt

mkdir

Create directories.

Syntax:

mkdir [-pv] [--parents] [--verbose] [--] directory...

Description: Creates the specified directories. By default, fails if the directory already exists or if parent directories are missing.

Options:

Option Description
-p, --parents Create parent directories as needed; no error if the directory already exists
-v, --verbose Print a message for each created directory
-- End of options; treat subsequent arguments as directory names

Examples:

mkdir mydir
mkdir -p path/to/nested/dir
mkdir -pv project/src project/tests
mkdir -- -starts-with-dash

cp

Copy files and directories.

Syntax:

cp [-rfnvR] [--recursive] [--force] [--no-clobber] [--verbose] [--] source... dest

Description: Copies SOURCE to DEST, or multiple SOURCE(s) to an existing DIRECTORY. By default, overwrites existing destination files. Copying a directory requires the -r flag.

Options:

Option Description
-r, -R, --recursive Copy directories recursively
-f, --force Force overwrite; remove destination if needed
-n, --no-clobber Do not overwrite existing files
-v, --verbose Print each file as it is copied
-- End of options; treat subsequent arguments as file names

Examples:

cp file.txt backup.txt
cp -r srcdir dstdir
cp -rv project/ /tmp/project-backup/
cp -n important.txt dest/
cp -- -starts-with-dash.txt dest.txt
cp a.txt b.txt c.txt target-directory/

mv

Move or rename files and directories.

Syntax:

mv [-fnvi] [--force] [--no-clobber] [--verbose] [--interactive] [--] source... dest

Description: Moves SOURCE to DEST, or multiple SOURCE(s) to an existing DIRECTORY. If the destination is on a different filesystem, the file is copied and the source is removed. By default, overwrites existing destination files without prompting.

Options:

Option Description
-f, --force Do not prompt before overwriting
-n, --no-clobber Do not overwrite existing files
-v, --verbose Print each file as it is moved
-i, --interactive Prompt before overwriting
-- End of options; treat subsequent arguments as file names

Examples:

mv file.txt renamed.txt
mv file.txt /tmp/
mv -v old.txt new.txt
mv -n important.txt dest/
mv -- -starts-with-dash.txt dest.txt
mv a.txt b.txt c.txt target-directory/

sleep

Wait for a specified duration.

Syntax:

sleep seconds

Description: Pauses execution for the given number of seconds. Supports decimal values.

Example:

sleep 1
sleep 0.5
echo "done"

fetch

Perform HTTP requests.

Syntax:

fetch URL

Description: Makes an HTTP GET request to the given URL and outputs the response body to stdout.

Example:

fetch https://api.github.com/zen

Note

The fetch builtin currently supports basic GET requests. Additional HTTP methods and options are planned for a future release.


bind

Configure key bindings.

Syntax:

bind                    # List all bindings
bind -l, --list         # List all bindings (same as no args)
bind KEY ACTION         # Bind a key to an action
bind -r, --remove KEY   # Remove a binding
bind --reset            # Reset to default bindings
bind -h, --help         # Show available actions and key format

Description: Manages the shell's key bindings at runtime. Changes take effect immediately. Keys are specified as modifier+key combinations (e.g. ctrl+a, alt+shift+f).

Modifiers: ctrl, alt (or meta), shift, super (or win, cmd)

Keys: az, enter, backspace, delete, tab, escape, up, down, left, right, home, end, pageup, pagedown, insert, space, f1f12

Example:

# List all bindings
bind

# Bind Ctrl+Y to yank (paste from kill ring)
bind ctrl+y yank

# Remove a binding
bind -r ctrl+y

# Reset to defaults
bind --reset

# Show available actions grouped by category
bind --help

Available actions:

Category Actions
Movement move-forward-char, move-backward-char, move-forward-word, move-backward-word, move-to-line-start, move-to-line-end, move-to-buffer-start, move-to-buffer-end, move-up, move-down, smart-move-to-line-start, smart-move-to-line-end
Editing delete-char-backward, delete-char-forward, delete-word, delete-word-backward, kill-to-end, kill-to-start, transpose
Undo/Redo undo, redo
Kill Ring yank, yank-pop
Selection select-all
Clipboard cut, copy, paste
Control submit, abort, insert-newline
History history-prev, history-next

See Configuration: Key Bindings for the full list of default bindings.


env

Get an environment variable (F# style).

Syntax (F# expression):

env "VARIABLE_NAME"

Description: Returns the value of an environment variable as an option<str>. Returns Some value if the variable is set, or None if it is not.

Example:

# Pattern match on the result
match (env "HOME") with
| Some dir -> println $"Home directory: {dir}"
| None     -> println "HOME is not set"

# Use with Option default
let editor = (env "EDITOR") ?| "vi"
println $"Using editor: {editor}"

# Use with the ? operator in a function
let getHome () =
    let home = (env "HOME")?
    Ok home

Tip

For shell-style access to environment variables, use $VAR or ${VAR} substitution syntax instead. The env function is designed for F# expressions where you want type-safe Option handling.


rand

Generate a random integer.

Syntax:

rand
rand <min> <max>

Description: Generates a random integer. With no arguments, returns a random positive integer greater than zero. With two arguments, returns a random integer in the inclusive range [min, max].

Example:

# Random positive integer
let n = rand
print n

# Random integer between 1 and 6 (inclusive)
let roll = rand 1 6
print $"You rolled a {roll}"

# Use in a pipeline
rand 1 100 |> fun n -> print $"Random: {n}"